IV. Les événements▲
Il y a plusieurs façons de programmer. En général la plus simple et la plus lisible consiste à procéder de façon séquentielle : on a une suite d'instructions (modulables par des conditions) qui sont toujours les mêmes. Le flux est facile à suivre.
Mais on a aussi l'approche événementielle. On va réagir à des événements susceptibles de se produire. On peut mettre ainsi en place un ensemble constitué par une partie qui détecte des événements et une autre qui les gère.
Laravel permet de gérer avec facilité les événements comme on va le voir dans ce chapitre.
IV-A. 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. Ça 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.
IV-B. 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 que l'on crée la première classe avec Artisan qui dispose de commandes pour le faire :
IV-B-1. Les événements déjà présents dans Laravel▲
Mais il n'y a pas que les événements que vous allez créer. Vous pouvez utiliser les événements existants déjà dans le framework qui en propose au niveau de l'authentification :
- tentative de connexion (login) ;
- connexion (login) réussie ;
- déconnexion (logout) réussie.
On trouve aussi des événements avec Eloquent :
- creating ;
- created ;
- updating ;
- updated ;
- saving ;
- saved ;
- deleting ;
- deleted ;
- restoring, restored.
Pour tous ces cas, vous n'avez donc pas à vous inquiéter de l'événement et du déclencheur qui existent déjà, il faudra juste mettre en place une écoute (Listener).
IV-B-2. Le fournisseur de service (service provider)▲
Il y a un fournisseur de service dédié aux événements :
Dans l'application d'exemple on a ce code :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
<?php
namespace
App\Providers;
use
Illuminate\Support\Facades\Event;
use
Illuminate\Foundation\Support\Providers\EventServiceProvider as
ServiceProvider;
class
EventServiceProvider extends
ServiceProvider
{
/**
* The event listener mappings for the application.
*
*
@var
array
*/
protected
$listen
=
[
'Illuminate\Auth\Events\Login'
=>
[
'App\Listeners\LoginSuccess'
],
'Illuminate\Auth\Events\Logout'
=>
[
'App\Listeners\LogoutSuccess'
],
'App\Events\UserAccess'
=>
[
'App\Listeners\UserAccess'
]
];
/**
* Register any events for your application.
*
*
@return
void
*/
public
function
boot()
{
parent
::
boot();
}
}
On a une propriété listen pour les abonnements. C'est un simple tableau qui prend l'événement (event) comme clé et l'observateur (listener) comme valeur.
On veut savoir quand quelqu'un se connecte ou se déconnecte. On prévoit donc des observateurs dans le provider :
2.
3.
4.
5.
protected $listen
=
[
'
Illuminate\Auth\Events\Login
'
=>
[
'
App\Listeners\LoginSuccess
'
],
'
Illuminate\Auth\Events\Logout
'
=>
[
'
App\Listeners\LogoutSuccess
'
],
...
];
Vous pouvez trouver ces événements dans la documentation.
Laravel prévoit de placer les observateurs (listeners) dans ce dossier en tant que classes :
IV-C. Le statut de l'utilisateur dans l'application▲
Pour simplifier la gestion le statut de l'utilisateur (son rôle) est enregistré dans la session. On a trois rôles :
- Administrateur (admin) : avec tous les droits ;
- Rédacteur (redac) : avec le droit de gérer des articles ;
- Utilisateur (user) : avec juste le droit de laisser des commentaires.
Et on ajoute visitor pour un utilisateur non connecté.
IV-C-1. La connexion▲
Donc dès que quelqu'un se connecte on doit regarder son rôle et le mémoriser dans la session.
Si on regarde l'observateur (listener) :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
<?php
namespace
App\Listeners;
use
Illuminate\Auth\Events\Login;
use
App\Services\Statut;
class
LoginSuccess
{
/**
* Handle the event.
*
*
@param
Login
$login
*
@return
void
*/
public
function
handle(Login $login
)
{
Statut::
setLoginStatut($login
);
}
}
On fait appel à un service avec une méthode statique :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
<?php
namespace
App\Services;
class
Statut
{
/**
* Set the login user statut
*
*
@param
Illuminate\Auth\Events\Login
$login
*
@return
void
*/
public
static
function
setLoginStatut($login
)
{
session([
'statut'
=>
$login
->
user->
getStatut()]
);
}
...
}
Il faut aller voir dans le modèle App\Models\User pour trouver la méthode :
On passe par la relation entre les utilisateurs et les rôles pour aller chercher l'information à mettre dans la session.
IV-C-2. La deconnexion▲
Et évidemment en cas de déconnexion c'est le même processus avec le listener LogoutSuccess :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
<?php
namespace
App\Listeners;
use
Illuminate\Auth\Events\Logout;
use
App\Services\Statut;
class
LogoutSuccess
{
/**
* Handle the event.
*
*
@param
Logout
$event
*
@return
void
*/
public
function
handle(Logout $event
)
{
Statut::
setVisitorStatut();
}
}
On utilise encore le service :
IV-C-3. Accès à une page▲
Il faut considérer un dernier cas : lorsque l'utilisateur accède à une page on va vérifier s'il y a un statut mémorisé en session et si ce n'est pas le cas, en créer un.
Cette fois ce n'est pas un événement qui existe comme login ou logout, il nous faut donc le créer.
On a donc cette fois une classe Event :
Avec ce code :
2.
3.
4.
5.
6.
7.
8.
<?php
namespace
App\Events;
class
UserAccess extends
Event
{
//
}
Oui il n'y a que la classe parce que l'on a rien de particulier à transmettre dans ce cas.
On doit donc déclencher cet événement quand un utilisateur accède à une page.
On va donc passer par un middleware. Regardez dans la classe App\Http\Middleware\App :
On utilise l'helper event pour déclencher l'événement. Sans l'helper il faudrait utiliser la façade :
Event::
fire(new UserAccess);
Au niveau de l'inscription on a vu que l'on a ceci :
2.
3.
4.
protected $listen
=
[
...
'
App\Event\UserAccess
'
=>
[
'
App\Listeners\UserAccess
'
]
];
Voici le code du listener :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
<?php
namespace
App\Listeners;
use
App\Events\UserAccess as
UserAccessEvent;
use
App\Services\Statut;
use
App\Services\Locale;
class
UserAccess
{
/**
* Handle the event.
*
*
@param
UserAccess
$event
*
@return
void
*/
public
function
handle(UserAccessEvent $event
)
{
Statut::
setStatut();
Locale::
setLocale();
}
}
On appelle encore la méthode dans le service :
On a la logique ici : si on n'a pas de statut dans la session on regarde si l'utilisateur est connecté, si c'est le cas on va chercher son statut, sinon on lui affecte le statut visitor.
Remarquez aussi dans le listener la gestion de la locale que l'on a vue dans un précédent chapitre.
Pour avoir la documentation complète sur ce sujet c'est dans la documentation.
La programmation événementielle en PHP est un certain style de programmation. Elle n'a rien d'obligatoire parce que l'on peut toujours s'en passer si on préfère coder de façon plus classique. Mais il y a de nombreuses situations où elle présente un intérêt certain, en particulier quand un événement possède plusieurs observateurs indépendants les uns des autres. D'autre part Laravel offre des événements précodés, comme on l'a vu dans ce chapitre, qu'il serait dommage de ne pas utiliser.
IV-D. En résumé▲
- Laravel comporte un système complet et simple de gestion des événements.
- Laravel comporte déjà des événements pour l'authentification et la gestion des données avec Eloquent.
- On doit créer une classe Event et une classe Listener pour mettre en place une gestion événementielle et ensuite définir un déclencheur.