Passer au contenu principal

Qu’est-ce qu’un événement

Le système d’événements de Laravel implémente le pattern observateur. Vous déclenchez des « événements » représentant des faits survenus dans l’application, et des listeners y réagissent, ce qui minimise les dépendances entre composants. Par exemple, un événement « commande validée » peut déclencher indépendamment « envoyer l’e-mail de confirmation », « décrémenter le stock » et « notifier Slack ». Le code de la commande ignore complètement l’implémentation de l’envoi de mails ou de Slack.
Les classes d’événement vont dans app/Events, les listeners dans app/Listeners. Ces dossiers sont créés automatiquement par les commandes Artisan.

Générer événements et listeners

Utilisez make:event et make:listener.
php artisan make:event UserRegistered

php artisan make:listener SendWelcomeEmail --event=UserRegistered
Sans arguments, la commande est interactive.
php artisan make:event

php artisan make:listener

Enregistrement des listeners

Auto-discovery

Par défaut, Laravel scanne app/Listeners et enregistre les listeners. La classe/méthode handle ou __invoke est inspectée : le type de son argument détermine l’événement écouté.
use App\Events\UserRegistered;

class SendWelcomeEmail
{
    public function handle(UserRegistered $event): void
    {
        // Envoi de l'e-mail de bienvenue
    }
}
Un type union PHP permet de gérer plusieurs événements dans la même méthode.
public function handle(UserRegistered|UserUpdated $event): void
{
    // ...
}
Pour des listeners hors de ce dossier, ajoutez des chemins de scan dans bootstrap/app.php.
->withEvents(discover: [
    __DIR__.'/../app/Domain/Orders/Listeners',
])
Wildcards autorisés :
->withEvents(discover: [
    __DIR__.'/../app/Domain/*/Listeners',
])
Liste des listeners enregistrés :
php artisan event:list
En production, mettez le manifest en cache : php artisan optimize ou php artisan event:cache. Videz-le avec php artisan event:clear.

Enregistrement manuel

Via Event dans AppServiceProvider::boot.
use App\Events\UserRegistered;
use App\Listeners\SendWelcomeEmail;
use Illuminate\Support\Facades\Event;

public function boot(): void
{
    Event::listen(
        UserRegistered::class,
        SendWelcomeEmail::class,
    );
}
Ou via closure.
use App\Events\UserRegistered;
use Illuminate\Support\Facades\Event;

public function boot(): void
{
    Event::listen(function (UserRegistered $event) {
        // ...
    });
}

Définir un événement

Une classe d’événement n’est qu’un conteneur de données. Elle porte les informations liées à l’événement, sans logique.
<?php

namespace App\Events;

use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class UserRegistered
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(
        public User $user,
    ) {}
}
Le trait SerializesModels garantit une bonne sérialisation des modèles Eloquent quand le listener est en file.

Déclencher un événement

Utilisez la méthode statique dispatch ou le helper event().
use App\Events\UserRegistered;

// Statique
UserRegistered::dispatch($user);

// Helper
event(new UserRegistered($user));
Il existe aussi les variantes conditionnelles.
UserRegistered::dispatchIf($condition, $user);

UserRegistered::dispatchUnless($condition, $user);

Après la commit d’une transaction

Pour ne dispatcher qu’après commit d’une transaction, implémentez ShouldDispatchAfterCommit. En cas de rollback, l’événement est ignoré.
<?php

namespace App\Events;

use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class UserRegistered implements ShouldDispatchAfterCommit
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(
        public User $user,
    ) {}
}

Implémenter un listener

La méthode handle reçoit l’événement. Le constructeur peut recevoir des dépendances via le conteneur.
<?php

namespace App\Listeners;

use App\Events\UserRegistered;
use App\Mail\WelcomeMail;
use Illuminate\Support\Facades\Mail;

class SendWelcomeEmail
{
    public function __construct() {}

    public function handle(UserRegistered $event): void
    {
        Mail::to($event->user->email)
            ->send(new WelcomeMail($event->user));
    }
}
Retourner false depuis handle interrompt la propagation aux listeners suivants.

Listeners en file (queued)

Pour les traitements longs (mail, HTTP…), exécutez le listener en asynchrone. Implémentez ShouldQueue : Laravel enfile automatiquement le listener lors du dispatch.
<?php

