Cette contrib est avant tout un exemple de création d’une balise qui, je l’espère, pourra quand-même rendre service aux Spipeurs...
Bien-sûr, ce n’est qu’un exemple, il est donc fort probable que des améliorations soient souhaitables, voire nécessaires, pour optimiser son fonctionnement, n’hésitez donc pas à faire part de vos remarques et/ou suggestions dans le forum attaché à l’article...
Avant-Propos
Alors, voici le contexte :
- Imaginons qu’on souhaite mémoriser quelques informations ou données pour être utilisées par la suite...
- Imaginons aussi qu’on souhaite pouvoir disposer des données mémorisées partout dans les squelettes...
- Enfin, imaginons qu’on souhaite disposer d’un système suffisamment souple permettant d’ajouter, modifier et supprimer des données...
Bien-sûr, certains diront qu’un tel mécanisme existe déjà, fourni par défaut dans Spip, sous la forme des balises #SET
et #GET
(voir documentation), mais ces balises sont un peu limités, c’est à dire qu’elles ne fonctionnent pas dans toutes les situations...
En effet, si on mémorise une variable à l’intérieur d’un squelette, les squelettes inclus (les « noisettes » donc) n’auront pas acces aux données des ces variables, ce qui peut s’avérer un peu embêtant dans certaines circonstances...
Il était donc peut-être intéressant de pouvoir disposer d’un système capable de fonctionner dans ce type de situations, c’est donc le rôle de cette balise #TMP
(pour « tampon » ou « temporaire »).
Attention !
Au même titre que les balises
#SET
et#GET
, cette balise#TMP
n’aura aucun effet dans une boucle si la valeur à récupérer a été mémorisée dans la partie optionnelle de la même boucle. Ce comportement est dû au mode de fonctionnement des boucles Spip.En effet, les parties optionnelles des boucles sont analysées et traitées après la partie principale de la boucle, et seulement si cette dernière retourne au moins une valeur, autrement dit, si la boucle principale ne retourne aucune valeur, les perties optionnelles ne seront pas considérées.
Utilisation
Passons à l’utilisation de la bête avant d’ouvrir le capot et d’examiner le moteur.
Voici toutes les utilisations possibles et leur syntaxe :
- Mémoriser une Valeur
Deux méthodes pour mémoriser une valeur, soit en passant par la balise #TMP
, soit en passant par le filtre |tmp
.
La balise #TMP
sert surtout à mémoriser des données libres, c’est à dire toute information non fournie par Spip, alors que le filtre |tmp
est plutôt dédié à la mémorisation des données générées par Spip (les balises), ce que la balise #TMP
ne permet pas. [1]
- Avec la balise
#TMP
:
Si par exemple on souhaite mémoriser la valeur « Coucou les amis... » sous la clé « coucou », voici comment faire :
[(#TMP{coucou,'Coucou les amis...'})]
Dans cette méthode, la première valeur fournie est donc la clé d’identification sous laquelle les données seront mémorisées, puis la deuxième valeur est la donnée elle même (la syntaxe de cette balise est donc exactement la même que celle de la balise #SET
de Spip).
- Avec le filtre
|tmp
:
Le filtre ne permet pas, par défaut, de mémoriser des données libres, ceci est plutôt le rôle de la balise, mais le filtre |tmp
est nécessaire pour mémoriser des données générées par Spip (les balises donc).
Si on souhaite par exemple afficher la date du jour à l’intérieur d’une boucle (ARTICLES)
(c’est juste un exemple hein ;-)), on ne pourrait pas utiliser la balise #DATE
de Spip, puisque cette balise retourne une valeur différente suivant le contexte, dans notre cas c’est la date de publication de l’article qui serait affichée et non pas la date du jour...
Pour y arriver, le filtre |tmp
peut nous être utile, en mémorisant la date du jour, sous la clé « today » par exemple, avant le code de la boucle (ARTICLES)
, avec la syntaxe suivante :
[(#DATE|tmp{today})]
Dans cette méthode, la première valeur fournie au filtre, la balise #DATE
donc, est la donnée à mémoriser, et l’argument fourni au filtre entre les accolades, {today}
, est la clé sous laquelle la date du jour sera conservée.
- Récupérer une Valeur
Pour retrouver une valeur mémorisée, rien de plus simple, la balise #TMP
s’utilise de la même manière que son homologue #GET
de Spip, avec la syntaxe :
[(#TMP{coucou})]
Cet exemple retournera notre « Coucou les amis... ». Autrement dit, il suffit de fournir, comme argument a la balise, la clé sous laquelle l’information a été enregistrée, quelque soit la méthode de mémorisation utilisée, par balise ou par filtre.
Notre second exemple retournera la date du jour au moment de la mémorisation de la valeur :
[(#TMP{today})]
- Valeur par Défaut
Il peut être pratique de disposer d’une valeur par défaut à utiliser si la variable demandée n’est pas ou n’est plus disponible, ceci est possible de la manière suivante :
[(#TMP{coucou,'',defaut})]
La syntaxe à respecter nécessite donc de fournir 3 arguments à la balise, dont le premier correspond a la clé des données qu’on cherche à récupérer, le deuxième argument doit être vide, ce qu’on obtient en mettant deux guillemets, ou deux apostrophes, sans aucun contenu entre les deux, enfin, le troisième argument est la valeur par défaut à afficher si la clé du premier argument n’est pas trouvée.
Attention !
La valeur par défaut est une donnée libre, c’est à dire qu’il ne s’agit pas d’une clé servant à extraire d’autres données en mémoire, mais d’une valeur « brute » à afficher tel-quelle si la clé du premier argument est introuvable.
- Modifier une Valeur
Il est aussi possible de modifier la valeur d’une variable déjà en mémoire, il suffit de mémoriser la nouvelle valeur avec exactement la même clé que la valeur originale, ceci fonctionne avec les deux méthodes : balise et filtre.
Suivant notre premier exemple, si au lieu d’avoir « Coucou les amis... » nous souhaitions afficher « Bonjour monde... » à la place, on ferait :
[(#TMP{coucou,'Bonjour monde..'})]
Dès lors, la clé « coucou » retournera cette nouvelle valeur.
- Supprimer une Valeur
Pour ne pas saturer inutilement l’espace mémoire utilisé (voir chapitre « Mécanique ») avec des données qui ne sont plus nécessaires, il est possible de supprimer les valeurs obsolètes.
La méthode est très simple, il suffit de fournir deux arguments à la balise #TMP
, dont le premier doit être vide et le deuxième correspondre à une clé existante en mémoire.
Par exemple, si on souhaite supprimer notre variable « coucou », il suffit d’utiliser la syntaxe suivante :
[(#TMP{'',coucou})]
Ici on fourni à la balise un premier argument vide, qu’on obtient en mettant deux guillemets, ou deux apostrophes, sans aucun contenu entre les deux, puis on fourni le nom de la clé correspondant aux données à supprimer.
Attention !
Ceci a pour effet de supprimer purement et simplement le couple « clé/valeur » concerné, les données seront donc perdues définitivement.
- Supprimer Toutes les Valeurs
On peut aussi supprimer toutes les données mémorisées en une seule opération, et éviter ainsi de devoir faire autant de suppressions individuelles, épargnant du coup un peu de travail au serveur.
Pour supprimer donc toutes les entrées mémorisées, il suffit d’insérer la balise #TMP
toute seule, sans aucun argument, soit :
[(#TMP)]
Attention !
Ceci a pour effet de supprimer purement et simplement toutes les entrées en mémoire gérées par la balise, les données seront donc perdues définitivement.
Résumons
- Mémoriser une valeur :
[(#TMP{cle,valeur})]
ou
[(#VALEUR|tmp{cle})]
- Récupérer une valeur mémorisée :
[(#TMP{cle})]
- Valeur par défaut (au cas où) :
[(#TMP{cle,'',defaut})]
- Supprimer une valeur :
[(#TMP{'',cle})]
- Supprimer toutes les valeurs :
[(#TMP)]
Mécanique
Le mécanisme mis en oeuvre est relativement simple, voire simpliste aux yeux de certains, mais il a le mérite d’assurer un bon fonctionnement.
Il s’agit donc d’utiliser la variable globale $GLOBALS
pour y stocker des données et informations qui seront ensuite récupérées pour être exploités aux endroits souhaités dans les différents squelettes...
D’accord, de l’avis de certains, c’est « mal » d’utiliser cette variable globale un peu pour tout et parfois pour n’importe quoi, mais avouons qu’elle a le grand avantage d’être disponible et facilement accessible sans avoir à sortir la grosse artillerie des sauvegardes en base de données ou dans des fichiers... ce qui aurait été un peu lourd pour des besoins relativement modestes, tels qu’abordés dans cette contrib.
Donc, en gros, pour ceux qui lisent un peu du Php, il s’agit de créer des nouvelles entrées dans la variable $GLOBALS
, sous la clé générique ['tmp']
, avec la syntaxe suivante :
$GLOBALS['tmp'][$cle] = $valeur;
Pour ensuite être utilisable par :
return $GLOBALS['tmp'][$cle];
Moteur
Voyons donc ce qui se cache sous le capot...
La balise est construite avec trois fonctions Php :
- La première fonction implémente la balise
#TMP
elle même, c’est le code appelé par Spip.
- La deuxième fonction est juste un pont entre le code de la balise
#TMP
et celui du filtre|tmp
.
- Enfin, la troisième fonction correspond au filtre
|tmp
, et c’est elle qui gère les accès aux données.
Voici le code complet, avec quelques commentaires :
<?php
/**************************************************************************************/
/* Balise "#TMP" 1.0 */
/* ---------------------------------------------------------------------------------------------------- */
/* Infos : GPL - 02/08 (c) FredoMkb */
/* Utilisation : #TMP{cle,valeur,defaut} (voir details dans le code) */
/* Role : Memorise des valeurs pour pouvoir les utiliser ensuite */
/* ---------------------------------------------------------------------------------------------------- */
function balise_TMP($p) {
// Fonction de la balise "#TMP", c'est le code appele par Spip.
// Initialisation des variables qui vont recevoir les arguments
$cle = "";
$val = "";
$dft = "";
// Recuperation des paramettres fournis, 3 arguments reconnus
// On test d'abord l'existence de chaque parametre, s'il existe,
// alors on affecte l'argument a la variable correspondante.
if (isset($p->param[0][1])) { $cle .= ($p->param[0][1][0]->texte); }
if (isset($p->param[0][2])) { $val .= ($p->param[0][2][0]->texte); }
if (isset($p->param[0][3])) { $dft .= ($p->param[0][3][0]->texte); }
// Comme on ne peut pas passer des "array", il faut generer du "string" exploitable
$listargs = var_export(array($cle,$val,$dft), true);
// Affectation du nom de la fonction a utiliser dans la balise, avec les arguments
$p->code = "get_tmp($listargs)";
// Le statut 'php' est sur, le statut 'html' passe le retour par le filtre 'interdire_scripts'.
// On peut aussi faire : '$p->interdire_scripts = false;' ou 'true'
$p->statut = 'html';
// Retour du resultat
return $p;
}
function get_tmp($listargs) {
// Fonction pour faire le "pont" entre la balise "#TMP" et le filtre "|tmp".
$cle = $listargs[0];
$val = $listargs[1];
$dft = $listargs[2];
// On change un peu l'ordre des arguments afin que le filtre
// puisse trouver la variable $val en premiere place
return tmp($val, $cle, $dft);
}
function tmp($val='', $cle='', $dft='') {
// Fonction du filtre "|tmp", gere les donnees, pour memoriser ou retourner une valeur.
if (empty($cle) && empty($val) && empty($dft)) {
// Si les trois arguments sont vides, alors on supprime la GLOBALE "tmp"
// Utilisation : [(#TMP)]
unset($GLOBALS['tmp']);
} elseif (empty($cle) && !empty($val)) {
// Si la cle est vide mais pas la valeur, alors un utilise cette derniere comme cle
// pour supprimer l'entree ayant comme cle la valeur fournie
// Utilisation : [(#TMP{'',cle})]
unset($GLOBALS['tmp'][$val]);
} elseif (!empty($cle) && !empty($val)) {
// Si la cle et la valeur sont fournies, alors on memorise ces infos
// Utilisation : [(#TMP{cle,valeur})] ou [(#VALEUR|tmp{cle})]
$GLOBALS['tmp'][$cle] = $val;
} elseif (!empty($cle) && isset($GLOBALS['tmp'][$cle])) {
// Si la cle seule est fournie, alors on tente de retourner les donnees correspondantes
// Utilisation : [(#TMP{cle})]
return $GLOBALS['tmp'][$cle];
} else {
// Si rien de ce qui precede ne fonctionne, alors on retourne la valeur par defaut fournie
// Utilisation : [(#TMP{cle,'',defaut})]
return $dft;
}
}
/**************************************************************************************/
?>
Installation
Pour éviter d’éventuels problèmes d’encodage du texte, vous pouvez récupérer le code complet en téléchargeant l’archive suivante :
Pour installer la balise, deux méthodes :
- Par Copier/Coller
Éditez simultanément le fichier téléchargé « spip_balise_tmp.php » et le fichier
« mes_fonctions.php » qui se trouve dans le dossier « squelettes » de votre site.
Faites un simple copier/coller de l’ensemble du code de la balise, fichier « spip_balise_tmp.php » donc, dans le fichier « mes_fonctions.php », au début ou à la fin du fichier.
Assurez-vous juste de ne pas copier les balises Php <?php
et ?>
qui se trouvent respectivement en début et fin du code.
- Par Inclusion
Cette méthode est plus simple et donc plus recommandée.
Il s’agit de placer le fichier téléchargé « spip_balise_tmp.php » au même niveau que le fichier « mes_fonctions.php », dans le même répertoire donc.
Il faut ensuite éditer le fichier « mes_fonctions.php » pour y placer, au début (juste après la balise d’ouverture Php), le bout de code suivant :
include('spip_balise_tmp.php');
Dans les deux cas, enregistrez les modifications du fichier « mes_fonctions.php » puis videz le cache de Spip (espace privé => Configuration => Vider le cache).
Limitations
La balise #TMP
, en l’état, n’est pas capable de traiter dans ses arguments des valeurs dynamiques, d’autres balises par exemple, il s’agit donc pour l’instant d’une simple balise « statique ».
Le filtre |tmp
tente de pallier, en partie, à cette restriction de la balise, mais son champ d’action reste assez limité tout de même, puisqu’il n’est pas possible, par exemple, d’insérer du code Html de manière simple et directe (voir chapitre « Astuces »).
Enfin, l’utilisation de la variable globale $GLOBALS
, pour mémoriser les variables, n’autorise pas la manipulation de grands volumes de données, ni de données aux contenus complexes, il faut donc se limiter à une utilisation modeste, voire basique, de cette solution.
Astuces
- Mini Config
Une idée d’utilisation de cette balise #TMP
serait, par exemple, de préparer une « noisette » contenant un ensemble de valeurs à mémoriser, pour qu’elles soient disponibles dans toutes les pages du squelette, un peu comme s’il s’agissait d’un mini système de configuration...
Par exemple, on crée un fichier Html nommé « inc-mini-config.html », dans lequel on insère autant de balises #TMP
que des infos à mémoriser, sans aucun autre code Html.
Il suffit d’insérer cette noisette, par un simple #INCLURE
(voir encadré ci-dessous), dans le fichier d’en tête du site « inc-head.html », pour avoir toutes ces données accessibles sur l’ensemble des fichiers du squelette.
Bien-sûr, il ne faut pas trop abuser de cette technique, il vaut mieux se tourner vers d’autres solutions de configuration, comme le plugin CFG par exemple, pour disposer d’un système de configuration plus souple et puissant.
Attention !
Spip possède deux mécanismes différents pour inclure des fichiers externes dans un fichier hôte, soit par la balise
#INCLURE
(depuis Spip 1.9.1) soit par la méthode historique<INCLURE>
(voir documentation).Or, ces deux techniques ne travaillent pas exactement de la même manière, notamment en ce qui concerne la gestion du cache, ce qui restreint l’utilisation de notre balise
#TMP
à travailler uniquement avec les inclusions de type#INCLURE
pour pouvoir bénéficier d’une disponibilité efficace des valeurs mémorisées dans la variable$GLOBALS
.Pour tenter de résumer en deux mots, disons que les fichiers hôte qui travaillent avec des balises de type
#INCLURE
génèrent un seul fichier de cache avec les données locales et celles issues des fichiers externes inclus, alors que la méthode par<INCLURE>
génère autant de fichiers de cache différents que des fichiers traités, autrement dit, ils ne partagent pas forcément le même espace mémoire de travail et n’auront donc pas accès aux données correspondantes.Ces remarques ne font que reprendre des explications for instructives partagées par Matthieu Marcillaud quant au fonctionnement des inclusions et à l’efficacité relative de cette contrib avec elles, merci à lui pour tout ces éclaircissements.
- Balises et Html
Comme expliqué dans le chapitre « Limitations », la balise n’est pas adaptée à traiter des données dynamiques, et le filtre est incapable en l’état de mélanger des balises Spip a du code Html... voici donc une astuce pour contourner cette restriction.
Il s’agit d’utiliser la balise #REM
pour lui forcer à afficher quelque chose (technique expliquée dans l’article « Appliquer un filtre sur autre chose qu’une balise »), puis d’appliquer le filtre sur ce résultat.
Imaginons que nous désirons insérer, un peu partout sur nos squelettes, un lien complet avec l’adresse du site, il peut être sympa de ne pas avoir à mettre toujours le même code Html, voici donc comment mémoriser un tel code afin de l’utiliser autant de fois qu’on le souhaite :
[(#REM|sinon{<a href="#URL_SITE_SPIP" title="[(#DESCRIPTIF_SITE_SPIP|couper{50})]">
<:bienvenue_sur:>#NOM_SITE_SPIP</a>}|tmp{url})]
Petite explication, on force une balise #REM
à afficher quelque chose grâce au filtre |sinon
(voir documentation), puis on applique notre filtre |tmp
en lui fournissant la cle d’identification du contenu à mémoriser.
Comme le montre l’exemple, on peut mettre des balises, des filtres et même des textes localisés entre les accolades du filtre |sinon
, mais il ne faut pas trop compliquer le contenu à mémoriser, il n’est pas garanti que Spip puisse gérer de telles acrobaties de calcul avec des codes trop complexes.
Enfin, pour placer ce code dans les squelettes, rien de plus simple :
[(#TMP{url})]
Un petit avantage de cette méthode est que le code Html est calculé une seule fois, puis le résultat est conservé en mémoire en l’état, ce qui permet de l’utiliser autant de fois que souhaité sans avoir à les recalculer.
Avertissements
Comme signalé à plusieurs reprises dans l’article, ne tentez pas d’utiliser cette technique pour des traitements lourds, elle n’est pas adaptée, préférez vous tourner vers de plugins capables d’une meilleur interaction avec Spip.
Enfin, veillez à nommer de manière la plus simple possible vos clés d’identification pour les données à mémoriser, évitez par exemple d’utiliser des caractères accentués ou spéciaux et, dans la mesure du possible, préférez les tirets bas « _ » aux espaces pour séparer les différents mots de la clé.
Remerciements
Comme d’hab, à toute la communauté de Spipiens pour toutes leurs contributions, les unes plus enrichissantes que les autres, et aussi, surtout, à tout ceux qui se démènent (jour et nuit) pour développer ce magnifique CMS qu’est SPIP.
Un grand merci à Matthieu Marcillaud pour toutes ces explications à propos du fonctionnement des différentes méthodes d’inclusion.
Discussions par date d’activité
Une discussion
Bonjour j’ai utilisé votre balise pour passer une variable avec le plugin agenda et le mini calendrier. Seulement cela ne marche que lorsque je suis identifié en temps que modérateur et que je recalcule la page.
Merci d’avance cordialement,
Mathieu.
Répondre à ce message
Ajouter un commentaire
Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :
Merci d’avance pour les personnes qui vous aideront !
Par ailleurs, n’oubliez pas que les contributeurs et contributrices ont une vie en dehors de SPIP.
Suivre les commentaires : |