Programmation PHP/Symfony/Twig

Un livre de Wikilivres.
Sauter à la navigation Sauter à la recherche


Twig est un moteur de templates pour le langage de programmation PHP, utilisé par défaut par le framework Symfony. Son livre officiel faisant 156 pages[1], la présente pas aura plutôt un rôle d'aide mémoire et d'illustration.

Pour exécuter du code sans installer Twig, il existe https://twigfiddle.com/.

Syntaxe native[modifier | modifier le wikicode]

Les mots réservés suivants s'ajoutent au HTML déjà interprété :

  • {{ ... }} : appel à une variable ou une fonction PHP, ou un template Twig parent ({{ parent() }}).
  • {# ... #} : commentaires.
  • {% ... %} : commande, comme une affectation, une condition, une boucle ou un bloc HTML.
    • {% set foo = 'bar' %} : assignation[2].
    • {% if (i is defined and i == 1) or j is not defined or j is empty %} ... {% endif %} : condition.
    • {% for i in 0..10 %} ... {% endfor %} : compteur dans une boucle.
  • ' : caractère d'échappement.

Pour créer un tableau itératif :

{% set myArray = [1, 2] %}

Un tableau associatif :

{% set myArray = {'key': 'value'} %}

A plusieurs lignes :

{% set months = {
    1: 'janvier',
    2: 'février',
    3: 'mars',
} %}
{{ dump(months[1]) }} {# 'janvier' #}

Multidimensionnel :

{% set myArray = [
    {'key1': 'value1'},
    {'key2': 'value2'}
] %}

Dans un "for ... in", pour séparer chaque élément avec une virgule :

{% if loop.first != true %}
    ,
{% endif %}

Précédence des opérateurs[modifier | modifier le wikicode]

Du moins au plus prioritaire[3] :

Opérateur Rôle
b-and Et booléen
b-xor Ou exclusif
b-or Ou booléen
or Ou
and Et
== Est-il égal
!= Est-il différent
< Inférieur
> Supérieur
>= Supérieur ou égal
<= Inférieur ou égal
in Dans
matches Correspond
starts with Commence par
ends with Se termine par
.. Séquence (ex : 1..5)
+ Plus
- Moins
~ Concaténation
* Multiplication
/ Division
// Division arrondie à l'inférieur
% Modulo
is Test (ex : is defined ou is not empty)
** Puissance
| Filtre
[] Entrée de tableau
. Attribut ou méthode d'un objet (ex : country.name)

Pour afficher la valeur NULL dans un opérateur ternaire, il faut la mettre entre apostrophes :

{{ (myVariable is not empty) ? '"' ~ myVariable.value ~ '"' : 'null' }}

Fonctions usuelles[modifier | modifier le wikicode]

  • url() : affiche l'URL en chemin absolu.
  • path() : affiche l'URL en chemin relatif. Les paramètres POST peuvent être ajoutés dans un tableau ensuite (ex : path(url, {'parametre1': param1}).
  • asset() : pointe vers le dossier des "assets" ("web" dans SF2, "public" dans SF4).
  • include() : inclus un Twig dans un autre.
  • render_esi() : inclus un Twig avec le cache Edge Side Includes[4].
  • controller() : exécute la méthode d'un contrôleur. Ex : {{ render_esi(controller('App\\Controller\\DefaultController:indexAction')) }}.

Filtres[modifier | modifier le wikicode]

Les filtres fournissent des traitements sur une expression, si on les place après elle séparés par des pipes. Par exemple :

  • capitalize : équivaut au PHP ucfirst(), met une majuscule à la première lettre d'une chaine de caractères, et passe les autres en minuscules.
  • upper : équivaut au PHP strtoupper(), met la chaine en lettres capitales. Exemple pour ne mettre la majuscule que sur la première lettre : {{ variable[:1]|upper ~ variable[1:] }}.
  • first : affiche la première ligne d'un tableau, ou la première lettre d'une chaine.
  • length : équivaut au PHP sizeof(), renvoie la taille de la variable (chaine ou tableau).
  • format : équivaut au PHP printf().
  • replace : équivaut au PHP str_replace().
  • join : équivaut au PHP implode() : convertit un tableau en chaine avec un séparateur en paramètre.
  • trim : équivaut au PHP trim().
  • raw : ne pas échapper les balises HTML.
  • default : ce filtre lève les exceptions sur les variables non définies ou vides[5]. Ex :
{{ variable1 |default(null) }}

Variables spéciales[modifier | modifier le wikicode]

  • loop contient les informations de la boucle dans laquelle elle se trouve. Par exemple loop.index donne le nombre d'itérations déjà survenue.
  • Les variables globales commencent par des underscores, par exemple :
    • _route (partie de URL située après le domaine)
    • _self (nom de du fichier courant)
    Donc, pour obtenir la route d'une page : {{ path(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')) }}
    L'URL courante : {{ app.request.uri }}
    La page d'accueil du site Web : url('homepage')
  • Les variables d'environnement CGI, telles que {{ app.request.server.get('SERVER_NAME') }}

Gestion des espaces[modifier | modifier le wikicode]

Un Twig bien formaté ne correspond pas forcément au rendu qu'il doit apporter. Pour supprimer les espaces du formatage dans ce rendu, il existe :

{% spaceless %}
    {% autoescape false %}
    <b>
        Hello World!
    </b>
{% endspaceless %}

De plus, on peut apposer le symboles "-" aux endroits où ignorer les espacements (dont retours chariot) du formatage :

    Hello {% ... -%}
    {%- ... %} World!

Cela fonctionne aussi entre {{- -}}.

