Souscrire en temps réel
Créer la page client qui reçoit les mises à jour Mercure et met à jour l'interface automatiquement sans rechargement
Notions théoriques
La fonction Twig mercure()
Le bundle Mercure ajoute une fonction Twig mercure() qui génère l'URL complète d'abonnement au Hub pour un topic donné. Elle intègre automatiquement les paramètres nécessaires (topic, JWT si besoin).
{% set url = mercure('https://symfolivraison.local/livraison/' ~ livraison.id) %}
La fonction génère une URL du type :
https://localhost/.well-known/mercure?topic=https%3A%2F%2Fsymfolivraison.local%2Flivraison%2F1
Cette URL est passée à EventSource pour ouvrir la connexion SSE.
Dans un contexte JavaScript inline (attribut <script>), utilisez toujours le filtre |escape('js') pour protéger contre les injections XSS :
"{{ mercure(...)|escape('js') }}"
L'API EventSource JavaScript
EventSource est une API JavaScript native qui établit et maintient une connexion SSE avec le Hub Mercure. Elle est supportée par tous les navigateurs modernes sans bibliothèque externe.
const eventSource = new EventSource(url);
eventSource.onmessage = function(event) {
const data = JSON.parse(event.data);
// data = { id: 1, statut: "Expédiée" }
};
| Événement | Déclenchement |
|---|---|
onopen | Connexion établie avec le Hub |
onmessage | Une mise à jour a été reçue |
onerror | Erreur de connexion (reconnexion automatique en cours) |
EventSource se reconnecte automatiquement si la connexion est interrompue — c'est un comportement natif du protocole SSE. Contrairement aux WebSockets, aucun code de gestion de reconnexion n'est nécessaire.
Mise à jour du DOM en JavaScript
Quand une mise à jour est reçue, il suffit de modifier le DOM pour refléter le nouveau statut :
eventSource.onmessage = function(event) {
const data = JSON.parse(event.data);
document.getElementById('statut').textContent = data.statut;
};
JSON.parse(event.data) désérialise la chaîne JSON envoyée par Symfony en objet JavaScript. Les clés correspondent aux clés du tableau PHP passé à json_encode() lors de la publication.
Exemple de mise en application
Le contrôleur de suivi (page client)
<?php
// src/Controller/LivraisonController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class LivraisonController extends AbstractController
{
#[Route('/livraison/{id}', name: 'livraison_suivi')]
public function suivi(int $id): Response
{
// En pratique, charger depuis Doctrine ; ici simulé pour simplifier
$livraison = ['id' => $id, 'client' => 'Alice', 'statut' => 'En préparation'];
return $this->render('livraison/suivi.html.twig', [
'livraison' => $livraison,
]);
}
}
Le template Twig avec souscription Mercure
{# templates/livraison/suivi.html.twig #}
{% extends 'base.html.twig' %}
{% block title %}Suivi de votre livraison #{{ livraison.id }}{% endblock %}
{% block body %}
<h1>Suivi de votre commande #{{ livraison.id }}</h1>
<div id="statut-container">
<p>Bonjour {{ livraison.client }}, statut actuel :</p>
<p id="statut" style="font-size: 1.5rem; font-weight: bold;">
{{ livraison.statut }}
</p>
</div>
<script>
const mercureUrl = "{{ mercure('https://symfolivraison.local/livraison/' ~ livraison.id)|escape('js') }}";
const eventSource = new EventSource(mercureUrl);
eventSource.onmessage = function(event) {
const data = JSON.parse(event.data);
document.getElementById('statut').textContent = data.statut;
};
eventSource.onerror = function() {
console.error('Connexion Mercure perdue, reconnexion automatique...');
};
</script>
{% endblock %}
Test du flux complet
Ouvrez deux onglets dans votre navigateur :
- Onglet 1 —
https://localhost/livraison/1(page de suivi client) - Onglet 2 — Appelez l'URL admin pour changer le statut :
https://localhost/admin/livraison/1/statut/Expédiée
Le statut dans l'onglet 1 se met à jour instantanément sans rechargement de page.
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Étape 1 — Créer le contrôleur de suivi client
Dans src/Controller/, créez le fichier LivraisonController.php avec la route /livraison/{id} :
Maintenez deux contrôleurs distincts : Admin\LivraisonController pour les routes d'administration (protégées), et LivraisonController pour les routes publiques. Cela simplifie l'application des règles de sécurité dans security.yaml.
Étape 2 — Créer le template Twig et générer l'URL Mercure
Dans templates/livraison/, créez suivi.html.twig. Commencez par la souscription au Hub :
Utilisez systématiquement |escape('js') quand vous insérez une variable Twig dans un contexte JavaScript. Sans cet échappement, un topic contenant des guillemets ou des backslashes peut briser le script ou créer une faille XSS.
Étape 3 — Mettre à jour l'affichage à la réception d'une mise à jour
Utilisez textContent plutôt qu'innerHTML pour insérer du texte reçu d'un serveur. innerHTML interprète le HTML et peut introduire une faille XSS si les données ne sont pas assainies. textContent insère toujours du texte brut.
Étape 4 — Tester le flux complet
Ouvrez deux onglets dans votre navigateur et testez :
- Onglet 1 —
https://localhost/livraison/1 - Onglet 2 —
https://localhost/admin/livraison/1/statut/Expédiée
Vérifiez que le statut dans l'onglet 1 change sans rechargement après l'appel de l'onglet 2.