29 - Symfony : Live Component
Objectifs
- ✅ Réaliser des fonctionnalités dynamiques sans coder une seule ligne de Javascript 🤯
Pré-requis
Avoir terminé les quêtes
Introduction
Dans cette quête, tu vas apprendre à utiliser une notion complémentaire aux Twig Component : les Live Components.
Sommaire
Qu’est ce qu’un Live Component ?
Les Live Component ont été introduits dans Symfony 5.3 grâce au composant SymfonyLive. Ils permettent de construire des interfaces utilisateur interactives en utilisant des technologies telles que JavaScript et WebSockets.
Les Live Components facilitent la mise en œuvre d'une expérience utilisateur en temps réel, où les changements apportés à ton application sont reflétés instantanément sans rechargement de page.
Installation
Nous devons installer le composant SymfonyLive dans notre projet. Pour cela, lance la commande suivante :
composer require symfony/ux-live-component
Si tu utilises un builder comme Webpack Encore ou Vite, pense bien à installer tes assets et à redémarrer la compilation des fichiers
yarn install --force
yarn dev
La barre de recherche à tout faire (mais c’est super)

Nous allons créer ensemble une barre de recherche nous permettant d’afficher, sans rechargement de page, et à chaque lettre tapée dans notre input, les séries correspondantes. Et tout ça, sans une seule ligne de JavaScript.
Comment cela marche-t-il ? Les Live Component s'appuient sur les contrôleurs Stimulus que nous avons vu précédemment. Ils écoutent les évènements définis sur nos différents éléments HTML, tels que les inputs ou les boutons, et déclenchent des requêtes Ajax. Une fois ces requêtes exécutées, Symfony régénère nos composants avec nos nouvelles données et met à jour le DOM.
Comme nous l'avons fait dans la quête précédente, nous allons utiliser la CLI Symfony pour générer notre LiveComponent.
Crée un nouveau composant appelé ProgramSearch grâce à la commande
symfony console make:twig-component
Cette fois tu pourras répondre oui à la question Make this a live component?
Et de la même manière qu'avec un TwigComponent, deux fichiers ont été créés par le maker :
- src/Twig/Components/ProgramSearch.php
- templates/components/ProgramSearch.html.twig
Voici le code de la classe PHP généré :
<?php
namespace App\Twig\Components;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\DefaultActionTrait;
#[AsLiveComponent]
final class ProgramSearch
{
use DefaultActionTrait;
}
-
L8. L’annotation
#[AsLiveComponent]nous permet de dire à Symfony : cette classe sera un Live Component. -
L11. Tu remarques l’utilisation d’un trait dans cette classe. Cela permet à Symfony de regénérer le composant. C’est nécessaire au bon fonctionnement du Live Component. Voir la documentation pour plus de précision
Ajoute à ta classe ces quelques lignes qui devraient te rappeler ce que tu as fait sur la quête précédente. Nous allons ensuite voir cela en détail.
<?php
namespace App\Twig\Components;
use App\Repository\ProgramRepository;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\DefaultActionTrait;
#[AsLiveComponent()]
final class ProgramSearch
{
use DefaultActionTrait;
#[LiveProp(writable: true)]
public string $query = '';
public function __construct(private ProgramRepository $programRepository) {}
public function getPrograms(): array
{
return $this->programRepository->findLikeName($this->query);
}
}
- L15-16. Création de notre propriété
$query, qui contiendra la valeur de notre recherche à chaque fois que l’on tapera une lettre dans notre champ. L’attribut#[LiveProp]nous permet de définir cette propriété comme dynamique.
Une propriété avec l'attribut LiveProp devient une propriété "persistante" pour un composant. En d'autres termes, chaque fois que le component se réaffiche, il se souviendra des valeurs d’origine de la propriété.
Les LiveProps doivent être une valeur qui peut être envoyée en Javascript (int, float, string, bool, null, arrays, enums, DateTime objects & Doctrine entity objects)
🚨 Il est aussi très important de remarquer, que contrairement à d’habitude, la propriété est publique et non privée ou protected. Ceci est primordial au bon fonctionnement d’un Live Component.
- L22. Nous appelons la fonction
findLikeNamede notreProgramRepositoryréalisée sur la quête précédente. Cela nous permet de récupérer tous les programmes liés à notre recherche.
Tu peux en profiter pour améliorer légèrement cette requête de sorte qu'elle n'affiche rien si la valeur de $query est vide.
Si tu n'y arrives vraiment pas, voici la solution ⬇️.
Voir la solution
//src/Repository/ProgramRepository.php
//..
public function findLikeName(string $name): array
{
$result = [];
if (!empty($name)) {
$result = $this->createQueryBuilder('p')
->andWhere('p.title LIKE :name')
->setParameter('name', '%' . $name . '%')
->orderBy('p.title', 'ASC')
->getQuery()
->getResult();
}
return $result;
}
Enfin, il te reste une dernière chose à faire, modifier le fichier HTML de ton component. Celui-ci contiendra 3 éléments principaux :
-
Le div contient déjà l’helper Twig
{{ attributes }}. Les attributs sont des valeurs que tu peux passer à ton component. Par défaut, cela permet de passer le contrôleur Stimulus. Tu peux aller plus loin et personnaliser ton component avec des attributs HTML de ton choix. -
Un champ input de type recherche.
Regarde du côté Data Binding de la documentation. Un exemple similaire y est expliqué.
L'attribut data-model nous permet ici de faire un lien entre le champ HTML et la propriété d'une classe LiveComponent.
Dans notre cas, le lien se ferait entre le champ de type search et la propriété $query class ProgramSearch.
Cela nous permettrait de mettre à jour automatiquement la valeur de notre propriété (souviens-toi de la notion de "persistance" expliquée plus haut) lorsque la valeur du champ HTML est modifiée.
- La boucle nous permettant d’afficher tous les programmes récupérés grâce à la fonction
getPrograms()de notre classeProgramSearch
Voici la solution si tu n’y arrives pas :
Voir la solution
<div{{ attributes }}>
<div class="mb-3">
<label class="form-label" for="search">
Search a progam in our catalogue
</label>
<input type="search"
id="search"
class="form-control"
data-model="query">
</div>
{% for program in this.programs %}
<article>
<h2 class="mt-4"> {{ program.id }} / {{ program.title }} -
Category: {{ program.category.name }}</h2>
<p>{{ program.synopsis }}</p>
<a href="{{ path("program_show", { slug: program.slug }) }}"> see more </a>
</article>
{% endfor %}
</div>
Tu peux ensuite inclure ce tout nouveau component sur ta page d’accueil et admirer le résultat.
Pour rappel, voici la syntaxe afin d'ajouter un component :
{{ component('ProgramSearch') }}
Tout est fait automatiquement, sans rechargement de page, et tu n'as pas codé une seule ligne de JavaScript.
Mission accomplie.
💪 Challenge
Rendezvous à la quête suivante pour réaliser un challenge avec un LiveComponent