Carnet Wiki

Plugin ’macrosession’ : usage optimisé et extension des données de session

SPIP-Contrib :: Carnet Wiki :: Recherche :

Plugin ’macrosession’ : usage optimisé et extension des données de session

Ce plugin est issu d’une interrogation et vise à répondre au besoin associé :
Quels sont les outils pour la couche de PHP nécessaire pour faire des squelettes très personnalisés selon l’auteur connecté ?

Il s’appuie sur l’expertise de Cédric, collectée et mise en forme dans l’article Du php dans le squelette à la place de #SESSION ou #CACHE0. Le premier jet de code de macro a été posé avec l’aide de marcimat.

Pour bien s’en servir il est souhaitable de bien comprendre le mécanisme de cache de SPIP et les 2 articles suivants :
-  SPIP, PHP et Javascript sont dans un bateau
-  Du php dans le squelette à la place de #SESSION ou #CACHE0

L’état actuel de ce plugin est « test », et non pas « stable ». Ça veut dire qu’il est bien avancé, que vous pouvez le tester, et même vous êtes invité à le tester. Actuellement il n’y a pas de bug connu, mais quelques limitations.

Le source est sur la zone : https://zone.spip.org/trac/spip-zone/browser/_plugins_/macrosession/trunk

Nouvelles balises #_SESSION et compagnie

Attention macros !

Notez le ’_’ au début de #_SESSION !!

Ces balises sont des macros php, c’est à dire qu’elles insèrent un appel à php dans le code compilé, au lieu d’insérer le résultat html comme le font la plupart des balises. Ainsi on peut court-circuiter le mécanisme de cache SPIP lorsqu’il est inadapté.

Le fait que ces balises sont en fait des macros a des conséquences importantes (voir plus loin) et c’est pour bien le rappeler que leur nom commence par un _.

Balise #_SESSION

#_SESSION donne accés aux données de la session, dont la valeur dépend de la session, mais à la différence de #SESSION, la balise #_SESSION ne crée pas un cache SPIP pour chaque visiteur : elle insère un code php dont le résultat n’est pas mis en cache, et qui cherche le résultat à chaque affichage de la page. De plus, la balise #_SESSION permet d’accéder à des données de session étendue, qui ne sont pas présente dans la session SPIP de base. Cette 2e fonctionnalité est présentée plus loin.

Dans un squelette, #_SESSION{nom} insère le nom de l’internaute connecté s’il y en a un.

Du fait que c’est une macro, on ne peut pas appeler un filtre sur cette balise. Pour compenser cela, la balise propose un mécanisme interne pour appeler un filtre : il suffit de le passer en 2e argument.

Par exemple : #_SESSION{nom,strlen} renverra la longueur du nom de l’internaute connecté.

Il est possible de passer 1 ou 2 arguments supplémentaires au filtre.
Par exemple #_SESSION{anciennete,plus,3} renverra l’ancienneté + 3.

Balises de test #_SESSION_SI, #_SESSION_SINON, #_SESSION_FIN

Il est très fréquent de devoir tester une valeur de session du visiteur connecté et produire un affichage différent selon sa valeur.

-  #_SESSION_SI{nom} produit le bloc php qui ouvre un test.

-  #_SESSION_SINON produit le bloc php <?php } else { ?>

-  #_SESSION_FIN produit le bloc php qui ferme un test : <?php }; ?>

Exemple

À la place de

  1. <?php
  2. if (isset($GLOBALS['visiteur_session']['nom'])
  3. AND $GLOBALS['visiteur_session']['nom'] )
  4. { ?>
  5. <h3>Bonjour <?php echo $GLOBALS['visiteur_session']['nom']; ?></h3>
  6. <?php } else { ?>
  7. <h3>Voulez vous vous connecter ?</h3>
  8. <?php }; ?>

Télécharger

on écrira :

  1. #_SESSION_SI{nom}
  2. <h3>Bonjour #_SESSION{nom}</h3>
  3. #_SESSION_SINON
  4. <h3>Voulez vous vous connecter ?</h3>
  5. #_SESSION_FIN

Télécharger

Si vous trouvez ça plus lisible et plus facile à écrire, ce plugin est fait pour vous !

#_SESSION_SI avec comparaisons de valeur

Il est également possible de faire des comparaisons avec ==, != , >, <, >= et <= :

-  #_SESSION_SI{nom,==,Linda} sera vérifié si le nom de l’internaute connecté est « Linda ».

-  #_SESSION_SI{nom,>,K} sera vérifié pour tous les noms qui viennent après la lettre K

#_SESSION_SI avec filtres

