Assembler une liste de valeurs dans un modèle Twig paraît simple, mais le détail compte vite: séparateur, dernier élément, liste vide et lisibilité du template. La logique que beaucoup appellent twig implode repose en réalité sur le filtre join, qui transforme une séquence en chaîne exploitable à l’écran. Dans un projet Symfony ou Twig pur, c’est souvent la différence entre un rendu propre et une boucle bricolée au milieu de la vue.
L’essentiel à retenir avant d’assembler vos valeurs
-
joinconcatène les éléments d’un tableau ou d’une séquence en une seule chaîne. - Le séparateur par défaut est vide, donc il faut presque toujours en préciser un.
- Un second séparateur permet de traiter différemment les deux derniers éléments d’une liste.
-
mapetfilterservent souvent à préparer la donnée avant la jointure. - Si la règle devient métier ou réutilisable ailleurs, je préfère la sortir du template.
Ce que fait vraiment le filtre join dans Twig
Le filtre join ne “formate” pas une liste au sens large. Il prend chaque élément dans l’ordre, les convertit en texte et les colle avec un séparateur choisi, exactement comme une concaténation contrôlée. Sans séparateur, Twig renvoie simplement les valeurs les unes à la suite des autres, ce qui est rarement ce que je veux dans une vraie interface.
{{ [1, 2, 3]|join }}Ce rendu peut être utile dans de rares cas, mais en pratique je définis presque toujours un séparateur explicite. Une fois ce principe clair, la vraie question devient la syntaxe et les variantes qui changent réellement le résultat.
La syntaxe qui sert au quotidien
Voici les formes que j’utilise le plus souvent dans les vues Twig.
| Expression Twig | Résultat attendu | Usage typique |
|---|---|---|
{{ tags|join(', ') }} |
php, twig, backend |
Liste standard, lisible immédiatement |
{{ tags|join(' · ') }} |
php · twig · backend |
Affichage visuel plus compact |
{{ tags|join(', ', ' et ') }} |
php, twig et backend |
Liste “humaine”, plus naturelle en français |
Le second séparateur ne remplace pas le premier: il ne sert qu’entre les deux derniers éléments. C’est pratique pour éviter l’effet un peu mécanique des listes qui se terminent toutes par une simple virgule.
{{ (1..5)|join(', ') }}Je garde aussi un réflexe simple: dès qu’une expression est plus complexe qu’un tableau déjà prêt, je l’entoure de parenthèses pour éviter toute ambiguïté de lecture. Dans la pratique, cette petite habitude évite plusieurs erreurs silencieuses.

Des cas concrets qui restent lisibles
Je vois surtout join dans des zones de rendu très concrètes: tags d’article, catégories, labels de filtres, chemins de navigation ou rôles utilisateur. L’intérêt n’est pas seulement de “faire une liste”, mais de garder le template court tant que la donnée est déjà dans la bonne forme.
{% set labels = article.tags|map(tag => tag.name) %}
{{ labels|join(' · ') }}Le point important ici, c’est le passage par map. Si je donne directement une collection d’objets à join, je perds le contrôle sur ce qui sera affiché. En revanche, si j’extrais d’abord le champ utile, le résultat reste net et prévisible.
{% if article.tags is not empty %}
{{ article.tags|map(tag => tag.name)|join(', ') }}
{% else %}
Aucun tag
{% endif %}Ce genre de garde-fou me semble plus propre qu’un rendu vide sorti de nulle part. Dès qu’il faut transformer la collection avant affichage, map et filter deviennent les vrais alliés.
Composer map, filter et join sans alourdir le template
La combinaison la plus saine suit presque toujours le même ordre: je filtre ce que je ne veux pas, je transforme ce que je garde, puis j’assemble le résultat. Cette séquence évite de mélanger nettoyage des données et mise en forme finale.
| Filtre | Rôle | Quand je l’utilise |
|---|---|---|
filter |
Garde uniquement les éléments utiles | Retirer les valeurs inactives, vides ou non pertinentes |
map |
Transforme chaque élément | Extraire un nom, un libellé ou un champ précis |
join |
Assemble le résultat en chaîne | Afficher la liste dans la vue |
split |
Fait l’opération inverse | Reconstituer une liste à partir d’une chaîne |
{{ products
|filter(product => product.visible)
|map(product => product.name)
|join(', ') }}Ce pipeline reste lisible tant qu’il sert la présentation. Je m’en sers volontiers pour une liste d’articles, de filtres ou de noms d’utilisateurs, mais pas pour masquer une logique métier compliquée derrière un rendu trop compact.
Les erreurs qui font perdre du temps
Les soucis les plus fréquents sont rarement spectaculaires, mais ils coûtent du temps au débogage. Je les retrouve surtout dans des vues qui ont grandi vite, sans qu’on ait repris la manière d’assembler les chaînes.
- Joindre des objets bruts : si je n’extrais pas la bonne propriété avant, le résultat est souvent inexploitable ou ambigu.
- Oublier le cas vide : une liste vide donne une chaîne vide, donc il faut prévoir un message clair ou une condition.
-
Confondre affichage et export : pour du CSV ou un autre format d’échange, un simple
joinne gère ni les guillemets ni les séparateurs imbriqués. - Déplacer de la logique métier dans le template : si la règle s’épaissit, je la remonte côté PHP.
-
Ignorer les parenthèses : sur une expression composée, j’écris
{{ (1..5)|join(', ') }}pour garder une lecture sans ambiguïté. -
Forcer du HTML non maîtrisé : je n’utilise
rawque sur du contenu sûr, jamais pour contourner un problème d’échappement.
C’est souvent à ce moment-là qu’on se pose la vraie bonne question: cette jointure doit-elle rester dans la vue, ou remonter dans la couche applicative ?
Quand je sors cette logique du template
Je garde join dans Twig tant qu’il s’agit vraiment de présentation. Dès que la chaîne doit être réutilisée ailleurs, la responsabilité change de place, et je préfère préparer le résultat en amont.
| Situation | Dans Twig | Côté PHP |
|---|---|---|
| Liste courte à afficher | Oui | Pas nécessaire |
| Format réutilisé dans plusieurs vues | Peu pratique | Oui |
| Règle métier ou dépendance à l’état | Non | Oui |
| Texte sensible à la locale | Limité | Souvent oui |
Je fais aussi attention aux cas où la formulation dépend de la langue ou d’une règle de produit. Une simple virgule et un et final suffisent pour beaucoup de listes, mais pas pour toutes les variations de contenu, ni pour tous les contextes de publication. Quand la même chaîne sert dans un export, un e-mail ou une API, je la construis une fois en amont et je laisse Twig se concentrer sur l’affichage.
Le réflexe que je garde pour des vues Twig propres
- Je joins dans Twig quand la valeur relève clairement de la présentation.
- Je transforme d’abord avec
mapoufiltersi la collection n’est pas prête. - Je remonte en PHP dès que la règle devient réutilisable, locale ou métier.
Cette frontière garde les templates courts, les revues de code plus simples et les changements de format moins risqués. C’est la discipline que j’applique le plus souvent quand une vue commence à accumuler des chaînes assemblées à la volée.