Créer un event listener dans Laravel

Dans ce tutoriel, nous allons voir comment créer un event listener aussi appelé écouteur d’événements en français dans mon framework préféré, Laravel. Si comme moi, vous avez plusieurs commandes qui se lancent automatiquement avec cron, vous voulez peut-être savoir ce qu’il se passe plus précisément dans votre application Laravel. Vous pouvez bien sûr utiliser les journaux de logs personnalisés, mais aujourd’hui, on va donc s’intéresser au concept d’event listener. Le framework nous fournit des outils pour le faire facilement donc autant s’en servir et garder une application avec du code propre et lisible.

Tout d’abord, c’est quoi un event listener ? Dans Laravel, un écouteur d’événement est un composant qui s’occupe de répondre à divers événements qui se produisent au sein de votre application. Un événement peut être déclenché par différentes actions comme la fin d’une requête HTTP, la réalisation d’une tâche en arrière-plan, ou même des actions personnalisées que vous définissez dans votre application. Les écouteurs d’événements permettent de décomposer votre application en parties réactives, ce qui facilite la gestion et la maintenance du code.

La liste des écouteurs d’événements dans Laravel

Laravel propose donc une série d’événements intégrés que vous pouvez utiliser pour déclencher des écouteurs d’événements spécifiques dans votre application. Cependant, il est important de noter que la liste exacte des événements disponibles peut varier en fonction de la version de Laravel que vous utilisez. Il faudra donc vérifier sur la documentation de Laravel si vous ne trouvez pas votre bonheur ici. Voici une liste générale des types d’événements couramment disponibles dans Laravel :

  1. Événements liés aux Requêtes HTTP :
    • Illuminate\Foundation\Http\Events\RequestHandled : déclenché après qu’une requête HTTP a été traitée.
    • Illuminate\Routing\Events\RouteMatched : déclenché lorsque une route est mise en correspondance.
  2. Événements d’Authentification :
    • Illuminate\Auth\Events\Registered : lorsqu’un nouvel utilisateur s’inscrit.
    • Illuminate\Auth\Events\Attempting : lors d’une tentative de connexion.
    • Illuminate\Auth\Events\Authenticated : après qu’un utilisateur a été authentifié.
    • Illuminate\Auth\Events\Login : après la connexion d’un utilisateur.
    • Illuminate\Auth\Events\Failed : après une tentative de connexion échouée.
    • Illuminate\Auth\Events\Logout : lorsqu’un utilisateur se déconnecte.
    • Illuminate\Auth\Events\Lockout : lorsqu’un utilisateur est verrouillé après plusieurs tentatives de connexion échouées.
  3. Événements liés aux Bases de Données :
    • Illuminate\Database\Events\QueryExecuted : après l’exécution d’une requête SQL.
    • Illuminate\Database\Events\TransactionBeginning : lorsqu’une transaction de base de données commence.
    • Illuminate\Database\Events\TransactionCommitted : après l’engagement d’une transaction.
    • Illuminate\Database\Events\TransactionRolledBack : après l’annulation d’une transaction.
  4. Événements liés à la Mise en File d’attente (Queue) :
    • Illuminate\Queue\Events\JobProcessed : après qu’un job de file d’attente a été traité.
    • Illuminate\Queue\Events\JobFailed : lorsqu’un job de file d’attente échoue.
    • Illuminate\Queue\Events\JobProcessing : lorsqu’un job de file d’attente commence son traitement.
  5. Événements liés aux Mail :
    • Illuminate\Mail\Events\MessageSending : avant l’envoi d’un e-mail.
    • Illuminate\Mail\Events\MessageSent : après l’envoi d’un e-mail.
  6. Événements liés aux Notifications :
    • Illuminate\Notifications\Events\NotificationSending : avant l’envoi d’une notification.
    • Illuminate\Notifications\Events\NotificationSent : après l’envoi d’une notification.
  7. Événements liés aux Broadcasts (Diffusion) :
    • Illuminate\Broadcasting\Events\BroadcastEvent : lorsqu’un événement est diffusé.
  8. Événements de Commandes Artisan :
    • Illuminate\Console\Events\CommandStarting : avant le démarrage d’une commande Artisan.
    • Illuminate\Console\Events\CommandFinished : après la fin d’une commande Artisan.
  9. Événements Divers :
    • Illuminate\Cache\Events\CacheHit : lorsqu’un élément est récupéré du cache.
    • Illuminate\Cache\Events\CacheMissed : lorsqu’un élément n’est pas trouvé dans le cache.
    • Illuminate\Cache\Events\KeyWritten : après qu’un élément a été écrit dans le cache.
    • Illuminate\Cache\Events\KeyForgotten : après qu’un élément a été supprimé du cache.

