Aller au contenu principal

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
info

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 !');
}
astuce

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]);
}
}
attention

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


Quelle classe Mercure représente une mise à jour à publier ?


Quel est le premier paramètre du constructeur de la classe Update ?


Comment Symfony injecte-t-il HubInterface dans un contrôleur ?


Sous quel format les données d'une Update Mercure sont-elles habituellement encodées ?


Quelle méthode de HubInterface déclenche l'envoi d'une Update vers les subscribers ?


Pourquoi est-il important de valider la valeur du statut avant de la publier via Mercure ?


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.

Bonne pratique - Sous-espaces de noms pour les contrôleurs admin

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

Bonne pratique - Regrouper les imports par namespace

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

Bonne pratique - Utiliser une constante pour le préfixe du topic

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.

📌 Une solution