namespace App\Listeners;

use App\Events\UserRegistered;
use Illuminate\Contracts\Queue\ShouldQueue;

class SendWelcomeEmail implements ShouldQueue
{
    public function handle(UserRegistered $event): void
    {
        // Exécuté en asynchrone par le worker
    }
}
Nécessite la configuration de la queue et le démarrage d’un worker. Voir Queues et jobs.

Personnaliser connexion, queue et délai

Utilisez les attributs PHP.
<?php

namespace App\Listeners;

use App\Events\UserRegistered;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\Attributes\Connection;
use Illuminate\Queue\Attributes\Delay;
use Illuminate\Queue\Attributes\Queue;

#[Connection('redis')]
#[Queue('emails')]
#[Delay(10)]
class SendWelcomeEmail implements ShouldQueue
{
    public function handle(UserRegistered $event): void
    {
        // ...
    }
}
Ou via des méthodes dynamiques.
public function viaConnection(): string
{
    return 'redis';
}

public function viaQueue(): string
{
    return 'emails';
}

public function withDelay(UserRegistered $event): int
{
    return 10;
}

Nombre max d’essais et timeout

use Illuminate\Queue\Attributes\Tries;
use Illuminate\Queue\Attributes\Timeout;

#[Tries(3)]
#[Timeout(30)]
class SendWelcomeEmail implements ShouldQueue
{
    // ...
}

Gestion des échecs

La méthode failed est appelée après épuisement des tentatives.
use Throwable;

public function failed(UserRegistered $event, Throwable $exception): void
{
    // Notifier un administrateur, par exemple
}

Souscripteurs d’événements

Un souscripteur regroupe plusieurs handlers dans une même classe.

Créer un souscripteur

subscribe renvoie la table événement → handler.
<?php

namespace App\Listeners;

use Illuminate\Auth\Events\Login;
use Illuminate\Auth\Events\Logout;
use Illuminate\Events\Dispatcher;

class UserActivitySubscriber
{
    public function handleLogin(Login $event): void
    {
        // Login
    }

    public function handleLogout(Logout $event): void
    {
        // Logout
    }

    /**
     * @return array<string, string>
     */
    public function subscribe(Dispatcher $events): array
    {
        return [
            Login::class => 'handleLogin',
            Logout::class => 'handleLogout',
        ];
    }
}

Enregistrement

Avec l’auto-discovery, les souscripteurs retournant un tableau sont enregistrés automatiquement. Sinon, dans AppServiceProvider::boot, appelez Event::subscribe.
use App\Listeners\UserActivitySubscriber;
use Illuminate\Support\Facades\Event;

public function boot(): void
{
    Event::subscribe(UserActivitySubscriber::class);
}

Exemple : e-mail de bienvenue à l’inscription

1

Créer l'événement

php artisan make:event UserRegistered
Ajoutez une propriété pour l’utilisateur.
<?php

namespace App\Events;

use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class UserRegistered
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(
        public User $user,
    ) {}
}
2

Créer le listener

php artisan make:listener SendWelcomeEmail --event=UserRegistered
Implémentez ShouldQueue pour un envoi asynchrone.
<?php

namespace App\Listeners;

use App\Events\UserRegistered;
use App\Mail\WelcomeMail;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Mail;

class SendWelcomeEmail implements ShouldQueue
{
    public function handle(UserRegistered $event): void
    {
        Mail::to($event->user->email)
            ->send(new WelcomeMail($event->user));
    }
}
3

Dispatcher l'événement depuis le contrôleur

Après la création de l’utilisateur.
<?php

namespace App\Http\Controllers\Auth;

use App\Events\UserRegistered;
use App\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

class RegisterController extends Controller
{
    public function store(Request $request): RedirectResponse
    {
        $user = User::create($request->validated());

        UserRegistered::dispatch($user);

        return redirect('/dashboard');
    }
}
RegisterController ignore l’implémentation de l’envoi de mail. Ajouter plus tard un « notifier Slack » ne modifie pas le contrôleur.
4

Démarrer un worker

Pour traiter les listeners en file.
php artisan queue:work
Avec l’auto-discovery, aucun enregistrement manuel n’est requis dans AppServiceProvider.
Vérifiez régulièrement php artisan event:list pour détecter d’éventuels listeners inattendus.
Dernière modification le 13 juillet 2026