Comme avec #_SESSION il est possible d’appliquer un filtre avant de tester la valeur :
#_SESSION_SI{email,mail_est_valide}mail_est_valide est un filtre maison qui teste si un email est valide.

Si les variations syntaxiques permises par ce plugin sont insuffisantes pour les besoins de vos squelettes, il vous sera possible de créer un filtre maison pour tester ce qu’il faut comme il faut.

Emboîtements
On peut emboiter les structures de test à volonté.
Par exemple ici un emboitement de 3 niveaux de test :

  1. <h4>Emboitements</h4>
  2. #_SESSION_SI
  3. #_SESSION_SI{nom}
  4. le nom existe
  5. #_SESSION_SI{nom,==,Linda}
  6. et vaut bien Linda
  7. #_SESSION_SINON
  8. et ne vaut pas Linda. Il vaut #_SESSION{nom}.
  9. #_SESSION_FIN
  10. #_SESSION_SINON
  11. il y a un visiteur mais il n'a pas de nom !
  12. #_SESSION_FIN
  13. #_SESSION_SINON
  14. Vous n'êtes pas connecté...
  15. #_SESSION_FIN

Télécharger

Accès à des données de session étendues

Selon le site ou l’application, il est possible d’accéder avec #_SESSION à des données relatives à l’internaute connecté, même si ces données ne sont pas dans sa session. Les données de cette session étendue peuvent être stockées dans une table spécifique de la BDD, dans une autre BDD ou accédés quelque part sur le net via une API REST, etc, ou simplement calculés à partir des données de session déjà présentes.

Pour cela un pipeline SPIP ’session_get’ a été défini.
Il reçoit un tableau avec 2 entrées :
-  ’champ’ contient le champ recherché,
-  ’visiteur_session’ contient la session en cours d’élaboration, que le pipeline peut, ou non, utiliser pour le calcul ou la recherche de la valeur demandée.

Pour l’utiliser un plugin doit définir une fonction php prefixe_session_get qui reçoit ce tableau et renvoie le tableau reçu en enrichissant l’entrée ’visiteur_session’ avec la valeur calculée pour le champ demandé.

L’accès est ensuite transparent dans les squelettes, puisque #_SESSION accède et renvoie de manière indifférenciées les données de la session SPIP ou celles issues de la session étendue.

Par exemple, un plugin ’majuscule’ pourrait donner accés au nom du visiteur en majuscule. Il définirait la fonction suivante :

  1. function majuscule_session_get($session) {
  2. if ($session['champ'] == 'nom_majuscule')
  3. $session['visiteur_session']['nom_majuscule'] = mb_strtoupper($visiteur_session['nom']);
  4. return $session;
  5. };

Télécharger

Un plugin pourrait par exemple interroger le réseau social fictif http://per.sonn.es et permettre à #_SESSION{listedamis} de renvoyer la liste d’amis de l’internaute connecté.

Note : ce pipeline est utilisé uniquement pour les accés aux données de session requises par les balises #_SESSION et #_SESSION_SI, et pas par la fonction php session_get du noyau spip ou par la balise #SESSION d’origine.

Attention : Les macros ne sont pas des balises comme les autres !

Vu que ces balises sont des macros, il faut être particulièrement vigilant en les utilisant, et certains usages ne sont pas possibles.

Appel de filtre

On ne peut pas appliquer de filtres ni de partie conditionnelle avant après sur une telle balise, car ces derniers s’appliquent au source du code php inclu en tant que chaine, et non au résultat.

