Automatiser les workflows d'approbation en PHP/Symfony : les leçons d'un moteur Laravel anti-spam
Dans les projets web d'entreprise, un problème revient inlassablement : les workflows d'approbation génèrent une avalanche de notifications par email. Demandes de congés, factures, bons de commande — chaque élément en attente déclenche un email distinct, jusqu'à saturer la boîte mail du responsable et noyer l'essentiel dans le bruit. Apurba Singh a publié sur dev.to une solution open source baptisée Laravel Approval Engine, conçue pour résoudre exactement ce problème. Cet article analyse l'architecture de cette solution et propose des pistes concrètes pour transposer ces concepts dans un projet Symfony.
Le problème : la fatigue des notifications en entreprise
Imaginez un responsable qui supervise 50 demandes en attente un lundi matin. Sans système de regroupement, il reçoit 50 emails distincts. Chacun contient un lien, un contexte, une action à effectuer. Le résultat est prévisible : les emails sont ignorés, les approbations s'accumulent, et le processus métier se bloque.
Ce phénomène, souvent appelé notification fatigue, est un anti-pattern classique dans les systèmes d'information d'entreprise. La solution n'est pas de supprimer les notifications, mais de les consolider intelligemment.
C'est le cœur du concept proposé par Apurba Singh : plutôt que d'envoyer N emails pour N éléments en attente, le moteur les regroupe en un seul digest contenant l'ensemble des actions disponibles.
L'architecture du moteur d'approbation : analyse technique
L'approche décrite dans l'article source repose sur plusieurs principes architecturaux solides, indépendants du framework utilisé.
Le batching différé
Les enregistrements en attente ne déclenchent pas immédiatement une notification. Ils transitent par un état pending et sont périodiquement regroupés par une commande planifiée (équivalent d'un cron ou d'un messenger:consume en Symfony). Ce découplage entre la création d'un événement métier et son traitement est une bonne pratique fondamentale.
En Symfony, ce pattern se modélise naturellement avec le composant Messenger :
// Dispatch d'un message lors de la création d'une demande
$this->messageBus->dispatch(new ApprovalRequestCreated($requestId));
Un handler dédié met à jour le statut de la demande, tandis qu'un second worker, déclenché par un scheduler, agrège les éléments pending et génère le digest.
Les workflows multi-étapes
L'article mentionne la possibilité de définir des chaînes d'approbation : Manager → Finance → Directeur. C'est exactement le cas d'usage pour lequel le composant Workflow de Symfony a été conçu.
// config/packages/workflow.yaml
framework:
workflows:
approval_request:
type: workflow
marking_store:
type: method
property: status
supports:
- App\Entity\ApprovalRequest
places:
- draft
- pending_manager
- pending_finance
- approved
- rejected
transitions:
submit:
from: draft
to: pending_manager
manager_approve:
from: pending_manager
to: pending_finance
finance_approve:
from: pending_finance
to: approved
Chaque transition peut émettre des événements auxquels on souscrit pour déclencher des notifications, des logs ou des actions métier spécifiques — sans modifier le cœur du workflow.
La sécurité par token
Une fonctionnalité particulièrement intéressante de la solution décrite est la sécurité par token : l'approbateur peut agir directement depuis l'email sans se connecter à une interface. Cela réduit les frictions et accélère les traitements.
En Symfony, ce mécanisme se met en place avec un token signé, stocké en base ou en cache :
class ApprovalTokenService
{
public function generate(ApprovalRequest $request): string
{
$token = bin2hex(random_bytes(32));
$this->cache->set(
'approval_token_' . $token,
$request->getId(),
3600 * 48 // 48 heures
);
return $token;
}
public function resolve(string $token): ?int
{
return $this->cache->get('approval_token_' . $token);
}
}
Le lien inclus dans le digest pointe vers un endpoint public qui vérifie le token, identifie la demande et exécute la transition appropriée.
Ce que cela change pour vos projets Symfony
Transposer ces idées dans un projet Symfony/PHP apporte plusieurs bénéfices concrets.
Réduction du volume d'emails : avec un batch quotidien ou toutes les heures, le nombre de messages envoyés peut être divisé par 10 à 50 selon le volume d'activité. C'est aussi un argument de délivrabilité : moins d'emails sortants, moins de risques d'être classé en spam par les serveurs destinataires.
Découplage métier/infrastructure : en passant par des events et des handlers Messenger, la logique d'approbation reste indépendante du canal de notification. Demain, si l'entreprise veut recevoir le digest sur Slack ou Teams plutôt que par email, seul le handler de notification change.
Maintenabilité : définir les étapes d'un workflow dans une configuration YAML plutôt que dans du code conditionnel rend le système lisible par des profils non techniques et facilite les évolutions.
Traçabilité : chaque transition du workflow peut être loggée avec son acteur, sa date et son motif. C'est souvent une exigence implicite dans les projets d'entreprise qui devient explicite lors des audits.
Conclusion
La solution présentée par Apurba Singh dans son article sur dev.to (voir la source originale) illustre un principe simple mais puissant : les problèmes de notification ne se résolvent pas en envoyant moins d'informations, mais en les structurant mieux.
Les outils pour implémenter ces patterns existent nativement dans l'écosystème Symfony — Messenger pour le traitement asynchrone, le composant Workflow pour les machines à états, et les événements du framework pour le découplage. Il ne s'agit pas de réinventer la roue, mais de les combiner avec intention.
Si vous gérez des workflows d'approbation dans vos projets PHP et que vos utilisateurs se plaignent de trop d'emails, c'est probablement le moment d'investir dans cette architecture. Le gain en expérience utilisateur est immédiat, et la robustesse technique sur le long terme en vaut largement l'effort initial.