Terrain 12 — Async & temps réel
🔍 Renfort : Partie 12.
1. Message + handler ⭐⭐
🕹️ Mission : un message SendBookingConfirmation(int $bookingId) + son handler.
✅ Solution
final readonly class SendBookingConfirmation { public function __construct(public int $bookingId) {} }
#[AsMessageHandler]
final class SendBookingConfirmationHandler {
public function __invoke(SendBookingConfirmation $m): void { /* recharge l'entité + envoie */ }
}2. Ids, pas d’entités ⭐⭐
🕹️ Mission : pourquoi transporter bookingId et non l’objet Booking ?
✅ Solution
Le message est sérialisé/désérialisé (file) ; une entité y est mal adaptée (état périmé, EM déconnecté). On transporte l’id et on recharge l’entité fraîche dans le handler.
3. Router en async ⭐⭐
🕹️ Mission : router SendBookingConfirmation vers un transport async.
✅ Solution
framework:
messenger:
routing:
App\Message\SendBookingConfirmation: async4. Consommer ⭐
🕹️ Mission : la commande pour traiter la file async.
✅ Solution
php bin/console messenger:consume async -vv (supervisé en prod).
5. Idempotence ⭐⭐⭐⭐
🕹️ Mission : pourquoi un handler de paiement doit-il être idempotent ?
✅ Solution
Un message peut être rejoué ; sans idempotence, on débiterait deux fois. Vérifier un état (isPaid()) ou une clé d’idempotence avant d’agir.
6. Scheduler ⭐⭐⭐
🕹️ Mission : envoyer les rappels chaque jour à 8h.
✅ Solution
RecurringMessage::cron('0 8 * * *', new SendDailyReminders())(dans une Schedule fournie par #[AsSchedule].)
7. Email Twig ⭐⭐
🕹️ Mission : un e-mail de confirmation rendu par un template.
✅ Solution
(new TemplatedEmail())->to($email)->subject('Confirmée')
->htmlTemplate('emails/confirmation.html.twig')->context(['booking' => $b]);8. Publier Mercure ⭐⭐⭐
🕹️ Mission : publier les places restantes d’un créneau sur son topic.
✅ Solution
$this->hub->publish(new Update(
'https://booklab.test/slots/' . $slot->getId(),
json_encode(['seatsLeft' => $slot->getSeatsLeft()]),
));9. Consommer Mercure (Next.js) ⭐⭐⭐
🕹️ Mission : avec quelle API navigateur s’abonne-t-on, et que ne pas oublier ?
✅ Solution
EventSource (SSE), dans un Client Component ; fermer la connexion (es.close()) au démontage (cleanup).
10. Confirmer un paiement Stripe ⭐⭐⭐⭐⭐
🕹️ Mission : où confirme-t-on réellement le paiement, et quelle vérification est indispensable ?
✅ Solution
Dans le webhook (checkout.session.completed), pas la redirection de succès ; avec vérification de la signature (constructEvent + secret) et un handler idempotent.
Terrain suivant : Interopérabilité.