Décorer un service Symfony avec #[AsDecorator]
La décoration de service, dans Symfony, glisse une classe entre un service et ceux qui l'utilisent, pour changer son comportement sans toucher à son code.
#[AsDecorator(Oracle::class)] // qui demande un Oracle reçoit désormais le carnet… final class OracleEnCache implements Oracle { public function __construct( #[AutowireDecorated] private readonly Oracle $mage, // … et le carnet reçoit le mage private readonly CacheInterface $cache, ) { } public function ventsDuJour(string $contree): string { return $this->cache->get('vents-'.md5($contree), fn () => $this->mage->ventsDuJour($contree)); } }
Le décorateur implémente la même interface que le service décoré. #[AsDecorator] demande au conteneur de le mettre à la place de l'original : partout où l'on injecte Oracle, on reçoit le décorateur, et #[AutowireDecorated] lui passe le service d'origine, qu'il appelle quand il le juge utile. Ni les contrôleurs ni le service décoré n'en savent rien ; c'est ainsi que Symfony entoure ses propres services de traces ou de cache. bin/console debug:container montre quel service répond vraiment à un identifiant. Le piège : une classe qui demande la classe concrète, OracleDuMage, au lieu de l'interface. Elle reçoit l'original et contourne le décorateur, sans erreur.
Les exercices font écrire le carnet de Pipin, un décorateur qui retient les prévisions d'un mage payé à chaque consultation, sans modifier ni le mage ni le contrôleur de la volière ; puis chercher, dans une taverne déréglée où rien ne lève d'erreur, pourquoi la facture du mage explose de nouveau.
2 exercices font travailler cette notion, en écrivant du code dans le navigateur.
Dans les parcours
- L'oracle des vents Symfony pour les devs PHP · chapitre 9 : Les rouages de la taverne
- 🐉 Boss : la taverne à l'envers Symfony pour les devs PHP · chapitre 9 : Les rouages de la taverne