
Il existe plusieurs approches en programmation, chacune ayant ses avantages et ses cas d'utilisation spécifiques.
L'approche la plus simple et souvent la plus lisible est la programmation séquentielle. Dans ce modèle, une série d'instructions est exécutée de manière linéaire et prédéfinie, avec des conditions qui peuvent moduler le flux d'exécution. Cette méthode est facile à suivre et à comprendre, car chaque étape suit logiquement la précédente.
Une autre approche importante est le paradigme événementiel. Contrairement à la programmation séquentielle, les applications événementielles réagissent à des événements qui peuvent survenir à tout moment. Ce type de programmation permet de dissocier la détection des événements de leur traitement, ce qui conduit à une architecture plus claire et mieux organisée.
Laravel simplifie la gestion des événements tout en offrant une structure robuste pour développer des applications web performantes. Dans ce chapitre, nous explorerons comment Laravel facilite la gestion des événements en examinant les concepts, les outils et les meilleures pratiques associés à cette approche. Nous illustrerons ces concepts avec des exemples pratiques pour vous aider à implémenter efficacement des événements dans vos propres applications Laravel.
Le design pattern Observateur
Le design pattern Observateur (observer) établit une relation de type 1:n entre des objets. Si l’objet côté 1 change d’état, il en informe les objets côté n pour qu’ils puissent agir en conséquence. Cela implique une intendance et les objets doivent pouvoir s’inscrire et se mettre à l’écoute des événements du sujet.
Voici une visualisation de ce design pattern :
On a un sujet et des observateurs. Les observateurs doivent s’inscrire (on dit aussi s’abonner) auprès du sujet. Lorsque le sujet change d’état, il notifie tous ses abonnés. Un observateur peut aussi se désinscrire, il ne recevra alors plus les notifications.
Vous pouvez trouver une description détaillée de ce design pattern ici.
Organisation du code
Laravel implémente ce design pattern et le rend très simple d’utilisation. On va avoir :
- des classes Event placées dans le dossier app/Events :
- des classes Listener placées dans le dossier app/Listeners :
Ces dossiers n’existent pas dans l’installation de base, ils sont ajoutés dès qu’on crée la première classe avec Artisan qui dispose de commandes pour le faire :
Les événements déjà présents dans Laravel
Événements d'Authentification
- Registered : Utilisateur enregistré avec succès.
- CurrentDeviceLogout : Déconnexion de l'appareil actuel.
- OtherDeviceLogout : Déconnexion d'un autre appareil.
- Attempting : Tentative de connexion en cours.
- Authenticated : Authentification réussie.
- Login : Connexion réussie.
- Failed : Échec de la connexion.
- Logout : Déconnexion réussie.
- Lockout : Compte verrouillé (peut-être à cause de tentatives de connexion échouées).
- PasswordReset : Réinitialisation du mot de passe.
- Validated : Validation réussie (peut-être des données d'entrée).
- Verified : Vérification réussie (peut-être de l'adresse e-mail).
- ...
Événements Eloquent (ORM)
- retrieved : Modèle récupéré de la base de données.
- creating : Avant la création d'un modèle.
- created : Après la création d'un modèle.
- updating : Avant la mise à jour d'un modèle.
- updated : Après la mise à jour d'un modèle.
- saving : Avant la sauvegarde d'un modèle (création ou mise à jour).
- saved : Après la sauvegarde d'un modèle.
- deleting : Avant la suppression d'un modèle.
- deleted : Après la suppression d'un modèle.
- restoring : Avant la restauration d'un modèle supprimé.
- restored : Après la restauration d'un modèle supprimé.
- ...
Pour tous ces cas, vous n’avez donc pas à vous inquiéter du déclencheur qui existe déjà.
Une application de test
Pour nos essais, il nous faut une application Laravel 12 avec l'authentification présente. Si vous ne savez plus comment faire, vous pouvez retrouver voir l'article concernant l'authentification.
On crée une écoute
On va utiliser l'événement intégré à Laravel qui se déclenche lorsqu'un utilisateur se connecte. La classe correspondante est Illuminate\Auth\Events\Login. Puisque l'événement existe, on n'a pas à créer une classe Event. Par contre, il nous faut une écoute (Listener) :
php artisan make:listener UserLogin --event=Illuminate\Auth\Events\Login
On a bien précisé l'événement déclencheur. La classe UserLogin se crée ainsi que le dossier : Voici le code généré :
<?php
namespace App\Listeners;
use Illuminate\Auth\Events\Login;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class UserLogin
{
/**
* Create the event listener.
*/
public function __construct()
{
//
}
/**
* Handle the event.
*/
public function handle(Login $event): void
{
//
}
}
Donc maintenant, dès qu'un utilisateur va se connecter, la méthode handle de notre écoute va être appelée. Mais qu'y a-t-il dans la variable $event ? On va faire un petit test :
public function handle(object $event): void
{
dd($event);
}
Là, dès qu'on se connecte, on obtient :
Illuminate\Auth\Events\Login {#399 ▼
+guard: "web"
+user: App\Models\User {#1370 ▶}
+remember: false
}
Une instance de la classe Illuminate/Auth/Events/Login avec plusieurs propriétés, en particulier une instance du modèle de l'utilisateur et un booléen pour le remember. On aurait aussi pu trouver ces informations en allant voir directement la classe.
Changez ainsi le code :
public function handle(object $event): void
{
dd($event->user->name . " s'est connecté.");
}
Cette fois, à la connexion, on obtient quelque chose dans ce genre :
"Durand s'est connecté."
On peut donc ici effectuer tous les traitements qu'on veut, comme comptabiliser les connexions.
On crée un événement
À présent, on va créer un événement et aussi son écoute. On va imaginer qu'on veut savoir quand quelqu'un affiche la page d'accueil et mémoriser son IP ainsi que le moment du chargement de la page, en gros un peu de statistiques.
On commence par créer une migration :
php artisan make:migration create_visits_table --create=visits
Avec ces créations de colonnes :
public function up(): void
{
Schema::create('visits', function (Blueprint $table) {
$table->id();
$table->string('ip', 45);
$table->timestamp('created_at');
});
}
Et on lance la migration :
php artisan migrate
On crée l'événement :
php artisan make:event Accueil
On le trouve ici avec création du dossier :
Avec ce code par défaut :
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class Accueil
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*/
public function __construct()
{
//
}
/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new PrivateChannel('channel-name'),
];
}
}
On ne va pas toucher à ce code. On crée aussi l'écoute :
php artisan make:listener Accueil --event=Accueil
Comme on a un conflit de nommage, on va changer le code et le compléter :
<?php
namespace App\Listeners;
use App\Events\Accueil as AcceuilEvent;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
class Accueil
{
/**
* Create the event listener.
*/
public function __construct()
{
//
}
/**
* Handle the event.
*/
public function handle(AcceuilEvent $event): void
{
DB::table('visits')->insert([
'ip' => request()->ip(),
'created_at' => Carbon::now(),
]);
}
}
J'utilise directement le Query Builder sans passer par Eloquent. Il ne reste plus qu'à déclencher cet événement dans la route :
use App\Events\Accueil;
Route::get('/', function () {
event(new Accueil);
return view('welcome');
})->name('home');
Maintenant, chaque fois que la page d'accueil est ouverte, l'événement Accueil est déclenché et donc l'écoute Accueil en est informée. On sauvegarde alors dans la base l'IP et le moment du chargement dans la table visits.
Si le traitement de vos événements est long (envoie d'email, requête...), il est conseillé d'utiliser un système de file d'attente. Vous pouvez consulter la documentation correspondante.
Si vous utilisez SQLite, et que vous n'avez pas d'outil pour aller lire les informations, vous pouvez utiliser tinker :
php artisan tinker
Et ensuite l'utiliser pour lire les données de la table visits :
Ce tinker est un REPL bien pratique.
En résumé
- Laravel permet d'utiliser la programmation événementielle.
- Laravel comporte des événements préexistants au niveau de l'authentification et d'Eloquent.
- On peut créer des événements (Events) et des écoutes (Listeners) et les mettre en relation automatiquement.
Par bestmomo
Aucun commentaire