Archives Wild Code School
Symfony

28 - Symfony : Twig component

Quête 31 sur 35 · 1 image archivée

Objectifs

  • ✅ Créer une navbar via un Twig component
  • ✅ Afficher les 3 derniers épisodes dans une sidebar ou dans le footer
title-book
Introduction

User stories 📋

In progress 🤸

en tant que visiteur, je souhaite accéder aux catégories depuis la barre de navigation

Doing 🏗️

Intégrer un contrôleur dans le template Twig de la navbar

Done ✅

en tant que visiteur, je souhaite avoir accès à un formulaire d'inscription afin de pouvoir me créer un compte

Sommaire

Imbriquer le contrôleur

Depuis le début de la conception de ton Wild Series, tu te demandes comment tu vas bien pouvoir ajouter la liste des catégories dans la barre de navigation.

Techniquement, tu pourrais ajouter dans TOUTES les méthodes de TOUS tes contrôleurs : 'categories' => $categories Techniquement, tu pourrais ajouter dans TOUTES les méthodes de TOUS tes... oui en effet, on doit beaucoup se répéter, ce n’est pas DRY ! Et si un développeur oubliait de l’ajouter lors de la création d’une prochaine méthode ?

La meilleure alternative sera plutôt de passer par le système de component dans Twig. Il faut voir cela comme un "super" include d'une vue twig, qui ne se contente pas d'afficher que l'HTML, mais peut aller récupérer dynamiquement des données au passage. Pour cela, il faut tout d'abord l'installer :

Installer le composant

php
composer require symfony/ux-twig-component
↗
Twig Components
symfony.com

Créer un component Twig

Un component Twig est une classe PHP. Tu pourrais la créer à la main mais comme souvent avec Symfony, tu vas utiliser le maker (de nouvelles commnandes sont apparues suite à l'installation du twig-component). Lance la commande suivante et répond aux questions.

sh
symfony console make:twig-component

Pour la première question, appelle ton composant Navbar. Pour la seconde, choisis "no" (option par défaut) quand il te demande si tu veux que ce composant soit un LiveComponent (tu verras cela dans une prochaine quête).

Le maker t'informe alors qu'il a créé deux fichiers :

  • src/Twig/Components/Navbar.php (la classe PHP Navbar dans un nouveau dossier src/Twig/Components)
  • templates/components/Navbar.html.twig (la vue Twig correspondante dans un nouveau dossier templates/components)

Côté PHP

Ouvre le fichier src/Twig/Components/Navbar.php

php
<?php

namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final class Navbar
{
}

Tu vois une classe vide, dans le namespace App\Twig\Components. Au dessus de la classe, tu as un nouvel attribut #[AsTwigComponent]. C'est cet attribut qui permet à Symfony de comprendre que nous avons ici un composant relié à une vue du même nom et qui s'appelle donc components/Navbar.html.twig

Ce que tu veux faire, c'est récupérer automatiquement les catégories à chaque fois que tu souhaites afficher ta navbar. Il y a donc besoin (en plus d'afficher le HTML de ta nav) de faire une requête en base de données pour récupérer ces catégories, puis de construire le HTML qui va les afficher. Tu vas faire cela dans un dropdown Bootstrap, UIkit ou Pico CSS.

Premièrement, tu dois pouvoir accéder au Repository CategoryRepository (sans cela, il serait difficile de créer un menu dynamique des catégories). Comme pour les services, tu vas passer par le __construct() pour le récupérer.

php
<?php

namespace App\Twig\Components;

use App\Repository\CategoryRepository;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent()]
final class Navbar
{
    public function __construct(
        private CategoryRepository $categoryRepository
    ) {
    }
}

