Apprendre Symfony 6 : Moteur de Template Twig
Twig est un moteur de template. Son rôle est de dynamiser les templates d'une application en exploitant les mécaniques de la programmation.
Twig : un moteur de template
Qu’est-ce qu’un moteur de templates ?
PHP peut être considéré comme un moteur de template car il permet de dynamiser les templates d’un site web en mélangeant du code PHP et du code HTML. Néanmoins, cela reste très verbeux et parfois peu adapté à nos besoins.
Un moteur de template propose ainsi un langage dédié à la création de nos interfaces, laissant PHP exclusivement en charge de la logique applicative.
Ce langage est, tout comme PHP, interprété côté serveur (exécution des boucles, conditions, fonctions, lecture des variables…) afin de retourner un fichier HTML statique au client.
Twig est un moteur de templates pour le langage PHP. Il a, à l’origine, été développé pour le framework Symfony.
Exemple de PHP traditionnel
<?php if count($articles) > 0) { ?>
<?php foreach ($articles as $article) { ?>
<article class="product">
<h2 class="product-title"><?= htmlspecialchars($product['title']) ?></h2>
<p class="product-description"><?= htmlspecialchars($product['description']) ?></p>
<span class="product-date">Publié le <?= htmlspecialchars(date_format($product['published_at'], 'd/m/Y')) ?></span>
</article>
<?php } ?>
<?php } else { ?>
<p>Aucun produit...</p>
<?php } ?>
Équivalent Twig
{% for article in articles %}
<article class="product">
<h2 class="product-title">{{ product.title }}</h2>
<p class="product-description">{{ product.description }}</p>
<span class="product-date">Publié le {{ product.published_at|date('d/m/Y') }}</span>
</article>
{% else %}
<p>Aucun produit...</p>
{% endfor %}
Un peu mieux n’est-ce pas ?!
Pourquoi utiliser un moteur de template ?
Un moteur de template vient avec son lot d’avantages et un inconvénient évident.
➕ Avantages
- Des templates plus clairs et concis : Twig est moins verbeux que PHP et sa syntaxe est pensée pour être intuitive.
- La sécurité : Twig échappe par défaut les variables à l’affichage (
htmlspecialchars()
automatiques). - Support de nombreuses fonctionnalités utiles : héritage, inclusions…
- Une architecture qualitative : en utilisant un moteur de template comme Twig, il est impossible d’écrire du PHP dans nos templates, cela nous force ainsi à séparer la logique applicative de l’affichage.
➖ Inconvénient
- L’apprentissage d’une nouvelle technologie.
En bref, Twig, c’est facile, beau, puissant et sécurisé !
Syntaxe (délimiteurs)
Ce moteur de template permet de dynamiser des pages web via tout un tas de fonctionnalités. Ces dernières sont exploitables au sein de délimiteurs. On distingue 3 types de délimiteurs :
- Commentaires : comme tout langage, Twig propose une syntaxe pour écrire des commentaires au sein du code avec les délimiteurs
{# Mon commentaire … #}
. Contrairement aux commentaires HTML, ceux-ci n’apparaîtront pas dans la page générée. - Expressions (variables, fonctions et filtres) : l’affichage des variables, du résultat de fonctions ou encore de filtres se fera au sein des délimiteurs
{{ expression }}
. - Tags : les tags regroupent l’ensemble des mécanismes dynamiques de Twig. Il s’agit d’exécuter des structures de contrôle (conditions), structures itératives (boucles), mécaniques d’héritage et d’inclusions de template, etc. On les écrira au sein des délimiteurs
{% tag %}
.
Extension .html.twig
Tous les fichiers Twig porteront l’extension .html.twig
.
Mise en page
Pour comprendre la mise en page avec Twig, il est important de comprendre les notions de layout, pages et partials.
Héritage
En Programmation Orientée Objet (POO), l’héritage consiste à hériter des propriétés et méthodes d’un élément.
Avec Twig, l’héritage consiste à hériter de la mise en page d’un parent.
L’héritage consiste à structurer ses templates de manière à les emboîter entre eux.
Cette mécanique est une implémentation des pseudo-frames en PHP, consistant à router notre application vers le fichier 📄 index.php
en faisant varier un paramètre $_GET['page']
, de sorte à ce que notre layout charge dynamiquement la page adaptée à la requête envoyée par le client.
L’héritage permet ainsi d’éviter la répétition du code de la mise en page globale commune à plusieurs pages. Mettre en place l’héritage consiste à :
- Créer un template parent qui va contenir le design global du site (= le layout, contenant les éléments communs à plusieurs pages).
- Création des templates enfants, qui vont hériter du parent, en y ajoutant un contenu spécifique et unique (= les pages).
Parent
Le parent est le template contenant les balises de premier niveau (html
, head
et body
) et la mise en page globale d’un site web.
Par défaut, lorsque vous initialisez un projet Symfony, vous possédez déjà le fichier qui va jouer le rôle de template parent, il s’agit du fichier 📄 base.html.twig
, situé à la racine du dossier 📁 templates. On l’appelle le « layout » de notre site.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}Welcome!{% endblock %}</title>
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
Notre attention va se porter sur les 2 blocs Twig {% block title %}
et {% block body %}
Ici, le rôle de ces balises est de définir dans le layout des zones identifiées avec la syntaxe {% block nom_du_bloc %} ... {% endblock %}
. Ces zones sont vouées à accueillir du contenu, défini au niveau du template enfant. Ici, le block body
va inclure le contenu propre à chaque page.
Comme vous pouvez le constater, ces zones peuvent :
- Être totalement vierges (la plupart du temps, comme c’est le cas du
block body
) - Déjà contenir des informations (parfois, comme c’est le cas du
block title
). Il y a 2 cas de figure pour lesquels on pourra mettre du contenu à l’intérieur des blocs définis par le parent :- Si le template enfant ne va pas remplir cette zone, nous aurons alors une valeur par défaut.
- Si le template enfant souhaite récupérer la valeur du parent et y ajouter des informations spécifiques (on dit qu’il va le surcharger), alors on utilisera la fonction Twig
parent()
dans le template enfant pour récupérer les informations du parent.
Définir un title
Généralement sur un site web, le titre de notre page a la forme « Titre de la page - Nom du site ».
C’est une bonne habitude à prendre qui est bénéfique en termes de référencement, mais aussi pour l’expérience des utilisateurs des moteurs de recherche, qui vont pouvoir voir à quels sites correspondent les résultats de recherche.
Cela pourrait se faire en ajoutant le nom du site à la fin de chaque {% block title %}{% endblock %}
des pages… mais cela serait maladroit !
{% block title %}Accueil - Nom site{% endblock %}
{% block title %}Formations - Nom site{% endblock %}
Pour éviter cela et respecter le principe du DRY, on isolera plutôt le nom du site dans le layout et les templates enfants ne viendront spécifier que le titre de la page :
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %} - Nom site</title>
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
{% extends 'base.html.twig' %}
{% block title %}Titre de la page{% endblock %}
Enfants
Les enfants sont les templates que vous allez inclure dans votre parent pour venir y injecter du contenu.
Les templates retournés par une méthode de contrôleur avec la fonction render()
sont des templates enfants. Ils vont venir remplir des blocs spécifiques d’une mise en page type définie dans le template parent, pour afficher une page complète.
On les retrouve dans des sous-dossiers situés dans 📁 templates/nom-sous-dossier
. Le nom de ce sous-dossier correspond généralement au contrôleur qui va appeler les templates qu’il contiendra.
La ligne de commande symfony console make:controller
nous avait créé un premier template enfant nommé 📄 index.html.twig
par défaut.
{% extends 'base.html.twig' %}
{% block title %}Hello AppController!{% endblock %}
{% block body %}
<style>
.example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; }.example-wrapper code { background: #F5F5F5; padding: 2px 6px; }
</style>
<div class="example-wrapper">
<h1>Hello {{ controller_name }}! ✅</h1>
This friendly message is coming from:
<ul>
<li>Your controller at <code><a href="{{ 'C:/Symfony/demo/src/Controller/AppController.php'|file_link(0) }}">src/Controller/AppController.php</a></code></li>
<li>Your template at <code><a href="{{ 'C:/Symfony/demo/templates/app/index.html.twig'|file_link(0) }}">templates/app/index.html.twig</a></code></li>
</ul>
</div>
{% endblock %}
Pour qu’un template hérite d’un parent, il va falloir lui indiquer avec le tag {% extends %}
. Vous pouvez voir cette balise tout en haut du fichier. Ici, on rattache un enfant à son parent.
Utilisation de la fonction parent()
La fonction Twig parent()
utilisée au sein d’un template enfant permet de récupérer le contenu du bloc parent portant le même nom.
{% block sidebar %}
<p>Contenu du parent</p>
{% endblock %}
{% block sidebar %}
{{ parent() }} {# Récupère "<p>Contenu du parent</p>" #}
<p>Contenu de l'enfant</p>
{% endblock %}
Héritage multiple
L’héritage multiple : quand bébé devient grand
Dans la vraie vie, un enfant peut devenir parent à son tour… et bien avec Twig, c’est pareil !
L’héritage multiple consiste à mettre en place une relation d’héritage de plus de 2 niveaux. Concrètement, cela consiste à définir qu’un enfant sera aussi parent d’un autre template.
Imaginons que vous souhaitez afficher des publicités sur certaines pages de votre site. Il peut être intéressant de créer un template qui va contenir les publicités et un autre qui ne les contiendra pas.
👴 Le grand-parent
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %} - Nom site</title>
</head>
<body>
{# Ici, mon header #}
{% block body %}{% endblock %}
{# Ici, mon footer #}
</body>
</html>
🧑 L'enfant (template sans pub)
{% extends 'base.html.twig' %}
{% block body %}
{% block content %}{% endblock %}
{% endblock %}
🧑 L'enfant (template avec pub)
{% extends 'base.html.twig' %}
{% block body %}
<aside class="ad">
{# Ici, je place une publicité avant mon contenu #}
</aside>
{% block content %}{% endblock %}
<aside class="ad">
{# Ici, j'en place une après #}
</aside>
{% endblock %}
👶 Le petit-enfant (page sans pub)
{% extends 'app/layout_no_ads.html.twig' %}
{% block title %}Page 1{% endblock %}
{% block content %}
<h1>Page 1</h1>
<p>...</p>
{% endblock %}
👶 Le petit-enfant (page avec pub)
{% extends 'app/layout_ads.html.twig' %}
{% block title %}Page 2{% endblock %}
{% block content %}
<h1>Page 2</h1>
<p>...</p>
{% endblock %}
En résumé
- Un template parent contient des blocs qui vont découper la page en zones.
- Les templates enfants rappellent ces blocs par leur nom afin d’y injecter du contenu.
Inclusion
Sur un site web, on trouve généralement des éléments communs d’une page à l’autre (header, footer, barre latérale…). On les appelle « template parts » ou « partials ».
Pour insérer ces templates au sein de notre layout ou de nos pages, on exploite la mécanique d’inclusion de Twig. Cela consiste concrètement à factoriser une portion de code dans un fichier spécifique et à l’inclure avec la fonction Twig include()
.
Il y a 2 cas de figures pour lesquels il est judicieux d’inclure un template : bien organiser ses templates et éviter de dupliquer son code.
Organiser ses templates
Si vous ne voulez pas qu’une portion de code vienne trop complexifier la structure de votre page, c’est une manière de l’isoler proprement (header, footer, sidebar…).
Au lieu de coder l’en-tête et le pied de page directement dans le layout 📄 base.html.twig
, il serait plus judicieux de les créer dans des fichiers distincts 📄 _header.html.twig
et 📄 _footer.html.twig
, puis de les inclure dans le layout.
<header>...</header>
<footer>...</footer>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %} - Nom site</title>
</head>
<body>
{{ include('_header.html.twig') }}
{% block body %}{% endblock %}
{{ include('_footer.html.twig') }}
</body>
</html>
Éviter la duplication de code
Si un template est appelé plusieurs fois / sur plusieurs pages, il est alors judicieux de le factoriser. #DRY
Ce scénario se produit par exemple :
- Pour une bannière d’inscription à une newsletter que l’on retrouverait sur plusieurs pages d’un site web
- Pour les formulaires d’ajout et d’édition des articles d’un blog (ces formulaires sont structurellement identiques, à la seule différence qu’à l’édition ils seront préremplis).
- …
<form>...</form>
{% extends 'base.html.twig' %}
{% block title %}Page 1{% endblock %}
{% block body %}
<section>...</section>
<section>
{{ include('app/_newsletter.html.twig') }}
</section>
<section>...</section>
{% endblock %}
{% extends 'base.html.twig' %}
{% block title %}Page 2{% endblock %}
{% block body %}
<section>...</section>
<section>
{{ include('app/_newsletter.html.twig') }}
</section>
<section>...</section>
{% endblock %}
Si, en toute logique, la portion de code incluse va bénéficier de l’ensemble des variables de notre page, notez qu’il est également possible de faire passer des variables additionnelles à un fichier que l’on va inclure. Cela se fait avec le mot-clé with
, de la manière suivante :
{{ include '_partial.html.twig' with { 'ma_variable': 'sa_valeur' } }}
Inclure une méthode de contrôleur
Si la fonction include()
est généralement utilisée pour inclure des templates, notez qu’il est aussi possible d’inclure des méthodes de contrôleur toutes entières avec la fonction Twig render()
.
Parfois, nous allons inclure des templates mais ne posséderons pas forcément toutes les variables qu’ils utilisent.
Par exemple, imaginons que sur toutes les pages d’un blog nous souhaitons afficher dans une sidebar les 5 derniers articles publiés.
Cette sidebar sera en toute logique créée dans un « partial » 📄 _last_articles.html.twig
.
{% for article in lastArticles %}
<h2><a href="#">{{ article.title }}</a></h2>
{% endfor %}
Méthode 1 (❌ mauvaise)
- J’inclus le template
📄 _last_articles.html.twig
dans toutes mes pages - Je suis contraint de récupérer les 5 derniers articles publiés dans chacune de mes méthodes de contrôleur afin de les transmettre aux pages.
Méthode 2 (✅ bonne)
J’inclus une méthode de contrôleur lastArticles(5)
chargée de récupérer les 5 derniers articles du blog et de les afficher dans le template 📄 _last_articles.html.twig
.
Notre méthode de contrôleur ressemblera à cela :
public function lastArticles(int $nb): Response {
// Plus tard, on récupérera en base de données, dans la variable $lastArticles, les $nb derniers articles
return $this->render('blog/_last_articles.html.twig', array(
'lastArticles' => $lastArticles
));
}
Pour inclure cette méthode de contrôleur dans un template, il suffit de remplacer la fonction include()
par render(controller())
:
{{ render(controller("App\\Controller\\AppController::lastArticles")) }}
Le paramètre de render(controller())
est une chaîne de caractères de la forme : namespace\\contrôleur::méthode
, en remplaçant bien le simple antislash du namespace de votre contrôleur, par un double antislash.
Héritage VS inclusion
Au début, il peut arriver d’hésiter lorsqu’il s’agit de choisir entre héritage et inclusion. Voici donc quelques tips pour vous aider dans ce choix :
Héritage | Inclusion |
---|---|
Si le template n’est inclus que dans un seul template (parent). | Si le template doit être inclus dans plusieurs templates. |
Si le template inclus dépend de l’autre (parent). | Si le template ne dépend d’aucun autre. |
Si le template inclus doit modifier plusieurs zones de l’autre template (parent). |
Liens entre pages
Les liens Twig vont nous permettre de naviguer sur notre site en appelant les routes créées dans notre système de routage.
Ceci fonctionnera de manière dynamique et nous permettra d’éviter d’écrire nous-mêmes les URL « en dur » dans l’attribut href
.
On appelle une route via la fonction Twig path()
en y précisant son nom (voilà pourquoi il était important de donner un nom à nos routes 😉) et ses paramètres, si elle en a.
<a href="{{ path('app_home') }}">Accueil</a>
<a href="{{ path('article_list', { slug: 'dev-web' }) }}">Développement web</a>
Algorithmie
Dans Twig, il est possible de faire appel aux structures algorithmiques classiques (variables, boucles, conditions…) afin de pousser plus loin la dynamique de nos pages.
Variables
Pour dynamiser nos pages web, on va généralement faire appel à des variables.
Pour afficher une variable, on écrit son nom entre les délimiteurs {{
… }}
.
Notre bon vieux <?php echo $ma_variable; ?>
ou <?= $ma_variable; ?>
sera donc remplacé par {{ ma_variable }}
.
Quand je parle de variable ici, je fais allusion à nos structures de stockage qui vont nous permettre de stocker des informations de manière globale : cela signifie des variables simples, mais aussi des tableaux ou encore des objets.
La syntaxe varie très légèrement en fonction :
Variable | {{ ma_variable }} |
---|---|
Tableau | {{ mon_tableau[0] }} , {{ mon_tableau['cle'] }} ou {{ mon_tableau.cle }} |
Objet | {{ mon_objet.propriete }} |
Mais ces variables ne proviennent pas toujours du même endroit, on peut :
Les faire passer depuis nos contrôleurs
Pour récupérer une variable provenant du contrôleur, on l’appelle par le même nom que celui qu’on lui a donné au moment de la transmettre au template dans notre fonction render()
:
#[Route('/blog/{slug}', name: 'article_show')]
public function showArticle(string $slug): Response {
// Ici, on récupèrera dans la variable $article, toutes les informations de l'article en question
return $this->render('blog/show.html.twig', ['article' => $article]);
}
'article'
: nom de la variable transmise à TWIG$article
: variable PHP contenant l’information
La variable TWIG 'article'
prend pour valeur le contenu de la variable PHP $article
.
Maintenant côté TWIG on peut exploiter notre objet article
de la manière suivante :
{{ article.title }}
Les déclarer dans nos templates
Il est aussi possible de déclarer des variables dans nos templates TWIG. Pour cela on utilise le mot-clé set
.
{% set a = 'Salut' %}
Aller la chercher dans notre application Symfony (variables globales)
Parfois, nous allons avoir besoin d’informations particulières sur la requête HTTP, une session, l’utilisateur authentifié, l’environnement courant…
Tout un tas d’informations utiles que Symfony nous offre dans une variable globale Twig appelée app
.
Variable | Description |
---|---|
{{ app.request }} | Les informations de la requête HTTP |
{{ app.session }} | Le système des sessions |
{{ app.environment }} | L’environnement courant : dev , prod (ou d’autres que vous auriez définis) |
{{ app.debug }} | Un booléen renvoyant si le mode debug est actif ou non |
{{ app.user }} | Si un utilisateur est authentifié, on peut accéder à ses informations comme ceci |
{{ app.flashes }} | Pour afficher des messages flashs stockés en session |
Il est également possible de déclarer nos propres variables globales Twig pour y stocker des informations personnelles, comme un code de tracking de Google Analytics, une clé API, des informations de contact ou encore les crédits du site, etc.
Cela se passe dans la section globals
du fichier 📄 config/packages/twig.yaml
:
twig:
globals:
ga_tracking_code: "UA-874279433-1"
developer: "Fabien Potencier"
contact: "[email protected]"
Ensuite, il ne reste plus qu’à l’appeler côté template .html.twig
.
{{ ga_tracking_code }}
Concaténation
Pour concaténer en Twig, on sépare la variable de la chaîne de caractères avec une ~
(tilde).
{{ var_1 ~ " concaténé avec " ~ var_2 }}
Fonctions
Twig possède de nombreuses fonctions dont certaines ont même été ajoutées pour le framework Symfony.
Nous en avons jusqu’à présent utilisées certaines comme include()
, path()
, parent()
ou encore render()
.
Filtres
Un filtre est une fonction qui permet de manipuler et de formater des données dans des templates Twig.
Ces données peuvent être des chaînes de caractère définies « en dur », des variables TWIG ou d’autres fonctions (avec valeur de retour). Ces filtres se notent après le caractère |
.
Filtres sans paramètre
Les filtres sans paramètres permettent de réaliser des traitements basiques.
{{ ma_variable|upper }}
{{ ma_variable|lower }}
{{ ma_variable|length }}
upper
: mise en majuscule d’une chaîne de caractèrelower
: mise en minuscule d’une chaîne de caractèrelength
: retourne la longueur
Filtres avec paramètre
Certains filtres peuvent êtres utilisés avec des arguments, ce qui les rend plus complets.
{{ article.createdAt|date('d/m/Y') }}
{{ title|replace({'o': '0'}) }}
- Le filtre
|date
permet de formater une date (nécessairement un objet de typeDatetime
). Le format de la date est donc un paramètre que l’on va renseigner lors de l’appel de ce filtre. Ici, la date est formatée au format français :dd/mm/YYYY
. - Le filtre
|replace
permet de remplacer des chaînes de caractères spécifiques par d’autres. Ici, tous leso
contenus dans la variabetitle
seront remplacés par des0
.
Filtres combinés
Il est possible d’appliquer plusieurs filtres en les plaçant les uns à la suite des autres. Ils s’exécuteront dans l’ordre d’écriture.
{{ "Framework Symfony"|replace({'o': '0', 'e': '3', 'a': '@'})|lower }}
La chaîne de caractère « Framework Symfony » deviendra :
- D’abord « Fr
@
m3
w0
rk Symf0
ny » - Puis «
f
r@m3w0rks
ymf0ny »
Point sécurité
Fini le temps où on craignait les failles XSS en PHP et où on était obligé de faire appel à la fonction htmlspecialchars()
à l’affichage de variables pour nous protéger d’éventuels scripts nocifs. Twig applique automatiquement à vos variables un filtre par défaut qui va échapper les caractères spéciaux.
Si une variable contient la valeur « <b>je suis en gras</b>
», par défaut, Twig génèrera le texte « <b>je suis en gras</b>
», qui affichera les caractères sans les interpréter.
Mais il peut arriver que cet échappement nous embête dans certains cas.
Imaginons que nous ayons un éditeur visuel de type WYSIWYG lors de la rédaction du contenu d’articles de blog. On va donc mettre en forme notre article via l’éditeur, et lors de son enregistrement en base de données, des balises HTML contenant la mise en forme de notre article seront stockées.
Si on affiche le champ qui contient le contenu, nos balises HTML seront échappées par Twig, et s’afficheront donc à l’écran comme du texte… ce qui n’est pas ce qu’on espérait !
Pour éviter ce scénario, Twig va mettre à notre disposition le filtre |raw
qui va désactiver localement l’échappement des caractères spéciaux (« raw » se traduit littérallement par « brut »), et interpréter le code qu’elle contient :
{{ article.content|raw }}
Nous n’avons utilisé ici que quelques filtres à des fins pédagogiques. La liste complète des filtres Twig est accessible sur la documentation officielle.
Conditions
Le rôle d’une condition, aussi appelée « structure de contrôle », est d’afficher du contenu, sous certaines conditions.
La structure de contrôle utilise les mots-clés if
, elseif
, else
.
{% if user['role'] == "Admin" %}
<p>Bienvenue admin !</p>
{% else %}
<p>Oups, cet endroit n'est pas pour toi !</p>
{% endif %}
- On déclare donc un bloc conditionnel avec
{% if condition %}
- On ferme un bloc conditionnel avec
{% endif %}
- Entre les deux il est tout à fait possible d’ajouter des
{% elseif %}
et{% else %}
Boucles
Le rôle d’une boucle, aussi appelée « structure itérative », est la répétition automatisée d’une portion de code. La structure itérative utilise le mot-clé « for ».
La boucle for
offre de nombreuses variations la rendant très utile dans de nombreux cas. Vous retrouverez en détails l’ensemble de ces applications sur la documentation officielle.
Dans notre cas nous nous attarderons uniquement sur sa déclinaison foreach
(notée for ... in ...
), afin de parcourir des tableaux d’objets, car c’est sous cette forme que nous exploitons généralement nos données dans une application moderne.
{% for article in articles %}
<h2><a href="{{ path('article_show', { slug: article.slug }) }}">{{ article.title }}</a></h2>
{% endfor %}
- On déclare un bloc itératif avec
{% for ... %}
- On ferme un bloc itératif avec
{% endfor %}
.
Twig a pensé à tout en nous permettant de faire appel à {% else %}
qui va s’exécuter si le tableau articles
est vide. Et inclure un else
dans un for
, c’est plutôt fort (ou for
…).
{# ✅ Bien ! #}
{% for article in articles %}
<h2><a href="{{ path('article_show', { slug: article.slug }) }}">{{ article.title }}</a></h2>
{% else %}
<p>Désolé, il n'y a pas encore d'articles...</p>
{% endfor %}
{# 😔 Maladroit #}
{% if articles|length > 0 %}
{% for article in articles %}
<h2><a href="{{ path('article_show', { slug: article.slug }) }}">{{ article.title }}</a></h2>
{% endfor %}
{% else %}
<p>Désolé, il n'y a pas encore d'articles...</p>
{% endif %}
Et comme Twig n’a pas pour habitude de faire dans la demi-mesure, il met également à notre disposition une variable loop
au sein de la boucle, qui contient les propriétés suivantess :
Propriété | Description |
---|---|
{{ loop.index }} | Numéro de l’itération courante (commence à 1 ) |
{{ loop.index0 }} | Numéro de l’itération courante (commence à 0 ) |
{{ loop.revindex }} | Nombre d’itérations restantes avant la fin de la boucle (finit par 1 ) |
{{ loop.revindex0 }} | Nombre d’itérations restantes avant la fin de la boucle (finit par 0 ) |
{{ loop.first }} | Booléen renvoyant true s’il s’agit de la première itération |
{{ loop.last }} | Booléen renvoyant true s’il s’agit de la dernière itération |
{{ loop.length }} | Nombre total d’itérations de la boucle |
Lier du CSS, JS ou une image
Symfony met à disposition la fonction Twig asset()
qui permet de générer des URL vers des ressources internes, placées dans notre répertoire 📁 public
.
{# Un logo situé dans "public/img/logo.png" #}
<img src="{{ asset('img/logo.png') }}" alt="Logo - Nom marque">
{# Un fichier CSS situé dans "public/css/app.css" #}
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
{# Un fichier JS situé dans "public/js/app.js" #}
<script src="{{ asset('js/app.js') }}"></script>