Astuce [eZ5] Ajouter des filtres et des fonctions à Twig

Twig fournit de nombreuses fonctions et une liste de filtres pour simplifier le développement des templates.

Quelques exemples :

{# Des fonctions natives : #}
Contenu d'une variable : {{ dump(my_var) }}
Nombre aléatoire : {{ random(5) }}

{# Des filtres natifs : #}
Taille d'un tableau : {{ my_array|length }}
Mise en minuscule : {{ my_string|upper }}
Échappement de caractère : {{my_string|escape}}

L'intérêt de Twig c'est qu'il est très facilement extensible, et vous vous pouvez créer vos propres fonctions et vos propres filtres. Par exemple :

{# Une nouvelle fonction : #}
Affiche l'Url actuelle : {{ current_uri() }}

{# Un nouveau filtre : #}
{{ "Ma phrase est trop longue parce que la fin n'est pas intéressante."|truncate(28) }}

Prérequis

  • Vous avez déjà créé le Bundle Acme/MyBundle, et l'avez activé dans le fichier ezpublish/EzPublishKernel.php.

Remarque :

Si ce n'est le nom du fichier de kernel, tout cet exemple est valable pour une application Symfony 2 non eZ.

Création de l'extension Twig

L'ajout de filtres et fonctions se fait via un fichier PHP, qu'on appelle une extension Twig.

Créez le répertoire Twig/ dans votre bundle, et le fichier MyExtension.php à l'intérieur :

<?php
namespace AT\APIToolsBundle\Twig;

use \Symfony\Component\DependencyInjection\ContainerInterface;

class MyExtension extends \Twig_Extension {

    /**
     * @var \Symfony\Component\DependencyInjection\ContainerInterface;
     */
    protected $container;

    /**
     * Contructeur de l'extension Twig MyExtension.
     *
     * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
     */
    public function __construct(ContainerInterface $container) {

        $this->container = $container;
    }

    /**
     * Retourne le nom de l'extension.
     *
     * @return string
     */
    public function getName() {

        return 'MyExtension';
    }

    /**
     * Retourne la liste des Filtres de template à ajouter à Twig.
     *
     * @return array
     */
    public function getFilters() {

        return [
            'truncate' => new \Twig_Filter_Method($this, 'truncate'),
        ];
    }

    /**
     * Retourne la liste des Fonctions de template à ajouter à Twig.
     *
     * @return array
     */
    public function getFunctions() {

        return [
            'current_uri' => new \Twig_Function_Method($this, 'getCurrentURI'),
        ];
    }

    /**
     * Retourne l'URI courante.
     *
     * @return string $_SERVER['REQUEST_URI']
     */
    public function getCurrentURI() {

        return $_SERVER['REQUEST_URI'];
    }

    /**
     * Tronque le texte en argument.
     * Si la longueur du texte est supérieure à $maxLength, $suffix est ajouté à la chaîne.
     *
     * @param string $text Chaîne à tronquer
     * @param int $maxLength Longueur maximale autorisée pour la chaîne
     * @param string $suffix Le sufixe à ajouter si besoin
     * @return string
     */
    public function truncate($text, $maxLength, $suffix = '...') {

        $truncatedText = $text;

        mb_internal_encoding('UTF-8');

        $length      = mb_strlen($text );
        $sufixlength = mb_strlen($suffix);

        // Si le texte est trop long
        if ($length > $maxLength && $length >= $sufixlength) {

            $truncatedText = mb_substr($text, 0, $maxLength - $sufixlength) . $suffix;
        }

        return $truncatedText;
    }
}

Explications :

  • La classe MyExtension étend la classe Twig_Extension fournie par Symfony.
  • La méthode getName() retourne le nom de votre choix pour votre extension.
  • Les méthodes getFilters() et getFunctions() retournent la liste des filtres et des fonctions à ajouter à Twig.
  • Le nom du filtre ou de la méthode est défini par la clé dans le tableau (ici truncate et current_uri).
  • Pour instancier un nouveau filtre, on utilise new \Twig_Filter_Method($this, 'méthode_à_appeler').
  • Et de la même manière, pour une nouvelle fonction new \Twig_Function_Method($this, 'méthode_à_appeler').
  • Les deux dernières méthodes sont celles appelées dans les constructeurs. Elles contiennent le code métier qui effectue le traitement.

Informer Symfony

L'extension Twig est terminée mais Symfony ne sait pas encore qu'elle existe. Il vous faut la déclarer en tant que service, dans le fichier Resources/config/services.yml de votre bundle :

parameters:
    acme_my.twig_extension.class: Acme\MyBundle\Twig\MyExtension

services:
    acme_my.twig_extension:
        class: %acme_my.twig_extension.class%
        arguments: [@service_container]
        tags:
            - { name: twig.extension }

Explications :

  • Chaque paramètre et chaque service du fichier a un identifiant unique (ex : acme_my.twig_extension).
  • On définit la classe MyExtension comme paramètre. Si on déplace ou renomme la classe par la suite, seul le paramètre sera à changer.
  • On déclare l'extension Twig en tant que service, en spécifiant la classe à utiliser et l'argument à passer au constructeur.
  • On tague le service avec twig.extension pour que Symfony sache de quel type de service il s'agit.