Cela vous donne une idée de ce qu’il est possible de faire de manière une peu globale avec les événements dans Laravel.

Création d’un event listener pour savoir quand une commande console se termine

Il est temps de passer aux choses sérieuses et on va voir comment créer un event listener qui va nous permettre d’enregistrer dans la base de données le nom de la commande et l’heure à laquelle elle s’est terminée. Pour cela, on va dans un premier temps créer une migration pour stocker ces informations. Tapez la commande suivante dans votre projet Laravel :

php artisan make:migration create_command_logs_table

Dans cette migration create_command_logs_table on va ajouter le code suivant pour créer la table et les colonnes pour avoir tout ce qu’il faut :

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('command_logs', function (Blueprint $table) {
            $table->id();
            $table->string('command_name');
            $table->dateTime('finished_at');
            $table->timestamps();
        });        
    }
    
    public function down(): void
    {
        Schema::dropIfExists('command_logs');
    }
};

Pour que notre application Laravel reste cohérente et propre, je vais créer un petit modèle correspondant à cette table qui va nous simplifier la vie. Pour ce faire, je lance la commande suivante :

php artisan make:model CommandLog

Dans ce nouveau modèle CommandLog, je vais insérer le contenu suivant pour qu’il fonctionne bien avec notre nouvelle table command_logs :

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class CommandLog extends Model
{
    use HasFactory;

    protected $fillable = [
        'command_name', 'finished_at',
    ];
}

Dans le modèle, définissez les propriétés fillable pour command_name et finished_at pour permettre la masse affectation. On maintenant à la création de notre événement que l’on va appeler LogCommandFinished. Comme d’habitude, on lance la commande Laravel qui va bien :

php artisan make:listener LogCommandFinished --event=CommandFinished

Vous allez avoir un nouveau fichier avec le chemin app/Listeners/LogCommandFinished.php. Dans la classe de l’écouteur, implémentez la méthode handle() pour qu’elle crée une entrée dans CommandLog chaque fois qu’une commande est terminée. N’oubliez pas d’importer votre modèle. Mon fichier LogCommandFinished ressemble alors à quelque chose comme ça :

<?php
namespace App\Listeners;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

use App\Models\CommandLog;
use Illuminate\Console\Events\CommandFinished;

class LogCommandFinished
{
    public function __construct()
    {
        //
    }

    public function handle(CommandFinished $event)
    {
        CommandLog::create([
            'command_name' => $event->command,
            'finished_at' => now(),
        ]);
    }
}

Il ne reste plus qu’une dernière étape pour que tout fonctionne bien, enregistrer l’écouteur d’événement pour qu’il s’execute bien. Ouvrez le fichier EventServiceProvider.php qui se trouve très exactement à cet endroit : app/Providers/EventServiceProvider.php. Ajoutez l’écouteur LogCommandFinished à la liste des écouteurs pour l’événement Illuminate\Console\Events\CommandFinished. Cela indique à Laravel de déclencher l’écouteur LogCommandFinished chaque fois qu’une commande console se termine. Voici le contenu ce fichier après ma modification pour que vous puissiez modifier correctement selon vos besoins.

<?php
namespace App\Providers;

use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
        'Illuminate\Console\Events\CommandFinished' => [
            'App\Listeners\LogCommandFinished',
        ],
    ];

    public function boot(): void
    {
        //
    }

    public function shouldDiscoverEvents(): bool
    {
        return false;
    }
}

Vous savez maintenant créer un écouteur d’événement ou event listener dans le framework Laravel. C’est vraiment très complet et cela permet de facilement faire beaucoup de choses avec très peu de lignes de code supplémentaire. Amusez-vous bien et n’arrêtez jamais d’apprendre !

Laisser un commentaire