Plugins Smarty de génération HTML


1Présentation

Quand on crée des templates Smarty, on peut utiliser des structures de contrôle (conditions {if}, boucles {foreach}, etc.), des balises personnalisées ({cycle}, {mailto}, {math}, etc.), et des modificateurs (default, date_format, escape, replace, etc.) fournis par Smarty.

Pour faciliter les développements, vous pouvez créer vos propres balises personnalisées et vos propres modificateurs. Nous allons voir ici un exemple de chaque.


2Créer un modificateur personnalisé

Nous allons créer un modificateur qui sert à traduire une chaîne de caractère dans une autre langue.
(voir la documentation Smarty sur l'écriture de modificateurs)

Par exemple, en écrivant ceci dans un template Smarty :

{* traduction directe d'une chaîne de caractères *}
{"Titre de l'article"|translate:'en'}

{* traduction du contenu de variables *}
{$product1.type|translate:'en'}
{$product2.type|translate:'en'}

Vous pourriez avoir le résultat suivant :

Article title

Computer
Screen

Pour développer ce modificateur, nous utiliserons la source de données qui se connecte à l'API Deepl, que nous avons vue dans le précédent tutoriel. Le code du modificateur présupposera la présence de cette source de données dans le fichier de configuration, sous le nom trad.
Voici le code du modificateur, à enregistrer dans le fichier lib/smarty-plugins/modifier.translate.php :

<?php

/**
 * Modificateur Smarty servant à traduire des textes.
 * @param   string    $text    Chaîne de caractères à traduire.
 * @param   string    $lang    Langue vers laquelle traduire le texte.
 * @return  string    Le texte traduit.
 */
function smarty_modifier_translate(string $text, string $lang) : string {
    // récupération de la source de données
    global $temma;
    $datasource = $temma->getLoader()->dataSources->trad ?? null;
    if (!$datasource)
        return ($text);

    // appel à l'API Deepl pour traduire la chaîne
    try {
        $result = $datasource->translate($text, $lang);
    } catch (\Exception $e) {
        $result = null;
    }
    // retour
    return ($result ?: $text);
}
  • Ligne 9 : Définition de la fonction smarty_modifier_translate().
  • Ligne 11 : Définition de la variable globale $temma, qui contient l'objet principal du framework.
  • Ligne 12 : Utilisation de la variable globale pour récupérer le composant d'injection de dépendances (avec la méthode getLoader()), pour ensuite récupérer le tableau des sources de données, et à partir de là récupérer la source de données connectée à l'API Deepl.
  • Lignes 13 et 14 : Si la source de données n'est pas définie, le texte d'origine (non traduit) est retourné.
  • Lignes 17 à 21 : Appel de la source de données pour traduire le texte.
  • Ligne 23 : Retour du texte traduit. S'il est vide, on retourne le texte d'origine.

3Créer une balise personnalisée

Imaginons que vous souhaitiez créer une balise Smarty qui a pour but de faciliter la création de titres.
(voir la documentation Smarty sur l'écriture de balises personnalisées)

Par exemple, en écrivant ceci dans votre template :

{title text="Premier titre" level="1"}
{title text="Premier sous-titre" level="2"}
<p>Bla bla</p>

{title text="Second sous-titre" level="2"}
<p>Bla bla</p>

{title text="Second titre" level="1"}
{title text="Premier sous-titre" level="2"}
<p>Bla bla</p>

{title text="Second sous-titre" level="2"}
<p>Bla bla</p>

Vous obtiendriez le code HTML suivant :

<h1 id="1-premier-titre">1 Premier titre</h1>
<h2 id="1-1-premier-sous-titre">1.1 Premier sous-titre</h2>
<p>Bla bla</p>

<h2 id="1-2-second-sous-titre">1.2 Second sous-titre</h2>
<p>Bla bla</p>

<h1 id="2-Second-titre">2 Second titre</h1>
<h2 id="2-1-premier-sous-titre">2.1 Premier sous-titre</h2>
<p>Bla bla</p>

<h2 id="2-2-second-sous-titre">2.2 Second sous-titre</h2>
<p>Bla bla</p>

Voici le code d'une telle balise personnalisée, à enregistrer dans le fichier lib/smarty-plugins/function.title.php :

<?php

/**
 * Balise Smarty servant à insérer des titres HTML.
 * @param   array             $params   Tableau associatif contenant les paramètres fournis à la balise.
 * @param   \Smarty\Template  $template Objet représentant le template traité.
 * @return  string    Le code HTML généré.
 */
function smarty_tag_title($params, $template) {
    // initialisation de la variable statique $levelsCount,
    // qui contient la profondeur de chaque niveau de titre
    static $levelsCount = [0];

    // récupération des paramètres
    $text = trim($params['text'] ?? null);
    $level = intval($params['level'] ?? 1) ?: 1;

    // vérification
    if (!$text)
        return ('');

    // gestion de la variable statique
    $levelsCount = array_slice($levelsCount, 0, $level);
    $levelsCount[$level - 1] ??= 0;
    $levelsCount[$level - 1]++;

    // préparation du résultat
    $title = implode('.', $levelsCount) . ' ' . $text;
    $id = \Temma\Utils\Text::urlize($title);

    return sprintf('<h%d id="%s">%s</h%d>', $level, $id, $title, $level);
}
  • Ligne 9 : Déclaration de la fonction smarty_tag_title(). Elle prend deux paramètres, un tableau associatif contenant les paramètres définis dans le template, et un objet représentant le template dans lequel la balise a été utilisée (nous n'utiliserons pas cet objet).
  • Ligne 12 : Définition d'une variable statique qui est initialisée à un tableau contenant un entier égal à zéro. Le fait que ce soit une variable statique fait qu'elle gardera sa valeur entre chaque appel à la fonction. Cette variable contient la profondeur de chaque niveau de titre, c'est-à-dire le nombre de titres connu pour chaque niveau de titre en cours.
  • Lignes 15 et 16 : Récupération des paramètres fournis à la balise dans le template. L'absence de valeur ou les valeurs incorrectes sont gérées.
  • Lignes 19 et 20 : Gestion du cas où le texte est vide.
  • Ligne 23 : Le tableau $levelsCount est réduit si nécessaire, lorsque le niveau de titre passé en paramètre est inférieur au précédent.
  • Lignes 24 et 25 : Dans le tableau $levelsCount, l'entrée correspondant au niveau de titre passé en paramètre est incrémentée (après avoir été initialisée à zéro si nécessaire).
  • Lignes 28 et 29 : Définition du titre qui va être inséré dans le code HTML, et de l'identifiant associé. Pour générer l'identifiant, on applique la fonction urlize() sur le titre.
  • Ligne 31 : On retourne la chaîne HTML formée par la balise <Hn> avec l'identifiant en attribut et le titre en contenu.

4Créer une balise de bloc personnalisée

Les balises de bloc sont des structures de contrôle qui ont un élément ouvrant ({nom_balise}) et un élément fermant ({/nom_balise}), et qui peuvent agir en fonction du contenu placé entre ces deux éléments.
(voir la documentation Smarty sur l'écriture de balises de bloc personnalisées)

Pour illustrer ce fonctionnement, nous allons écrire une balise de bloc équivalente à la balise {title} vue précédemment. Vous pourrez voir les différences, aussi bien dans le code Smarty que dans l'implémentation PHP.

Par exemple, en écrivant ceci dans votre template :

{title level="1"}Premier titre{/title}
{title level="2"}Premier sous-titre{/title}
<p>Bla bla</p>

{title level="2"}Second sous-titre{/title}
<p>Bla bla</p>

{title level="1"}Second titre{/title}
{title level="2"}Premier sous-titre{/title}
<p>Bla bla</p>

{title level="2"}Second sous-titre{/title}
<p>Bla bla</p>

Vous obtiendriez le code HTML suivant :

<h1 id="1-premier-titre">1 Premier titre</h1>
<h2 id="1-1-premier-sous-titre">1.1 Premier sous-titre</h2>
<p>Bla bla</p>

<h2 id="1-2-second-sous-titre">1.2 Second sous-titre</h2>
<p>Bla bla</p>

<h1 id="2-Second-titre">2 Second titre</h1>
<h2 id="2-1-premier-sous-titre">2.1 Premier sous-titre</h2>
<p>Bla bla</p>

<h2 id="2-2-second-sous-titre">2.2 Second sous-titre</h2>
<p>Bla bla</p>

Voici le code d'une telle balise de bloc personnalisée, à enregistrer dans le fichier lib/smarty-plugins/block.title.php :

<?php

/**
 * Balise de bloc Smarty servant à insérer des titres HTML.
 * @param   array             $params   Tableau associatif contenant les paramètres fournis à la balise.
 * @param   string            $content  Contenu placé entre la balise ouvrante et la fermante.
 * @param   \Smarty\Template  $template Objet représentant le template traité.
 * @param   bool              $repeat   False pour la balise fermante.
 * @return  ?string    Le code HTML généré.
 */
function smarty_block_title($params, $content, $template, &$repeat) {
    if ($repeat)
        return (null);

    // initialisation de la variable statique $levelsCount,
    // qui contient la profondeur de chaque niveau de titre
    static $levelsCount = [0];

    // récupération des paramètres
    $content = trim($content ?? '');
    $level = intval($params['level'] ?? 1) ?: 1;

    // vérification
    if (!$content)
        return ('');

    // gestion de la variable statique
    $levelsCount = array_slice($levelsCount, 0, $level);
    $levelsCount[$level - 1] ??= 0;
    $levelsCount[$level - 1]++;

    // préparation du résultat
    $title = implode('.', $levelsCount) . ' ' . $content;
    $id = \Temma\Utils\Text::urlize($title);

    return sprintf('<h%d id="%s">%s</h%d>', $level, $id, $title, $level);
}
  • Ligne 11 : Déclaration de la fonction smarty_block_title(). Elle prend quatre paramètres, un tableau associatif contenant les paramètres définis dans le template, le texte contenu entre les balises ouvrante et fermante, un objet représentant le template dans lequel la balise a été utilisée (nous n'utiliserons pas cet objet), et un booléen indiquant si la fonction est appelée à la lecture du tag ouvrant ou du tag fermant.
  • Lignes 12 et 13 : Si l'appel à la fonction est pour la balise ouvrante, on retourne null, car le texte contenu entre les balises ouvrante et fermante n'est pas encore disponible. Tout le traitement se fera lorsque la fonction est appelée pour la balise fermante.
  • Ligne 17 : Définition d'une variable statique qui est initialisée à un tableau contenant un entier égal à zéro. Le fait que ce soit une variable statique fait qu'elle gardera sa valeur entre chaque appel à la fonction. Cette variable contient la profondeur de chaque niveau de titre, c'est-à-dire le nombre de titres connu pour chaque niveau de titre en cours.
  • Lignes 20 et 21 : Récupération des paramètres fournis à la balise dans le template. L'absence de valeur ou les valeurs incorrectes sont gérées.
  • Lignes 24 et 25 : Gestion du cas où le texte est vide.
  • Ligne 28 : Le tableau $levelsCount est réduit si nécessaire, lorsque le niveau de titre passé en paramètre est inférieur au précédent.
  • Lignes 29 et 30 : Dans le tableau $levelsCount, l'entrée correspondant au niveau de titre passé en paramètre est incrémentée (après avoir été initialisée à zéro si nécessaire).
  • Lignes 33 et 34 : Définition du titre qui va être inséré dans le code HTML, et de l'identifiant associé. Pour générer l'identifiant, on applique la fonction urlize() sur le titre.
  • Ligne 36 : On retourne la chaîne HTML formée par la balise <Hn> avec l'identifiant en attribut et le titre en contenu.