Publier un événement
Créer le contrôleur d'administration qui publie une mise à jour de statut en temps réel vers le Hub Mercure
Notions théoriques
La classe Update
Pour publier une mise à jour, Mercure utilise la classe Update du composant symfony/mercure. Elle prend deux paramètres obligatoires :
use Symfony\Component\Mercure\Update;
$update = new Update(
'https://monapp.fr/livraison/42', // 1. le topic
json_encode(['statut' => 'Expédiée']) // 2. les données (JSON)
);
- Le topic identifie la ressource mise à jour (une URL unique par ressource)
- Les données sont une chaîne JSON transmise à tous les subscribers du topic
Il est recommandé de sérialiser les données en JSON avec json_encode(). Les subscribers JavaScript peuvent alors les désérialiser facilement avec JSON.parse().
L'interface HubInterface
Pour envoyer l'Update vers le Hub, Symfony injecte automatiquement l'interface HubInterface dans le contrôleur (ou tout service). Cette interface expose une unique méthode : publish().
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;
public function changerStatut(HubInterface $hub): Response
{
$update = new Update(
'https://monapp.fr/livraison/42',
json_encode(['statut' => 'Expédiée'])
);
$hub->publish($update); // ← envoie l'Update au Hub
return new Response('Mise à jour envoyée !');
}
HubInterface est autowirable — Symfony l'injecte automatiquement dans vos contrôleurs et services par le système d'injection de dépendances, sans configuration supplémentaire.
Construction du topic dans SymfoLivraison
Dans notre projet, le topic est construit à partir de l'identifiant de la livraison :
https://symfolivraison.local/livraison/{id}
Chaque client s'abonnera uniquement au topic de sa livraison et ne recevra que les mises à jour qui le concernent. Un admin qui change le statut de la livraison n°3 ne déclenchera aucune mise à jour sur la page de suivi de la livraison n°7.
Exemple de mise en application
Voici le contrôleur d'administration complet qui publie un changement de statut via Mercure :
<?php
// src/Controller/Admin/LivraisonController.php
namespace App\Controller\Admin;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;
use Symfony\Component\Routing\Attribute\Route;
class LivraisonController extends AbstractController
{
private const TOPIC_PREFIX = 'https://symfolivraison.local/livraison/';
private const STATUTS_VALIDES = [
'En préparation',
'Expédiée',
'En cours de livraison',
'Livrée',
];
#[Route('/admin/livraison/{id}/statut/{statut}', name: 'admin_livraison_statut')]
public function changerStatut(int $id, string $statut, HubInterface $hub): Response
{
if (!in_array($statut, self::STATUTS_VALIDES)) {
return $this->json(['error' => 'Statut invalide'], 400);
}
$update = new Update(
self::TOPIC_PREFIX . $id,
json_encode(['id' => $id, 'statut' => $statut])
);
$hub->publish($update);
return $this->json(['success' => true, 'statut' => $statut]);
}
}
Notez la validation du statut (in_array) avant de publier : sans elle, n'importe qui pourrait appeler cette URL avec n'importe quelle valeur. En production, cette route devrait également être protégée par un contrôle d'accès (security.yaml).
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Étape 1 — Créer le contrôleur d'administration
Dans src/Controller/Admin/, créez le fichier LivraisonController.php.
Regrouper les contrôleurs d'administration dans Controller\Admin\ permet de séparer clairement les routes publiques des routes réservées aux administrateurs. Cela facilite l'application de règles de sécurité globales dans security.yaml (ex : path: ^/admin → rôle requis).
Étape 2 — Ajouter les imports nécessaires
Classez les use par ordre alphabétique du namespace. Cela facilite la lecture et évite les doublons dans les projets en équipe.
Étape 3 — Implémenter la méthode changerStatut
Définissez le format du topic dans une constante de classe (TOPIC_PREFIX) plutôt qu'en dur dans chaque méthode. Cette valeur sera réutilisée dans la séance suivante pour la souscription côté client — une seule modification suffit si l'URL change.