Séance 2 : Filtres twig

Twig propose de nombreux filtres permettant d'interagir avec vos variables. Ces filtres sont très utiles pour formater vos données, les transformer, les comparer, etc. Une longue liste est disponible par défaut https://twig.symfony.com/doc/3.x/, mais vous pouvez également créer vos propres filtres https://symfony.com/doc/current/templates.html#writing-a-twig-extension.

Création de votre premier filtre

Première version

Nous souhaitons formater les prix de notre application dans le format monétaire en euros. Nous pourrions le faire avec le filtre number_format de twig, mais nous allons créer notre propre filtre, car nous aurons toujours la même configuration. Cela nous permettra également d'ajouter le symfony euro.

Pour créer un filtre nous devons créer une classe qui va étendre Twig\Extension\AbstractExtension. Cette classe peut se mettre n'importe où dans le dossier src, mais nous allons la mettre dans le dossier src/Twig.

<?php

namespace App\Twig;

use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;

class AppExtension extends AbstractExtension
{
    public function getFilters()
    {
        return [
            new TwigFilter('price', [$this, 'formatPrice']),
        ];
    }

    public function formatPrice($number)
    {
        $price = number_format($number, 2);
        $price = $price.' €';

        return $price;
    }
}

Dans cette classe, nous avons créé une méthode getFilters qui va nous permettre de définir les filtres que nous souhaitons créer. Cette méthode doit retourner un tableau d'objets TwigFilter. Pour chaque filtre, nous devons définir un nom (qui est utilisé dans Twig) et une méthode qui va être appelée lorsque le filtre sera utilisé.

Dans notre exemple, nous avons créé un filtre price qui va formater un nombre en ajoutant le symbole euro.

Pour l'utiliser dans Twig, il suffit d'utiliser le nom du filtre :

{{ 10|price }}

Deuxième version

Nous pouvons améliorer notre filtre afin de pouvoir recevoir des paramètres si nous ne souhaitons pas avoir un format en euro, mais par exemple en dollar. Dans ce cas, le symbole est différent, le séparateur de décimales et de milliers également. Cependant notre cas le plus classique restant l'euro, nous allons mettre ces paramètres en option.

<?php

namespace App\Twig;

use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;

class AppExtension extends AbstractExtension
{
    public function getFilters()
    {
        return [
            new TwigFilter('price', [$this, 'formatPrice']),
        ];
    }

        public function formatPrice($number, $symbol = '€', $decimals = 0, $decPoint = '.', $thousandsSep = ',')
    {
        $price = number_format($number, $decimals, $decPoint, $thousandsSep);
        $price = $price. ' €'; //il faudrait améliorer encore ce code car le symbole ne se met pas à la fin si le nombre est en dollar par exemple.

        return $price;
    }
}

Et l'usage dans twig pourrait être

{{ 10|price }}
{{ 10|price('€', 2, ',', ' ') }}
{{ 10|price('$', 2, '.', ',') }}

Un filtre qui retourne du HTML

Nous allons créer un filtre qui va retourner du HTML. Nous allons créer un filtre qui va permettre d'afficher un nombre d'étoiles en fonction d'une note. Par exemple, si la note est 3, nous allons afficher 3 étoiles pleines, 2 étoiles vides.

<?php

namespace App\Twig;

use Twig\Extension\AbstractExtension;

class AppExtension extends AbstractExtension
{
    public function getFilters()
    {
        return [
            new TwigFilter('stars', [$this, 'stars']),
        ];
    }

    public function stars($note)
    {
        // pour le moment nous mettons un simple tiret pour les étoiles vides, nous verrons plus tard comment ajouter des icônes avec une libraire CSS
        $html = '';
        for ($i = 0; $i < $note; $i++) {
            $html .= '<strong>*</strong>';
        }
        for ($i = 0; $i < 5 - $note; $i++) {
            $html .= '-';
        }

        return $html;
    }
}

Et l'usage dans twig pourrait être

{{ 3|stars }}

Mais vous aurez une erreur, et un résultat affiché en HTML (en fait Symfony à empéché l'interpréation du HTML car il ne sait pas s'il peut le faire. Cela pourrait potentiellement être dangeureux). Pour cela, nous devons utiliser le filtre raw de twig pour forcer l'affichage du HTML.

{{ 3|stars|raw }}

Comme ce filtre va toujours renvoyer un contenu HTML que nous allons vouloir afficher, nous pouvons configurer notre filtre pour qu'il retourne directement du HTML "affiché".

<?php

namespace App\Twig;

use Twig\Extension\AbstractExtension;

class AppExtension extends AbstractExtension
{
    public function getFilters()
    {
        return [
            new TwigFilter('stars', [$this, 'stars'], ['is_safe' => ['html']]),
        ];
    }

    public function stars($note)
    {
        $html = '';
        for ($i = 0; $i < $note; $i++) {
            $html .= '*';
        }
        for ($i = 0; $i < 5 - $note; $i++) {
            $html .= '-';
        }

        return $html;
    }
}

Nous ajoutons sur la déclaration du filtre un tableau avec la clé is_safe et la valeur html. Cela va permettre à twig de savoir que le filtre retourne du HTML et qu'il ne doit pas l'encoder (autrement dit l'afficher en texte).

Exercices

Exercice 1

Mettre en place les filtres price et stars dans votre projet pour pouvoir les utiliser dans vos vues. La notion d'étoile n'existe pas dans Jeu, vous devrez donc ajouter une entrée dans la base de données, saisir des valeurs pour les jeux et afficher les étoiles en fonction de la note.

Exercice 2

Créer un filtre qui va permettre d'afficher la date du jour au format français, sur la page d'accueil. L'appel du filtre dans twig pourrait être :

{{ dateObjet|dateFr }}

Ou dateObjet est un objet DateTime envoyé par le contrôleur

Modifier votre filtre pour que la syntaxe suivante puisse fonctionne en utilisant la date du jour

{{ 'now'|dateFr }}

Exercice 3

Créer un filtre qui va formatter un numéro de téléphone de l'éditeur en ajoutant des espaces entre les groupes de chiffres. L'appel du filtre dans twig pourrait être :

{{ '0606060606'|formatPhone }}
{{ '+33606060606'|formatPhone }}

Notez de nouveau que la donnée n'existe pas, il faut donc ajouter ce champs dans l'entité Editeur, saisir des données et les afficher dans la vue.

Dernière mise à jour

Cet article vous a-t-il été utile ?