Utilisation du traducteur[modifier | modifier le wikicode]

Configuration[modifier | modifier le wikicode]

Le module de traduction Symfony s'installe avec :

composer require translator

Quand une page peut apparaitre dans plusieurs langues, inutile d'injecter la locale dans le Twig depuis le contrôleur PHP, c'est une variable d'environnement que l'on peut récupérer avec :

{{ app.request.getLocale() }}

Le fichier YAML contenant les traductions dans cette langue sera automatiquement utilisé s'il est placé dans le dossier "translations" apparu lors de l'installation. En effet, il est identifié par le code langue ISO de son suffixe (ex : le Twig de la page d'accueil pourra être traduit dans homepage.fr.yml, homepage.en.yml, etc.).

Pour définir le préfixe des YAML auquel un Twig fera appel, on le définit sans suffixe en début de fichier Twig :

{% trans_default_domain 'homepage' %}

Filtre trans[modifier | modifier le wikicode]

Une fois la configuration effectuée, on peut apposer le filtre trans aux textes traduis dans le Twig.

{{ MessageInMyLanguage |trans }}

Parfois, il peut être utile de factoriser les traductions de plusieurs Twig dans un seul YAML. Pour piocher dans un YAML qui n'est pas celui par défaut, il suffit de le nommer en second paramètre du filtre trans :

 {{ 'punctuation_separator'|trans({}, 'common') }}
Attention !

Logo Si le YAML contient des balises HTML à interpréter, il faut apposer le filtre raw après trans.


Si une variable doit apparaitre dans une langue différente de celle de l'utilisateur, on le précisera dans le troisième paramètre du filtre trans :

{{ FrenchMessage |trans({}, 'common', 'fr') }}

Si le YAML doit contenir une variable, on la place entre pourcentages pour la remplacer en Twig avec le premier paramètre du filtre trans :

{{ variableMessage |trans({"%price%": formatPrice(myPrice)}) }}
Attention !

Logo Si la clé à traduire doit être variable, on ne peut pas réaliser la concaténation dans la même commande que la traduction : il faut décomposer en deux lignes :

{% set variableMessage = 'constante.' ~ variable %}
{{ variableMessage |trans }}


Opération trans[modifier | modifier le wikicode]

Il existe aussi une syntaxe alternative au filtre. Par exemple les deux paragraphes ci-dessous sont équivalents :

{{ 'punctuation_separator'|trans({}, 'common') }}

{% trans from 'common' %}
    punctuation_separator
{% endtrans %}


De plus, on peut injecter une variable avec "with". Voici deux équivalents :

{{ 'Bonjour %name% !' |trans({"%name%": name}) }}

{% trans with {'%name%': name}%}Bonjour %name% !{% endtrans %}

Images[modifier | modifier le wikicode]

Stockage d'une image dans variable Twig :

{% set myImage = '<img src="' ~ {{ asset('images/myImage.png') }} ~ '">' %}

Méthodes PHP appelables en Twig[modifier | modifier le wikicode]

En PHP, on peut créer des classes qui étendent Twig_Extension et dont les méthodes seront invocables en Twig, et de la déclarer par surcharge de getFunctions(). Ex :

return [
    new Twig_SimpleFunction('getPrice', [$this, 'getPrice']),
];

Héritages et inclusions[modifier | modifier le wikicode]

extends[modifier | modifier le wikicode]

Si une fichier appelé doit être inclus dans un tout, il doit en hériter avec le mot extends. Le cas typique est celui d'une "base.html.twig" qui contient l'en-tête et le pied de page HTML commun à toutes les pages d'un site. Ex :

    {% extends "base.html.twig" %}

include[modifier | modifier le wikicode]

A contrario, si un fichier doit en inclure un autre (par exemple pour qu'un fragment de vue soit réutilisable dans plusieurs pages), on utilise le mot include. Ex :

    {% include("partials/footer.html.twig") %}

En lui injectant des paramètres :

    {% include("partials/footer.html.twig") with {'clé': 'valeur'} %}

embed[modifier | modifier le wikicode]

Enfin, embed combine les deux précédentes fonctions :

    {% embed "footer.html.twig" %}
        ...
    {% endembed %}

import[modifier | modifier le wikicode]

import récupère certaines fonctions d'un fichier en contenant plusieurs :

    {% from 'mes_macros.html' import format_price as price, format_date %}

Macros[modifier | modifier le wikicode]

Les macros sont des fonctions globales, appelables depuis un fichier Twig[6].

Exemple :

{% macro format_price(price, currency = '€') %}
    {% set locale = (app.request is null) ? 'fr_FR' : app.request.locale %}
    {% if locale == 'fr_FR' %}
        {{ price|number_format(2, ',', ' ') }}&nbsp;{{ currency }}
    {% else %}
        {{ price|number_format(2, '.', ' ') }}{{ currency }}
    {% endif %}
{% endmacro %}
Attention !

Logo Lors de l'appel, les paramètres nommés ne fonctionnent que si 100 % des paramètres appelés le sont.


Exemples[modifier | modifier le wikicode]

{% extends "base.html.twig" %}
{% block navigation %}
    <ul id="navigation">
    {% for item in navigation %}
        <li>
            <a href="{{ item.href }}">
                {% if item.level == 2 %}&nbsp;&nbsp;{% endif %}
                {{ item.caption|upper }}
            </a>
        </li>
    {% endfor %}
    </ul>
{% endblock navigation %}

Pour ne pas qu'un bloc hérité écrase son parent, mais l'incrémente plutôt, utiliser :

{{ parent() }}

Références[modifier | modifier le wikicode]