[Symfony 4] – Gestion d’événements

On continue notre série de gestion des utilisateurs sans FOSUserBundle, cette fois on va mettre en place un EventListener, c’est à dire un événement qui va se déclencher là où on le voudra.

On va simplement envoyer un mail à l’utilisateur qui vient de s’inscrire afin de lui souhaiter la bienvenue.

Pour cela on va déjà ajouter la librairie qui permet de gérer l’envoi des mails :

composer req symfony/swiftmailer-bundle

Suite à ça vous devez avoir une nouvelle ligne dans votre fichier .env, qu’il faut modifier selon votre serveur, pour moi c’est :

MAILER_URL=smtp://localhost:25?encryption=&auth_mode=

(vous avez aussi la même ligne dans le fichier phpunit.xml.dist si vous voulez envoyer des mails durant vos tests)

On va aussi ajouter quelques paramètres dans nos fichiers de config, comme l’adresse expéditeur :

# services.yaml
parameters:
    locale: 'en'
    app.notifications.email_sender: g.ponty@dev-web.io

services:
   # le nom de votre service
   App\EventSubscriber\RegistrationNotifySubscriber:
        # le nom de la variable que l'on utilisera dans le service
        $sender: '%app.notifications.email_sender%'

Pour mettre en place de bonnes pratiques, on va créer un fichier qui regroupera tous nos events, ça permettra de les avoir tous au même endroit :

// App/Events.php
namespace App;

/**
 * This class defines the names of all the events dispatched in
 * our project. It's not mandatory to create a
 * class like this, but it's considered a good practice.
 *
 */
final class Events
{
    /**
     * For the event naming conventions, see:
     * https://symfony.com/doc/current/components/event_dispatcher.html#naming-conventions.
     *
     * @Event("Symfony\Component\EventDispatcher\GenericEvent")
     *
     * @var string
     */
    const USER_REGISTERED = 'user.registered';
}

On créé maintenant notre Listener, il n’y a rien de compliqué :

<?php
// App\EventSubscriber\RegistrationNotifySubscriber.php
namespace App\EventSubscriber;

use App\Entity\User;
use App\Events;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\EventDispatcher\GenericEvent;

/**
 * Envoi un mail de bienvenue à chaque creation d'un utilisateur
 *
 */
class RegistrationNotifySubscriber implements EventSubscriberInterface
{
    private $mailer;
    private $sender;

    public function __construct(\Swift_Mailer $mailer, $sender)
    {
        // On injecte notre expediteur et la classe pour envoyer des mails
        $this->mailer = $mailer;
        $this->sender = $sender;
    }

    public static function getSubscribedEvents(): array
    {
        return [
            // le nom de l'event et le nom de la fonction qui sera déclenché
            Events::USER_REGISTERED => 'onUserRegistrated',
        ];
    }

    public function onUserRegistrated(GenericEvent $event): void
    {
        /** @var User $user */
        $user = $event->getSubject();

        $subject = "Bienvenue";
        $body = "Bienvenue mon ami.e sur ce tutorial";

        $message = (new \Swift_Message())
            ->setSubject($subject)
            ->setTo($user->getEmail())
            ->setFrom($this->sender)
            ->setBody($body, 'text/html')
        ;

        $this->mailer->send($message);
    }
}

Et enfin on modifie notre Controller pour juste y ajouter le déclenchement de notre event :

<?php
// src/Controller/RegistrationController.php
namespace App\Controller;

use App\Form\UserType;
use App\Entity\User;
use App\Events;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;

class RegistrationController extends Controller
{
    /**
     * @Route("/register", name="user_registration")
     */
    public function registerAction(Request $request, UserPasswordEncoderInterface $passwordEncoder, EventDispatcherInterface $eventDispatcher)
    {
    
        $user = new User();
        $form = $this->createForm(UserType::class, $user);

        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {

            $password = $passwordEncoder->encodePassword($user, $user->getPassword());
            $user->setPassword($password);

            // Par defaut l'utilisateur aura toujours le rôle ROLE_USER
            $user->setRoles(['ROLE_USER']);

            // On enregistre l'utilisateur dans la base
            $em = $this->getDoctrine()->getManager();
            $em->persist($user);
            $em->flush();

            //On déclenche l'event
            $event = new GenericEvent($user);
            $eventDispatcher->dispatch(Events::USER_REGISTERED, $event);

            return $this->redirectToRoute('security_login');
        }

        return $this->render(
            'register.html.twig',
            array('form' => $form->createView())
        );
    }
}

and voilà !

Vous pouvez retrouver toutes les sources ici :

https://github.com/gponty/userDemo

14 commentaires

  1. Bonjour, j’ai essayer d’adapter votre méthode à mon site internet en construction et j’ai une erreur lorsque je lance le serveur :

    In RegisterControllerArgumentLocatorsPass.php line 159:

    Cannot determine controller argument for « App\Controller\RegistrationController::registerAction() »: the $eventDispatcher argument is type-hinted with the non-existent class or interface: « App\Controller\EventDispatcherInterface ».
    Did you forget to add a use statement?

    Cependant dans votre tutoriel il n’est pas question de créer un autre controller, pourriez vous m’éclairer

  2. mercii pour le tuto j’ai pas d’erreur mais ca ne send pas dans mon boite mail es ce je doit prendre ceci MAILER_URL=smtp://localhost:25?encryption=&auth_mode=

  3. Salut et merci pour les tutos !

    J’aimerais savoir comment faire pour simplement faire en sorte que le Password saisi lors de l’enregistrement qu’ils remplissent les conditions min-max length entre 8-15 caractères, 1Maj, 1Min et un caractères spécial ? J’ai beau chercher mais je ne trouve pas :/

    Merci !

  4. Bonjour,

    super tuto, tout fonctionne chez dans la mise en place.
    Il y a juste un loupé je pense : Dans le tuto 3, tu finis par
    « Dans le prochain chapitre nous verrons comment l’utilisateur peur modifier son mot de passe et le modifier si il l’a oublié. »

    Hors dans le chapitre 3.5 et 4 tu n’en parles pas.

    Est-ce prévu dans un chapitre 5 à venir ?

      1. Merci pour ta réponse 🙂
        Mais du coup les gens n’ont pas forcément le reflex de faire ca !
        C’est pas très grave, en le faisant sans l’event mais directement dans le controller ca marche !
        C’est pour savoir si il manquait un réglage :p

  5. Bonjour,

    J’ai également un erreur en suivant le tuto (avec Symfony 4.1.4) :

    Cannot autowire service « App\RegistrationNotifySubscriber\RegistrationNotifySubscriber »: argument « $sender » of method « __construct() » has no type
    -hint, you should configure its value explicitly.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.