Les vues avec Twig
Dans Symfony, les vues sont gérées par le moteur de templates Twig.
Dans les leçons précédentes, nous avons déjà utiliser un Twig. Nous allons maintenant approfondir son utilisation.
Twig offre une syntaxe simple et sécurisée pour afficher des variables, exécuter des boucles, et structurer vos pages de manière claire.
Structure d’un projet avec Twig
Comme vous le savez, les fichiers Twig sont situées dans le dossier templates/.
|-- .../
|-- src/
|-- templates/
|-- hello/
|-- index.html.twig
|-- tests/
|-- .../
Syntaxe de base de Twig
Délimiteurs principaux
Twig utilise une syntaxe simple et lisible.
Les trois délimiteurs principaux sont :
-
{{ variable }}pour afficher une variable -
{% ... %}pour une instruction (boucle ou condition) -
{# ... #}pour les commentaires qui seront ignorés par Twig
Afficher des variables → {{ variable }}
Comme nous l’avons vu dans la leçon sur le l’architecture MVC, un lien fort s’établit entre le contrôleur et la vue (Twig). Il est donc nécessaire d’utiliser ces deux éléments conjointement pour un bon fonctionnement.
Donc, les variables affichées dans Twig proviennent du contrôleur : elles doivent y être définies et transmises au template pour être accessibles.
Nous allons travailler sur une méthode existante du contrôleur, celle qui est associée à la route /hello et nous allons la modifier.
#[Route('/hello', name: 'app_hello')]
public function index(): Response
{
$nom = 'Dupont';
$age = 30;
$ville = 'Paris';
return $this->render('hello/index.html.twig', [
'nom' => $nom,
'age' => $age,
'ville' => $ville,
]);
}
Dans cette méthode, on n'a définit 3 variables. Ces variables, on les a envoyé dans le vue de Twig grâce à au tableau suivant :
[
'nom' => $nom,
'age' => $age,
'ville' => $ville,
]
Ainsi dans le fichier Twig, on pourra les récupérer et les insérer à l'endroit choisit. D'ailleurs, c'est ce que nous allons faire en modifiant complètement le fichier Twig associé : templates/hello/index.html.twig
<h1>Hello</h1>
<p>Nom: {{ nom }}</p>
<p>Âge: {{ age }}</p>
<p>Ville: {{ ville }}</p>
Dans le navigateur, si on tape http://localhost:8000/hello, vous allez voir que Twig a remplacé les variables par le contenu transmis par le contrôleur.
C'est génial ! 😃
Instruction → {% ... %}
Les conditions
Comme dans tout langage de programmation, il est possible de créer des conditions avec Twig. Les conditions sont utilisées pour exécuter certaines parties du code uniquement si une ou plusieurs expressions sont vraies.
On va prendre un exemple et pour cela nous allons utiliser le contrôleur et modifier le fichier Twig que nous avons utilisé pour l'affichage de variable.
#[Route('/hello', name: 'app_hello')]
public function index(): Response
{
$nom = 'Dupont';
$age = 30;
$ville = 'Paris';
return $this->render('hello/index.html.twig', [
'nom' => $nom,
'age' => $age,
'ville' => $ville,
]);
}
<h1>Hello</h1>
<p>Nom: {{ nom }}</p>
<p>Âge: {{ age }}</p>
<p>Ville: {{ ville }}</p>
{% if age >= 18 %}
<p>Vous êtes majeur.</p>
{% else %}
<p>Vous êtes mineur.</p>
{% endif %}
On observe clairement la structure des conditions entre les lignes 6 et 10, avec la présence des mots-clés if, else et endif.
Cette condition analyse la variable age, transmise à la vue par le contrôleur. Si la valeur de cette variable est supérieure ou égale à 18, le message Vous êtes majeur. est affiché ; sinon, le message Vous êtes mineur. apparaît.
Dans notre cas, puisque que la variable age est de 30, le navigateur va afficher cette page :
Les boucles
Les boucles dans Twig permettent d’afficher une série d’éléments transmis à la vue par le contrôleur sous forme de tableau.
Par exemple, nous allons définir un tableau dans le contrôleur et le transmettre à la vue. Twig utilisera ensuite une boucle pour afficher l’ensemble des éléments de ce tableau.
#[Route('/hello', name: 'app_hello')]
public function index(): Response
{
$nom = 'Dupont';
$age = 30;
$ville = 'Paris';
$hobbies = ['Lecture', 'Voyage', 'Cinéma'];
return $this->render('hello/index.html.twig', [
'nom' => $nom,
'age' => $age,
'ville' => $ville,
'hobbies' => $hobbies,
]);
}
<h1>Hello</h1>
<p>Nom: {{ nom }}</p>
<p>Âge: {{ age }}</p>
<p>Ville: {{ ville }}</p>
{% if age >= 18 %}
<p>Vous êtes majeur.</p>
{% else %}
<p>Vous êtes mineur.</p>
{% endif %}
<h2>Hobbies</h2>
<ul>
{% for hobby in hobbies %}
<li>{{ hobby }}</li>
{% endfor %}
</ul>
Quel est le résultat lorsque nous réactualisons le navigateur ?
Grâce à notre code, nous avons pu afficher la liste des hobbies de notre page sous forme de liste.
Analysons la boucle de Twig :
{% for hobby in hobbies %}
<li>{{ hobby }}</li>
{% endfor %}
Dans cet exemple, hobbies correspond au tableau envoyé par le contrôleur à la vue. À chaque itération de la boucle, la variable hobby contient un élément du tableau : elle commence par le premier, puis passe au suivant, jusqu’à ce que tous les éléments aient été parcourus.
Twig offre aussi des variables de boucle comme loop.index, loop.first, loop.last, loop.length, ...
Filtres Twig
Les filtres dans Twig permettent de transformer l’affichage d’une variable.
Voici la syntaxe générale :
{{ variable|filtre }}
Par exemple, si la variable contient chat :
{{ variable|upper }}
Le résultat sera :
CHAT
Voici la liste des filtres qu'il est possible d'utiliser :
-
Texte ↴
-
upper→ met le texte en majuscules ('symfony' → 'SYMFONY') -
lower→ met le texte en minuscules ('HELLO' → 'hello') -
capitalize→ met la première lettre en majuscule, le reste en minuscules ('bonjour' → 'Bonjour') -
title→ met une majuscule à chaque mot ('bonjour le monde' → 'Bonjour Le Monde') -
trim→ supprime les espaces avant et après la chaîne (' Salut ' → 'Salut') -
reverse→ inverse le texte ('abc' → 'cba') -
replace→ remplace une sous-chaîne par une autre ('Salut %nom%'|replace({'%nom%': 'Alice'}) → 'Salut Alice') -
slice→ extrait une portion du texte ('Symfony'|slice(0, 3) → 'Sym') -
length→ retourne la longueur du texte ('Bonjour' → 7) -
default→ affiche une valeur par défaut si la variable est vide ou inexistante ({{ nom|default('Anonyme') }}) -
join→ joint les éléments d’un tableau en une seule chaîne (['PHP','Twig']|join(', ') → 'PHP, Twig') -
split→ divise une chaîne en tableau selon un séparateur ('a,b,c'|split(',') → ['a','b','c']) -
nl2br→ convertit les sauts de ligne en balises
("Bonjour\nSymfony" → "Bonjour<br>Symfony")
-
-
Nombre ↴
-
number_format→ formate un nombre avec décimales et séparateurs (1234.56 → 1 234,56) -
round→ arrondit un nombre (3.14159|round(2) → 3.14) -
abs→ renvoie la valeur absolue (-5 → 5) -
format_currency→ affiche un nombre en devise locale (1000|format_currency('EUR') → 1 000,00 €)
-
-
Dates ↴
-
date→ formate une date ({{ date|date('d/m/Y') }} → 26/10/2025) -
date_modify→ modifie une date ({{ date|date_modify('+1 day') }}) -
time_diff→ affiche le temps écoulé ({{ date|time_diff }} → il y a 3 jours)
-
-
Tableaux ↴
-
first→ retourne le premier élément ([1,2,3]|first → 1) -
last→ retourne le dernier élément ([1,2,3]|last → 3) -
reverse→ inverse l’ordre des éléments ([1,2,3]|reverse → [3,2,1]) -
sort→ trie les éléments ([3,1,2]|sort → [1,2,3]) -
merge→ fusionne deux tableaux ([1,2]|merge([3,4]) → [1,2,3,4]) -
filter→ filtre les éléments selon une condition ([1,2,3,4]|filter(v => v > 2) → [3,4]) -
map→ transforme chaque élément ([1,2,3]|map(v => v * 2) → [2,4,6]) -
keys→ retourne la liste des clés d’un tableau ({'a':1,'b':2}|keys → ['a','b']) -
length→ retourne le nombre d’éléments ([1,2,3]|length → 3)
-
-
HTML et sécurité ↴
-
escape→ échappe le HTML (<b>Texte</b> → <b>Texte</b>) -
raw→ affiche le HTML brut (⚠️ à utiliser avec précaution) -
striptags→ supprime toutes les balises HTML (<b>Texte</b> → Texte) -
nl2br→ transforme les retours à la ligne en
-
-
Internationalisation / Traduction ↴
-
trans→ traduit un texte selon les fichiers de traduction ({{ 'message.bienvenue'|trans }}) -
format_datetime→ formate la date selon la locale ({{ date|format_datetime(locale='fr') }}) -
localizeddate→ affiche la date localisée ({{ date|localizeddate('long', 'none', 'fr') }})
-
-
Symfony spécifiques ↴
-
asset→ génère le chemin public vers un fichier ({{ asset('images/logo.png') }}) -
path→ crée une URL relative vers une route ({{ path('app_home') }}) -
url→ crée une URL absolue ({{ url('app_home') }})
-
Débogage avec Twig
Dans certains cas, nous aurons besoin de savoir qu'elle est le contenu d'une variable, lorsqu'elle est envoyée dans la vue de Twig. Pour atteindre cet objectif, on peut utiliser une fonctionnalité de Twig grâce au mot clé {{dump('')}}.
Il permet d’afficher de manière élégante le contenu d’une variable (par exemple un tableau). Cependant, cet outil est destiné uniquement au développement, afin d’aider le développeur à déboguer. Il n’est pas prévu pour les utilisateurs finaux et ne devrait donc pas être présent lorsque l’application est déployée sur le serveur.
On va l'utiliser grâce à un exemple :
<h1>Hello</h1>
<p>Nom: {{ nom }}</p>
<p>Âge: {{ age }}</p>
<p>Ville: {{ ville }}</p>
{% if age >= 18 %}
<p>Vous êtes majeur.</p>
{% else %}
<p>Vous êtes mineur.</p>
{% endif %}
<h2>Hobbies</h2>
<ul>
{% for hobby in hobbies %}
<li>{{ hobby|upper }}</li>
<li>{{ loop.index }}</li>
<li>{{ loop.length }}</li>
<li>{{ loop.first ? 'Premier hobby' : '' }}</li>
<li>{{ loop.last ? 'Dernier hobby' : '' }}</li>
{% endfor %}
</ul>
{{ dump(nom) }}
{{ dump(age) }}
{{ dump(ville) }}
{{ dump(hobbies) }}
Et voici le résultat :
C'est une fonctionnalité très pratique ! 😊
Commentaire → {# ... #}
Twig permet d’insérer des commentaires destinés aux développeurs, qui ne seront pas interprétés par le code.
{# Ceci est un commentaire qui ne sera pas interprété par le code ! #}
Héritage de templates
L’un des points forts de Twig est la possibilité de réutiliser une structure commune (en-tête, pied de page, ...) grâce à l’héritage de templates.
Pour mieux comprendre, prenons un exemple.
Nous allons utiliser un nouveau fichier qui est appelé templates/base.html.twig, dans lequel nous placerons la structure de base commune à toutes les pages.
Voici l'arborescence de notre dossier templates :
templates/
|-- hello/
|-- index.html.twig
|-- base.html.twig
Dans le fichier templates/base.html.twig, nous allons effacer le contenu par défaut et placer le code suivant pour une structure simple :
{# templates/base.html.twig #}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
Maintenant, nous allons supprimer le contenu de templates/hello/index.html.twig pour le remplacer avec autres choses.
{% extends 'base.html.twig' %}
{% block title %}Page d'accueil{% endblock %}
{% block body %}
<h1>Bienvenue sur la page d’accueil</h2>
<p>Ce contenu remplace celui du bloc "body" du template parent.</p>
{% endblock %}
Pour bien comprendre la mécanique, nous allons expliquer chaque partie.
{% extends 'base.html.twig' %}
Cette partie permet d'indiquer le chemin du fichier qui servira de base.
{% block title %} ... {% endblock %} et {% block body %} ... {% endblock %}
Ces parties doivent être fermées par {% endblock %}. Le contenu sera inséré dans les mêmes parties qui porte le même nom dans le fichier templates/base.html.twig. Si vous observez bien les deux fichiers, vous allez repérer {% block title %} ... {% endblock %} et {% block body %} ... {% endblock %}
Quel est le résultat envoyé au navigateur ?
Voici ce qui est affiché :
Et voici le code source généré :
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Page d'accueil</title>
</head>
<body>
<h1>Bienvenue sur la page d’accueil</h1>
<p>Ce contenu remplace celui du bloc "body" du template parent.</p>
</body>
</html>
Libre à vous d'utiliser autant de parties que nécessaire pour votre projet personnel.
Inclusion de fichiers Twig
En plus de l’héritage, Twig permet d’inclure des sous-templates (fragments de page réutilisables).
L’objectif est d’intégrer un extrait de code d'un fichier réutilisable dans une ou plusieurs pages.
Voici comment procéder !
Sans variable
Dans un premier temps, nous allons créer un dossier partial dans le dossier templates. C'est dans ce dossier que l'on pourra placer les fichiers qui contiendront des fragments de code et que l'on pourra insérer dans les pages souhaitées grâce à l'inclusion de fichiers Twig.
Puis dans ce dossier on va créer un fichier que l'on va appeler templates/partials/_header.html.twig !
Le préfixe «_» devant le fichier n'est pas obligatoire. Mais, c'est une bonne pratique pour indiquer que le fichier Twig est un fragment de template et qu'il n'est donc pas destiné à être affiché directement.
templates/
|-- hello/
|-- index.html.twig
|-- hello/
|-- _header.html.twig
|-- base.html.twig
Dans le le fichier templates/partials/_header.html.twig nous allons taper le code ci-dessous.
<header>
<nav>
<a href="/">Accueil</a>
<a href="{{ path('app_hello') }}">Hello</a>
</nav>
</header>
Nous créons un header avec deux liens : un pour naviguer vers la page app_hello et un autre vers la page d’accueil (qui est la page par défaut de Symfony, car nous ne l’avons pas encore modifiée).
On peut insérer ce bout de code où bon nous semble. Par exemple, on peut l’ajouter à notre fichier templates/base.html.twig comme ceci :
{# templates/base.html.twig #}
{% extends 'base.html.twig' %}
{% block title %}Page d'accueil{% endblock %}
{% block body %}
{% include 'partials/_header.html.twig' %}
<h1>Bienvenue sur la page d’accueil</h1>
<p>Ce contenu remplace celui du bloc "body" du template parent.</p>
{% endblock %}
Comme vous pouvez le constater dans la ligne 7, la syntaxe à écrire pour atteindre le résultat voulu est la suivante : {% include ' ... ' %} ! Remplacez les trois points par le chemin du fichier contenant le code partiel.
Voici le résultat :
Et voici le code source :
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Page d'accueil</title>
</head>
<body>
<header>
<nav>
<a href="/">Accueil</a>
<a href="/hello">Hello</a>
</nav>
</header> <h1>Bienvenue sur la page d’accueil</h1>
<p>Ce contenu remplace celui du bloc "body" du template parent.</p>
</body>
</html>
Avec des variables
Dans nos partials, il est également possible d'utiliser des variables.
Voici un exemple pour comprendre comment les choses fonctionnent avec des variables transférées.
{% include 'partials/_message.html.twig' with {'type': 'success', 'texte': 'Opération réussie !'} %}
Et dans partials/_message.html.twig :
<div class="alert alert-{{ type }}">
{{ texte }}
</div>
Vous disposez désormais de toutes les clés pour bien utiliser la Vue dans l’architecture MVC, grâce au moteur de templates Twig. 😍
Prochaine leçon !
Si vous n’êtes pas familier avec le concept d’injection automatique, je vous recommande de consulter la prochaine leçon sur l’autowiring de Symfony.
Sinon, vous pouvez passer directement à la leçon suivante, où nous aborderons la manipulation des paramètres d’URL et des requêtes.