Par exemple [(#_SESSION{nom}|strlen)] renvoie toujours 33, quel que soit le nom de la personne connectée, car ça s’applique sur le source php (qui s’écrit en 33 caractères) et non sur le résultat php : il ne faut PAS appeler de filtre sur # _SESSION)

À la place d’un appel de filtre sur le résultat de la balise, il est possible de passer un filtre en 2e argument de la balise, et un ou plusieurs arguments supplémentaires qui seront passés au filtre.
#_SESSION{nom,strlen)

Parties conditionnelles avant après appel de balise

Les parties conditionnelles avant après sur balise s’affichent toujours, même si le résultat php est vide (par exemple car il n’y a pas de visiteur), car le source php n’est jamais vide, lui : [avant si non vide (#_SESSION{nom}) apres si non vide]

Il est tout de même possible d’utiliser cette syntaxe de base de spip dans un cas : pour forcer l’insertion d’un espace après ou avant l’appel de la balise :
[(#_SESSION{nom}) ][(#_SESSION{prenom}) ]
Car sans cela, SPIP accole les 2 résultats des appels de balises en supprimant les espaces, comme il fait partout.

Macros et SPIP sont dans un bateau

En employant des macros, tout se passe comme si du php figurait dans le squelette, et tout ce qui s’applique au php dans l’article « SPIP, PHP et javascript sont dans un bateau » s’applique aussi aux macros.

Et donc, les valeurs #_SESSION et les tests #_SESSION_SI se calculent aprés l’évaluation par SPIP des balises et des boucles.

Effets de bords

Ce point est une des conséquences du point précédent.

La partie de HTML masquée par un #_SESSION_SI n’est pas affichée mais elle est quand même compilée par SPIP, et donc les #SET et #GET et autres morceaux de squelettes SPIP présents dans des zones conditionnelles non affichées à cause d’un #_SESSION_SI sont quand même calculés.

Il y a donc un risque d’effets indésirérables si vous vous servez de balises qui ont des effets de bords : #SET par exemple, car le #SET se fera même si la partie ne s’affiche pas. C’est la règle du « SPIP d’abord ! » expliquée dans l’article SPIP, PHP et Javascript sont dans un bateau.

L’exemple suivant illustre la difficulté.

  1. <h4>Ce qu'il ne faut pas faire</h4>
  2. #SET{var,debut} var vaut debut<br>
  3. Le nom : _SESSION_SI{nom} :
  4. #_SESSION_SI{nom}
  5. Ya un nom. #SET{var,oui_visiteur} var vaut maintenant : #GET{var}<br>
  6. #_SESSION_SINON{nom}
  7. Il n'y a pas de nom. #SET{var,pas_de_visiteur} var vaut maintenant : pas_de_visiteur : #GET{var}<br>
  8. #_SESSION_FINSI
  9. À la fin, var vaut : #GET{var}<br>

Télécharger

Dans le cas où il y a une session avec le nom ’jluc’, il s’affichera :

Le nom : jluc
Ya un nom. var vaut maintenant : oui_visiteur
À la fin, var vaut : non_visiteur

Il ne faut donc pas utiliser de #SET dans les parties conditionnées par ces macros, car le code produit nécessiterait une double lecture (php vs html). Autrement dit, le code devient illisible.

Cache du pipeline session_get

Le mécanisme d’extension doit bien gérer son système de cache afin de ne pas refaire inutilement des calculs à chaque appel de page, et ne pas servir non plus des informations périmées.

Boucles

Les résultats des balises #_SESSION ne sont pas utilisables en critères de boucle.

Squelettes de test et debuging

Le plugin embarque plusieurs squelettes de tests qui permettent de tester les évolutions du plugin et permettent aussi de voir comment l’utiliser :
-  test_visiteur
-  test_visiteur_si
-  test_visiteur_comparaison
-  test_visiteur_filtre
-  test_visiteur_etendu
-  test_visiteur_si_etendu
...

À tester et explorer

-  Modèles : Il semble que les modèles utilisés dans un article sont mis en cache en ce qui concerne l’usage des balises #_SESSION, et ce même lorsqu’il y a #CACHE{0} dans le squelette du modèle. C’est un peu étrange mais les modèles ont des mécaniques de cache spécifiques et d’ailleurs ce n’est que depuis SPIP3 que les modèles peuvent, normalement, avoir un cache à 0. Faudrait explorer plus en détail.

-  Inclusions : Inclure un simple #_SESSION{prenom} dans une <INCLURE>, et dans une #INCLURE

Souhaitable de développer encore

Autres pistes

microcache

Le microcache (produit par le plugin éponyme) est un fichier cache totalement statique, de longue durée et dont le nom est facilement accessible. Du fait que le nom est accessible, on peut en effacer un sélectivement.

-  Annonce sur seenthis
-  Sources sur la zone

Le filtre |microcache s’applique sur un id_auteur, et reçoit le nom de fichier d’un squelette en argument. Le squelette caché par microcache reçoit l’id_auteur dans #ENV{id}. On peut aussi appliquer |microcache sur une chaine qui sert d’identifiant alphanumérique.

microcache stocke sous forme de fichiers et n’est donc souvent pas plus efficace que memoization.
Mais microcache a une interface pratique pour le stockage de data visiteur étendues ou squelettes de visu = un filtre portant sur un id_auteur, que n’a pas memoization en l’état.

Le code de microcache est simple et peut facilement être dupliqué et adapté pour d’autres formes de stockage que sur le disque. On pourrait donc faire un plugin dupliquant l’interface filtre de microcache et stockant avec memoization.

Une autre différence, c’est que microcache enregistre de manière plus « définitive » sur le disque dur, avec l’avantage que ça tient entre les redémarrages et l’inconvénients que ça se remplit sans jamais se vider si on ne fait rien.

Selon fil, ce serait mieux de faire évoluer memoization et d’abandonner
microcache, donc ajouter à memoization une couche « filtre sur id_auteur ou identifiant string ».