Ensuite, il te faut une méthode qui va récupérer les categories (idéalement par ordre alphabétique, c'est plus sympa), donc getCategories(). Le nom de la méthode doit toujours commencer par get pour le bon fonctionnement.

php
<?php

namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
use App\Repository\CategoryRepository;

#[AsTwigComponent()]
final class Navbar
{
    public function __construct(
        private CategoryRepository $categoryRepository
    ) {
    }

    public function getCategories(): array
    {
        return $this->categoryRepository->findBy([], ['name' => 'ASC']);
    }
}

Côté component Twig

Le principe de fonctionnement est en deux parties. Première partie, la vue Twig et seconde partie, l'appel de cette vue dans une autre vue twig (par exemple base.html.twig).

Première partie : création de la vue du composant

La vue du component Twig a été générée par le maker, rends-toi sur le fichier templates/components/Navbar.html.twig.

html
<div{{ attributes }}>
    <!-- component html -->
</div>

Tu as une <div{{ attributes }}> vide. Le {{ attributes }} permet de charger la configuration stimulus (sur laquelle s'appuie Symfony UX, pour rappel).

Dans cette <div>, que tu peux modifier en un autre tag HTML si tu le souhaites, tu vas avoir accès aux getters créés dans la classe reliée à cette vue, donc ta classe App\Twig\Components\Navbar

Nous allons boucler sur le tableau reçu du component PHP this.categories. Profitons-en pour expliquer this.categories côté Twig.

La variable this.categories fait référence à getCategories(). this pour le composant Navbar et categories qui va aller chercher le getter de la propriété du même nom, soit getCategories().

C'est le côté magique de Symfony.

html
<li{{ attributes }} class="nav-item dropdown">
    <a
            class="nav-link dropdown-toggle"
            href="#"
            role="button"
            data-bs-toggle="dropdown"
            aria-expanded="false">
        Categories
    </a>
    <ul class="dropdown-menu">
        {% for category in this.categories %}
            <li>
                <a
                        class="dropdown-item"
                        href="{{ path('app_category_show', {'categoryName': category.name}) }}">
                    {{ category.name }}</a>
            </li>
        {% endfor %}
    </ul>
</li>

Au delà du code HTML nécessaire à créer un dropdown dans une navbar bootstrap, tu vois que tu peux récupérer le retour de ta méthode getCategories() de ton component, en utilisant this.categories. La syntaxe change un peu par rapport à ce que tu as l'habitude de manipuler, car il faut bien rajouter le this sinon il ne reconnait pas la variable. Par contre, inutile d'ajouter "get" devant "categories", Twig le fait tout seul.

Seconde partie : intégration de la vue dans la navbar

Maintenant que tu as créé ce morceau de vue, tu dois l'inclure dans ta navbar. Rends-toi sur le code de ta navbar et fais appel à la vue Twig de la première partie.

html
{# fichier où se trouve ta navbar #}
<nav class="navbar navbar-expand-lg">
// ...
    {{ component('Navbar') }}
// ...
</nav>

Inclus le composant (qui correspond uniquement au dropdown, au bon endroit dans ta navbar. Une fois fait, réactualise ta page, tu devrais voir les catégories apparaître dans le dropdown, bravo !

Récapitulons !

  • Tu crées ton fichier PHP dans src/Twig/Components/Navbar.php
  • Tu crées tes méthodes __construct() et getCategories() dans src/Twig/Components/Navbar.php
  • Tu crées ta page Twig Navbar.html.twig dans templates\components\Navbar.html.twig et tu intègres ton code pour afficher ton dropdown comme tu le souhaites.
  • Tu fais appel dans ta vue de navbar à ton component {{ component('Navbar') }} (ou <twig:NavBar />)
↗
UX Symfony : Twig Component
ux.symfony.com
↗
Component twig
symfony.com
↗
Symfony : Twig et Live Components
yoandev.co

Pour aller plus loin !

Il est possible d'intégrer un component dans un autre component. Par exemple, il est possible d'avoir un component qui affiche tous les épisodes mais en se basant sur le design d'un component affichant un épisode.

💪 Challenge

Une fois ta navbar terminée, et pour mettre en pratique, crée un nouveau composant LastEpisode dont le but sera d'afficher les derniers épisodes créés dans la base. Tu devras les afficher dans une balise HTML <aside> sur toutes tes pages (au dessus du footer, ou en sidebar comme tu préfères en fonction de ton design).

Les trois cards d'épisode devront afficher le titre de l'épisode, le numéro, la saison et la série.

Critères de validation

  • La navbar affiche les catégories dans un dropdown
  • Un aside affiche les trois derniers épisodes créés dans l'application (via un Twig Component)