Les event subscribers
Un autre moyen d'écouter un événement est de créer un event subscriber. Dans ce cas, on peut écouter l'événement comme si on s'y inscrivait.
Créons un autre écouteur, mais sous la forme d'un subscriber. Il va écouter l'événement prePersist de Doctrine, et nous allons lui déléguer le hachage du mot de passe d'un utilisateur lors de la persistence.
La particularité des subscribers
La différence entre les event listeners et les subscribers est que les subscribers savent toujours quel(s) événement(s) ils écoutent :
src/EventSubscriber/HashUserPasswordSubscriber.php
<?php
namespace App\EventSubscriber;
use App\Entity\User;
use Doctrine\ORM\Event\PrePersistEventArgs;
use Doctrine\ORM\Events;
use Doctrine\Bundle\DoctrineBundle\EventSubscriber\EventSubscriberInterface;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
class HashUserPasswordSubscriber implements EventSubscriberInterface
{
public function __construct(private UserPasswordHasherInterface $hasher)
{
}
public function getSubscribedEvents(): array
{
return [
Events::prePersist,
];
}
public function prePersist(PrePersistEventArgs $args): void
{
$entity = $args->getObject();
if (!$entity instanceof User) {
return;
}
$entity->setPassword($this->hasher->hashPassword($entity, $entity->getPassword()));
}
}
L'autoconfiguration
Nous avons vu dans la section précédente le concept des tags, qui permettent à Symfony d'enregistrer un service d'une manière particulière, suivant le tag qui est appliqué.
Ici, dans la classe HashUserPasswordSubscriber, nous déclarons implémenter une interface EventSubscriberInterface issue de Doctrine.
En réalité, dans notre application, un système d'autoconfiguration est activé : à la lecture de cette interface, il va automatiquement ajouter un tag à notre service pour qu'il soit considéré comme un event subscriber de Doctrine.
Ensuite, vu que l'interface définit une signature de méthode getSubscribedEvents, nous l'implémentons et déclarons quel événement nous souhaitons écouter.
On nomme notre méthode comme l'événement, et dans la méthode prePersist on effectue notre action seulement si l'entité est de type User. En effet, le subscriber sera appelé pour toute entité qui est persistée.
Vérifions depuis la console le tag qui a été automatiquement ajouté à notre service. Le tag concerné est doctrine.event_subscriber :
php bin/console debug:container --tag=doctrine.event_subscriber
Normalement, on trouve notre classe HashUserPasswordSubscriber dans la liste des services portant ce tag.
Conséquences de l'ajout d'un subscriber
Tout comme avec les listeners, nous n'avons pas à nous soucier d'une logique de code qui a ou aura peut-être besoin d'être exécutée à plusieurs endroits de mon application.
À la place, je peux écouter des événements et exécuter ces bouts de code quand je le souhaite.
En revanche, contrairement au listener, nous n'avons pas eu de besoin de configurer notre subscriber pour lui ajouter un tag : en implémentant une interface, le mécanisme d'autoconfiguration de Symfony a pris le relais et a ajouté un tag automatiquement à notre subscriber.