Les frameworks front-end, comme React, Angular ou Vue, ont apporté une manière de développer une page Web différente de ce qu’on a pu faire jusqu’à présent : le découpage en composant. Cette approche est très pratique car elle permet de réutiliser des composants d’une page à une autre, et favorise également l’isolation du code. Chaque composant reste donc dans son propre scope, bien qu’un transfert de données soit possible… du parent vers l’enfant et inversement.
Mais alors comment concevoir une page avec le framework Symfony (avec le moteur de template par défaut Twig) ? Dans notre boite à outils, le tag include, très simple d’utilisation, permet déjà un bon découpage de notre page. Le tag embed, quant à lui, fonctionne de manière comparable, mais donne en plus la possibilité de surcharger certaines parties du contenu.
Un peu léger, non ? Bien que ça suffise amplement, dès qu’on se met dans le mindset d’un framework front-end, on se retrouve vite au pied du mur. C’est là qu’entrent en action les Twig Component.
L’initiative Symfony UX est née en 2020. Ce projet facilite l’intégration de packages rendant votre application plus dynamique, plus smooth… et surtout, sans prise de tête avec JavaScript. On limite ainsi l’usage du JS, et dans certains cas, on peut même s’en passer totalement.
Les Twig Components, même s’ils n’embarquent pas de JavaScript (contrairement aux Live Components, mais on en reparlera dans un prochain article 😉), font partie de ces packages proposés par Symfony UX.
Un Twig Component se compose de deux fichiers : une classe PHP et un template Twig. Dans la classe PHP, on pourra inclure de la validation de données, injecter des services ou des managers. Dans le template Twig, sans surprise, on retrouve le contenu que l’on souhaite rendre réutilisable. Voyons maintenant une mise en application simple.
La classe PHP utilise un attribut « AsTwigComponent » qui permet de la déclarer comme composant. Le paramètre template est facultatif, mais utile si l’on souhaite nommer le template différemment. Par défaut, le framework Symfony s’attend à trouver un template portant le même nom que la classe dans le dossiers components. Ce dernier est modifiable dans la configuration twig_component.yaml. Définir explicitement le nom du template permet également d’éviter les confusions si plusieurs fichiers portent le même nom.
On déclare ensuite nos propriétés (ou props), qui seront directement accessible dans le template.
La partie Twig, quant à elle, présente deux particularités :
`twig:block`
(Pour les connaisseurs de Vue, c’est l’équivalent des slots).Et maintenant, l’appel du composant :
Comme vous le voyez, pour appeler notre composant il suffit de démarrer notre tag par `twig:`
, suivi du nom du composant. Notre tag peut également s’auto-fermer si on n’utilise pas de block. Ici comme il en a un, nous ajoutons un bouton à l’intérieur. Et vous remarquez ? C’est également un composant !
Note - Il existe deux syntaxes possibles : HTML et Twig. Je vous conseille d’utiliser la première, plus lisible, et surtout compatible avec l’auto-complétions de l’IDE.
Alors, je vous le concède, la classe PHP, ici, hormis déclarer des props, ne sert strictement à rien 😅. Modifions donc notre composant pour créer un composant anonyme.
Puisque que notre template est dans le dossier `/templates/components`
, et qu’il se nomme `Card.html.twig`
, il n’est pas nécessaire de modifier le(s) appel(s) de notre composant.
Notre précédent composant ne nécessitait pas de classe PHP puisqu’on ne faisait que déclarer des props. Il était donc plus judicieux d’en faire un composant anonyme. Voyons maintenant comment la classe PHP peut réellement nous servir.
Dans cet exemple, notre composant devra faire deux choses :
Avant que le composant soit instancié, on peut vérifier les données passées grâce à l’attribut `#[PreMount]`
. Dans notre cas, deux props sont attendues : animalType et animals. On peut donc effectuer des vérifications sur l’une, l’autre… ou les deux.
Concrètement, on va :
cat
) pour animalType
;cat
et dog
;Ce comportement est assez proche de ce qu’on fait dans la méthode configureOptions()
d’un formulaire Symfony.
Formidable, maintenant que nos données sont validées, on peut passer à la récupération des données.
Pour récupérer nos données, je vous propose de le faire de la façon la plus simple possible. On va injecter un service dans notre composant, puis utiliser l’attribut PostMount.
Cet attribut est un autre hook disponible qui va nous permettre de réaliser des actions supplémentaires une fois le composant instancié.
Comme nos données d’entrées ont été vérifiées en amont via PreMount, on peut hydrater la props animals.
Voici la version complète de notre composant Animals :
Et son template associé :
Je récapitule…
La classe Animals
vérifie le type passé en entrée, puis récupère les données associées.
Le template Twig Animals boucle sur ces données et affiche une série de composants Card.
Chaque Card appelle à son tour un composant Button.
En résumé : trois composants réutilisables, chacun autonome. Et lorsqu’on assemble tout ça, voici le rendu obtenu en image. Pas mal, non ? Et surtout : c’est français. 😊
Pour pousser encore un peu plus loin la logique de réusabilité, les Twig Components permettent aussi d’exploiter le concept de Class Variance Authority (CVA). Issu du monde du front-end, ce principe permet de définir plusieurs variantes d’un même composant à partir de quelques règles simples.
Dans notre exemple, nous avons un bouton capable d’adopter différentes tailles et couleurs. Et comme nous avons également une props has_link, notre bouton pourra être un lien (<a>) ayant l’apparence d’un bouton.
Comme pour le composant Card, Button ne nécessite pas de classe PHP. On y déclare nos props en premier lieu puis nous créons un objet CVA (L8) avant d’être servi dans notre tag :
Pour créer cet objet CVA, on utilise la fonction Twig html_cva(). Elle prendra en premier paramètre la classe de base qui sera tout le temps présente. Le second paramètre sera un objet pour définir les différentes variantes possibles. Ici, la couleur et la taille.
Ensuite, on va ensuite appliquer les classes CSS en appelant la méthode `apply()`
sur notre objet. La méthode nécessite un premier paramètre qui sera un tableau. Dans ce dernier on passe les deux variantes. Le second paramètre correspond aux classes additionnelles que l’on passerait à notre composant (optionnel).
À l'usage, notre composant pourrait aussi servir comme bouton de déconnexion à l’aide des props que l’on a défini dans objet CVA :
Et voici le rendu de notre exemple :
Pourquoi utiliser CVA dans un Twig Component ? L’intérêt est triple. Déjà on évite de surcharger l’attribut HTML class. De faciliter la maintenance de ce composant, que ce soit en termes de style ou de fonctionnalité. Et surtout, l’IDE permet d’afficher automatiquement les valeurs valides pour chaque prop de votre composant.
On ne parle pas assez de l’expérience développeur, mais elle a aussi son importance.
Pour conclure - À travers ces exemples, on a vu que les Twig Components permettent de créer des composants plus ou moins simples, imbricable, dont les propriétés peuvent faire varier l’apparence.
Qu’ils aient besoin de données ou non, où que vous souhaitiez les afficher, il suffit de les appeler dans un template Twig – aucun effort supplémentaire.
Dans un prochain article, j’irai un peu plus loin avec les Live Components. Ce ne sont ni plus ni moins que des Twig Components couplés à Stimulus. Ce combo rend nos composants dynamiques rendant l’expérience utilisateur plus fluide avec un effet wahoo. Est-ce que nous avons réellement encore besoin de développer des Single Page Application (SPA) ? Symfony UX commence à nous prouver que non.
Crédit photo : Deagreez
Sources :