Maison > développement back-end > tutoriel php > Un guide pour les événements modèles de Laravel

Un guide pour les événements modèles de Laravel

James Robert Taylor
Libérer: 2025-03-06 02:25:14
original
859 Les gens l'ont consulté

A guide to Laravel's model events

Les événements du modèle de Laravel sont une fonctionnalité très pratique qui vous aide à exécuter automatiquement la logique lors de l'exécution de certaines opérations sur votre modèle éloquent. Cependant, s'ils sont utilisés mal, cela peut parfois conduire à d'étranges effets secondaires.

Cet article explorera ce que sont les événements de modèle et comment les utiliser dans les applications Laravel. Nous explorerons également comment tester les événements du modèle et certains problèmes à connaître lors de leur utilisation. Enfin, nous couvrirons certaines alternatives aux événements modèles que vous pouvez envisager d'utiliser.

Que sont les événements et les auditeurs?


Vous avez peut-être entendu parler des "événements" et des "auditeurs". Mais si vous n'en avez pas entendu parler, en voici un bref aperçu de ces éléments:

#Event

C'est ce qui se passe dans les applications sur lesquelles vous souhaitez agir - par exemple, les utilisateurs s'inscrivent sur votre site Web, les utilisateurs se connectent, etc.

Habituellement, dans Laravel, les événements sont des classes PHP. En plus des événements fournis par des cadres ou des packages tiers, ils sont généralement enregistrés dans le répertoire app/Events.

Ce qui suit est un exemple de classe d'événements simples que vous souhaiterez peut-être planifier lorsqu'un utilisateur s'inscrit sur votre site Web:

declare(strict_types=1);

namespace App\Events;

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

final class UserRegistered
{
    use Dispatchable;
    use InteractsWithSockets;
    use SerializesModels;

    public function __construct(public User $user)
    {
        //
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans l'exemple de base ci-dessus, nous avons une classe d'événements AppEventsUserRegistered qui accepte une instance de modèle User dans son constructeur. Cette classe d'événements est un conteneur simple pour enregistrer les instances utilisateur enregistrées.

Lorsqu'il est expédié, l'événement déclenche tout auditeur qui l'écoute.

Ce qui suit est un exemple simple de la façon de planifier l'événement lorsqu'un utilisateur enregistre:

use App\Events\UserRegistered;
use App\Models\User;

$user = User::create([
    'name' => 'Eric Barnes',
    'email' => 'eric@example.com',
]);

UserRegistered::dispatch($user);
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Dans l'exemple ci-dessus, nous créons un nouvel utilisateur, puis planifions l'événement

à l'aide de l'instance utilisateur. En supposant que l'auditeur est enregistré correctement, cela déclenchera tout écouteur qui écoute sur l'événement AppEventsUserRegistered. AppEventsUserRegistered

#Listener

Les écouteurs sont des blocs de code que vous souhaitez exécuter lorsqu'un événement spécifique se produit.

Par exemple, respectez notre exemple d'enregistrement de l'utilisateur, vous pouvez envoyer un e-mail de bienvenue à l'utilisateur lorsque l'utilisateur enregistre. Vous pouvez créer un auditeur de l'événement

et envoyer un e-mail de bienvenue. AppEventsUserRegistered

Dans Laravel, les auditeurs sont généralement (mais pas toujours) des classes trouvées dans le répertoire

. app/Listeners

Exemple d'auditeur envoyant un e-mail de bienvenue à un utilisateur lorsqu'un utilisateur enregistre peut ressembler à ceci:

declare(strict_types=1);

namespace App\Listeners;

use App\Events\UserRegistered;
use App\Notifications\WelcomeNotification;
use Illuminate\Support\Facades\Mail;

final readonly class SendWelcomeEmail
{
    public function handle(UserRegistered $event): void
    {
        $event->user->notify(new WelcomeNotification());
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Comme nous l'avons vu dans l'exemple de code ci-dessus, la classe d'écoute

a une méthode AppListenersSendWelcomeEmail qui accepte une instance d'événement handle. Cette méthode est responsable de l'envoi d'un e-mail de bienvenue à l'utilisateur. AppEventsUserRegistered

Pour des instructions plus approfondies sur les événements et les auditeurs, vous souhaiterez peut-être consulter la documentation officielle: https://www.php.cn/link/d9a8c56824cfbe66f28f85edbbe83e09

Qu'est-ce qu'un événement modèle?


Dans votre application Laravel, vous devez généralement planifier manuellement les événements lorsque certaines actions se produisent. Comme nous l'avons vu dans l'exemple ci-dessus, nous pouvons planifier des événements en utilisant le code suivant:

declare(strict_types=1);

namespace App\Events;

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

final class UserRegistered
{
    use Dispatchable;
    use InteractsWithSockets;
    use SerializesModels;

    public function __construct(public User $user)
    {
        //
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Cependant, lorsque vous utilisez le modèle éloquent dans Laravel, certains événements nous sont automatiquement programmés, nous n'avons donc pas besoin de les planifier manuellement. Si nous voulons effectuer des opérations lorsque des événements se produisent, nous avons juste besoin de définir des auditeurs pour eux.

La liste suivante montre des événements et des déclencheurs planifiés automatiquement par le modèle éloquent:

  • récupéré - Récupérez dans la base de données.
  • Création - Création d'un modèle.
  • Créé - Le modèle a été créé.
  • Mise à jour - mise à jour du modèle.
  • Mise à jour - Le modèle a été mis à jour.
  • Enregistrement - Création ou mise à jour d'un modèle.
  • enregistré - Le modèle a été créé ou mis à jour.
  • Suppression - Suppression du modèle.
  • supprimé - Le modèle a été supprimé.
  • Trashed - Le modèle a été doucement supprimé.
  • Forcélétisme - suppression forcée du modèle.
  • Forcedeleted - Le modèle a été forcé d'être supprimé
  • Restauration - Récupération du modèle à partir de délétion douce.
  • Restauré - Le modèle a été récupéré d'une suppression douce.
  • reproduisant - reproduisant le modèle.

Dans la liste ci-dessus, vous remarquez peut-être certains noms d'événements similaires; par exemple, creating et created. Les événements se terminant par ing sont exécutés avant que l'opération ne se produise, et les modifications sont persistées dans la base de données. Les événements se terminant par ed sont exécutés après l'opération, et les modifications sont persistées dans la base de données.

Voyons comment utiliser ces événements de modèle dans une application Laravel.

Utiliser dispatchesEvents Écoutez les événements du modèle


Une façon d'écouter les événements du modèle est de définir une propriété dispatchesEvents sur votre modèle.

Cette propriété vous permet de cartographier les événements de modèle éloquents à la classe d'événements qui devrait être planifiée lorsque l'événement se produit. Cela signifie que vous pouvez définir l'auditeur tout comme vous géreriez tout autre événement.

pour fournir plus de contexte, regardons un exemple.

Supposons que nous créons une application de blog avec deux modèles: AppModelsPost et AppModelsAuthor. Nous dirons que les deux modèles prennent en charge la suppression douce. Lorsque nous enregistrons un nouveau AppModelsPost, nous voulons calculer le temps de lecture de l'article en fonction de la longueur du contenu. Lorsque nous supprimons doucement l'auteur, nous voulons que l'auteur supprime doucement tous les articles.

#Set le modèle

Nous pouvons avoir un modèle AppModelsAuthor comme indiqué ci-dessous:

use App\Events\UserRegistered;
use App\Models\User;

$user = User::create([
    'name' => 'Eric Barnes',
    'email' => 'eric@example.com',
]);

UserRegistered::dispatch($user);
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans le modèle ci-dessus, nous avons:

  • Ajout d'une propriété dispatchesEvents qui mappe l'événement de modèle deleted à la classe d'événements AppEventsAuthorDeleted. Cela signifie que lorsque le modèle est supprimé, un nouvel événement AppEventsAuthorDeleted sera planifié. Nous créerons cette classe d'événements plus tard.
  • définit une relation posts.
  • La suppression douce est activée sur le modèle en utilisant la fonction IlluminateDatabaseEloquentSoftDeletes.

Créons notre modèle AppModelsPost:

declare(strict_types=1);

namespace App\Events;

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

final class UserRegistered
{
    use Dispatchable;
    use InteractsWithSockets;
    use SerializesModels;

    public function __construct(public User $user)
    {
        //
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans le modèle ci-dessus AppModelsPost, nous avons:

  • Ajout d'une propriété dispatchesEvents qui mappe l'événement de modèle saving à la classe d'événements AppEventsPostSaving. Cela signifie que lorsque le modèle est créé ou mis à jour, un nouvel événement AppEventsPostSaving sera planifié. Nous créerons cette classe d'événements plus tard.
  • définit une relation author.
  • La suppression douce est activée sur le modèle en utilisant la fonction IlluminateDatabaseEloquentSoftDeletes.

Notre modèle est maintenant prêt, alors créons nos classes d'événements AppEventsAuthorDeleted et AppEventsPostSaving.

#create Event Class

Nous créerons une classe d'événements AppEventsPostSaving qui sera planifiée lors de l'enregistrement d'un nouvel article:

use App\Events\UserRegistered;
use App\Models\User;

$user = User::create([
    'name' => 'Eric Barnes',
    'email' => 'eric@example.com',
]);

UserRegistered::dispatch($user);
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans le code ci-dessus, nous pouvons voir la classe d'événements AppEventsPostSaving, qui accepte une instance de modèle AppModelsPost dans son constructeur. Cette classe d'événements est un conteneur simple pour enregistrer l'instance de l'article enregistrée.

De même, nous pouvons créer une classe d'événements AppEventsAuthorDeleted qui sera planifiée lors de la suppression de l'auteur:

declare(strict_types=1);

namespace App\Listeners;

use App\Events\UserRegistered;
use App\Notifications\WelcomeNotification;
use Illuminate\Support\Facades\Mail;

final readonly class SendWelcomeEmail
{
    public function handle(UserRegistered $event): void
    {
        $event->user->notify(new WelcomeNotification());
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans la classe ci-dessus AppEventsAuthorDeleted, nous pouvons voir que le constructeur accepte une instance de modèle AppModelsAuthor.

Maintenant, nous pouvons continuer à créer des auditeurs.

#create écouteur

Créons d'abord un auditeur qui peut être utilisé pour calculer l'estimation du temps de lecture de l'article.

Nous allons créer une nouvelle classe d'écoute AppListenersCalculateReadTime:

UserRegistered::dispatch($user);
Copier après la connexion
Copier après la connexion

Comme nous le voyons dans le code ci-dessus, nous n'avons qu'une méthode handle. Il s'agit d'une méthode qui sera automatiquement appelée lors de la planification de l'événement AppEventsPostSaving. Il accepte une instance de la classe d'événements AppEventsPostSaving qui contient l'article enregistré.

Dans la méthode handle, nous utilisons une formule simple pour calculer le temps de lecture de l'article. Dans cet exemple, nous supposons que la vitesse de lecture moyenne est de 265 mots par minute. Nous calculons le temps de lecture en secondes, puis en définissant l'attribut read_time_in_seconds sur le modèle d'article.

Étant donné que cet écouteur sera appelé lorsque l'événement saving Modèle est déclenché, cela signifie que l'attribut read_time_in_seconds est calculé chaque fois que l'article est persistant dans la base de données avant de la créer ou de la mettre à jour.

Nous pouvons également créer un auditeur qui supprime doucement tous les articles associés lors de la suppression doucement de l'auteur.

Nous pouvons créer une nouvelle classe d'écoute AppListenersSoftDeleteAuthorRelationships:

declare(strict_types=1);

namespace App\Events;

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

final class UserRegistered
{
    use Dispatchable;
    use InteractsWithSockets;
    use SerializesModels;

    public function __construct(public User $user)
    {
        //
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans l'auditeur ci-dessus, la méthode handle accepte une instance de la classe d'événements AppEventsAuthorDeleted. Cette classe d'événements contient l'auteur supprimé. Ensuite, nous utilisons la relation posts pour supprimer l'article de l'auteur. delete

Par conséquent, chaque fois que le modèle

est supprimé doucement, tous les articles de tous les auteurs seront également supprimés doucement. AppModelsAuthor

Soit dit en passant, il convient de noter que vous voudrez peut-être utiliser une solution plus puissante et réutilisable pour y parvenir. Mais aux fins de cet article, nous restons simples.

Utilisez la fermeture pour écouter les événements du modèle


Une autre façon d'utiliser est de définir l'auditeur comme une fermeture sur le modèle lui-même.

Jetons un coup d'œil à l'exemple d'articles de suppression douce lorsque nous avons doucement supprimé l'auteur. Nous pouvons mettre à jour notre modèle

pour contenir une fermeture qui écoute les événements de modèle AppModelsAuthor: deleted

use App\Events\UserRegistered;
use App\Models\User;

$user = User::create([
    'name' => 'Eric Barnes',
    'email' => 'eric@example.com',
]);

UserRegistered::dispatch($user);
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Nous pouvons voir dans le modèle ci-dessus que nous définissons l'auditeur dans la méthode

du modèle. Nous voulons écouter l'événement modèle booted, nous avons donc utilisé deleted. De même, si nous voulons créer un auditeur pour l'événement de modèle self::deleted, nous pouvons utiliser created et ainsi de suite. La méthode self::created accepte une fermeture qui reçoit le self::deleted supprimé. Cette fermeture sera exécutée lorsque le modèle sera supprimé, de sorte que tous les articles d'auteur seront supprimés. AppModelsAuthor

J'aime vraiment cette façon de définir la logique de l'écoute car elle peut immédiatement voir si elle enregistre un observateur lors de l'ouverture de la classe de modèle. Ainsi, bien que la logique soit toujours "cachée" dans un fichier séparé, nous pouvons savoir que nous avons enregistré des auditeurs pour au moins un événement du modèle. Cependant, si le code de ces fermetures devient plus complexe, il peut être utile d'extraire la logique dans une classe d'écoute distincte.

Une astuce pratique est que vous pouvez également utiliser la fonction

pour faire la file d'attente de fermetures. Cela signifie que le code de l'auditeur sera poussé dans la file d'attente pour s'exécuter en arrière-plan, plutôt que dans le même cycle de vie. Nous pouvons mettre à jour l'auditeur à la queregue comme suit: IlluminateEventsqueueable

declare(strict_types=1);

namespace App\Listeners;

use App\Events\UserRegistered;
use App\Notifications\WelcomeNotification;
use Illuminate\Support\Facades\Mail;

final readonly class SendWelcomeEmail
{
    public function handle(UserRegistered $event): void
    {
        $event->user->notify(new WelcomeNotification());
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Comme nous l'avons vu dans l'exemple ci-dessus, nous enroulons la fermeture dans la fonction

. IlluminateEventsqueueable

Utilisation d'Observer pour écouter les événements du modèle


Une autre façon de prendre pour écouter les événements de modèle est d'utiliser des observateurs de modèles. Les observateurs du modèle vous permettent de définir tous les auditeurs du modèle dans une classe.

Habituellement, ce sont des classes qui existent dans le répertoire app/Observers, et ils ont des méthodes correspondant aux événements du modèle que vous souhaitez écouter. Par exemple, si vous souhaitez écouter un événement modèle deleted, vous définissez une méthode deleted dans la classe Observer. Si vous souhaitez écouter un événement modèle created, vous définissez une méthode created dans la classe Observer, etc.

Voyons comment créer un observateur de modèles pour notre modèle AppModelsAuthor Écoute du modèle pour les événements de modèle deleted:

declare(strict_types=1);

namespace App\Events;

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

final class UserRegistered
{
    use Dispatchable;
    use InteractsWithSockets;
    use SerializesModels;

    public function __construct(public User $user)
    {
        //
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Comme nous le voyons dans le code ci-dessus, nous créons un observateur avec la méthode deleted. Cette méthode accepte les instances du modèle AppModelsAuthor supprimé. Ensuite, nous utilisons la relation posts pour supprimer l'article de l'auteur. delete

Supposons, par exemple, nous voulons également définir des auditeurs pour les événements de modèle

et created. Nous pouvons mettre à jour nos observateurs comme ceci: updated

use App\Events\UserRegistered;
use App\Models\User;

$user = User::create([
    'name' => 'Eric Barnes',
    'email' => 'eric@example.com',
]);

UserRegistered::dispatch($user);
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Afin d'exécuter la méthode

, nous devons demander à Laravel de l'utiliser. Pour ce faire, nous pouvons utiliser l'attribut AppObserversAuthorObserver. Cela nous permet d'associer des observateurs au modèle, similaire à la façon dont nous enregistrons les lunettes de requête globales à l'aide de l'attribut #[IlluminateDatabaseEloquentAttributesObservedBy] (comme indiqué pour comprendre comment maîtriser la portée de la requête dans Laravel). Nous pouvons mettre à jour notre modèle #[ScopedBy] comme celui-ci pour utiliser l'observateur: AppModelsAuthor

declare(strict_types=1);

namespace App\Listeners;

use App\Events\UserRegistered;
use App\Notifications\WelcomeNotification;
use Illuminate\Support\Facades\Mail;

final readonly class SendWelcomeEmail
{
    public function handle(UserRegistered $event): void
    {
        $event->user->notify(new WelcomeNotification());
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
J'aime vraiment cette façon de définir la logique de l'auditeur, car elle peut immédiatement voir si elle enregistre un observateur lors de l'ouverture de la classe de modèle. Ainsi, bien que la logique soit toujours "cachée" dans un fichier séparé, nous pouvons savoir que nous avons enregistré des auditeurs pour au moins un événement du modèle.

Testez votre modèle d'événement


Quelle que soit la méthode des événements de modèle que vous utilisez, vous pouvez rédiger certains tests pour vous assurer que votre logique fonctionne comme prévu.

Voyons comment tester les événements du modèle que nous avons créés dans l'exemple ci-dessus.

Nous écrivons d'abord un test pour nous assurer que l'article de l'auteur est supprimé doucement lorsque l'auteur est supprimé doucement. Le test peut ressembler à ceci:

UserRegistered::dispatch($user);
Copier après la connexion
Copier après la connexion
Dans le test ci-dessus, nous créons un nouvel auteur et un nouvel article pour cet auteur. Nous avons ensuite doucement supprimé l'auteur et affirmé que l'auteur et l'article avaient été doucement supprimés.

Il s'agit d'un test très simple mais efficace que nous pouvons utiliser pour nous assurer que notre logique fonctionne comme prévu. L'avantage de ce test est qu'il devrait fonctionner avec chacune des méthodes dont nous discutons dans cet article. Donc, si vous basculez entre l'une des méthodes dont nous avons discuté dans cet article, votre test devrait toujours passer.

De même, nous pouvons rédiger certains tests pour nous assurer que le temps de lecture de l'article est calculé lors de la création ou de la mise à jour. Le test peut ressembler à ceci:

declare(strict_types=1);

namespace App\Events;

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

final class UserRegistered
{
    use Dispatchable;
    use InteractsWithSockets;
    use SerializesModels;

    public function __construct(public User $user)
    {
        //
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Nous avons deux tests dessus:

  • Le premier test garantit que le temps de lecture de l'article est calculé lors de la création.
  • Le deuxième test garantit que le temps de lecture de l'article est calculé lorsque l'article est mis à jour.

Précautions lors de l'utilisation des événements du modèle


Bien que les événements du modèle soient très pratiques, il y a certains problèmes à connaître lors de leur utilisation.

Les événements du modèle sont prévus à partir du modèle éloquent uniquement. Cela signifie que si vous utilisez une façade IlluminateSupportFacadesDB pour interagir avec les données sous-jacentes du modèle dans la base de données, ses événements ne seront pas planifiés.

Par exemple, regardons un exemple simple, nous utilisons la façade IlluminateSupportFacadesDB pour supprimer l'auteur:

use App\Events\UserRegistered;
use App\Models\User;

$user = User::create([
    'name' => 'Eric Barnes',
    'email' => 'eric@example.com',
]);

UserRegistered::dispatch($user);
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

L'exécution du code ci-dessus supprimera l'auteur de la base de données comme prévu. Cependant, les événements du modèle deleting et deleted ne sont pas planifiés. Donc, si vous définissez des auditeurs pour ces événements de modèle lors de la suppression de l'auteur, ils ne seront pas exécutés.

De même, si vous utilisez Eloquent pour mettre à jour par lots ou supprimer un modèle, les événements de modèle saved, updated, deleting et deleted ne sont pas planifiés pour les modèles affectés. En effet, les événements sont prévus à partir du modèle lui-même. Cependant, lorsque les mises à jour par lots et les suppressions sont mises à jour, le modèle n'est pas réellement récupéré dans la base de données, donc les événements ne sont pas planifiés.

Par exemple, supposons que nous utilisons le code suivant pour supprimer l'auteur:

declare(strict_types=1);

namespace App\Listeners;

use App\Events\UserRegistered;
use App\Notifications\WelcomeNotification;
use Illuminate\Support\Facades\Mail;

final readonly class SendWelcomeEmail
{
    public function handle(UserRegistered $event): void
    {
        $event->user->notify(new WelcomeNotification());
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Étant donné que la méthode delete est appelée directement sur le générateur de requête, les événements de modèle deleting et deleted ne sont pas prévus pour cet auteur.

Méthodes alternatives à considérer


J'aime utiliser des événements modèles dans mes projets. Ils servent de bon moyen de découpler mon code et me permettent également d'exécuter automatiquement la logique lorsque je n'ai pas beaucoup de contrôle sur le code qui affecte le modèle. Par exemple, si je supprime l'auteur dans Laravel Nova, je peux toujours exécuter une logique lors de la suppression de l'auteur.

Cependant, il est important de savoir quand envisager d'utiliser différentes méthodes.

Pour expliquer cela, examinons un exemple de base où nous pourrions vouloir éviter d'utiliser des événements de modèle. Étendez notre exemple de l'application de blog simple précédente, en supposant que nous voulons exécuter ce qui suit lors de la création d'un nouvel article:

  • Calculez le temps de lecture de l'article.
  • Envoyez des appels API à X / Twitter pour partager l'article.
  • Envoyez des notifications à chaque abonné de la plate-forme.

afin que nous puissions créer trois auditeurs distincts (un pour chaque tâche) qui s'exécutent à chaque fois qu'une nouvelle instance AppModelsPost est créée.

Mais passons maintenant en revue l'un de nos tests précédents:

declare(strict_types=1);

namespace App\Events;

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

final class UserRegistered
{
    use Dispatchable;
    use InteractsWithSockets;
    use SerializesModels;

    public function __construct(public User $user)
    {
        //
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Si nous exécutons le test ci-dessus, il déclenchera également ces trois opérations lorsque le modèle AppModelsPost est créé via son usine. Bien sûr, le calcul du temps de lecture est une tâche secondaire, donc cela n'a pas beaucoup d'importance. Mais nous ne voulons pas essayer de passer des appels d'API ou d'envoyer des notifications pendant les tests. Ce sont des effets secondaires inattendus. Si le développeur qui rédige le test n'est pas au courant de ces effets secondaires, il peut être difficile de retrouver la raison pour laquelle ces opérations se produisent.

Nous voulons également éviter d'écrire une logique spécifique au test dans l'auditeur, ce qui empêche ces opérations de fonctionner pendant les tests. Cela rendra le code d'application plus complexe et plus difficile à maintenir.

C'est l'un des cas où vous voudrez peut-être envisager une approche plus explicite plutôt que de compter sur des événements de modèle automatique.

Une façon peut être d'extraire votre code de création AppModelsPost dans un service ou une classe d'action. Par exemple, une classe de service simple peut ressembler à ceci:

use App\Events\UserRegistered;
use App\Models\User;

$user = User::create([
    'name' => 'Eric Barnes',
    'email' => 'eric@example.com',
]);

UserRegistered::dispatch($user);
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans la classe ci-dessus, nous appelons manuellement le code qui calcule le temps de lecture, envoie des notifications et des publications à Twitter. Cela signifie que nous avons un meilleur contrôle sur le moment où ces opérations sont exécutées. Nous pouvons également se moquer facilement de ces méthodes dans les tests pour les empêcher de fonctionner. Nous pouvons toujours faire la queue de ces opérations si nécessaire (dans ce cas, nous le ferons très probablement).

Par conséquent, nous pouvons supprimer les événements du modèle et les auditeurs pour ces opérations. Cela signifie que nous pouvons utiliser cette nouvelle classe AppServicesPostService dans notre code d'application et utiliser en toute sécurité l'usine Model dans notre code de test.

L'avantage supplémentaire de le faire est qu'il rend également le code plus facile à comprendre. Comme je l'ai brièvement mentionné, une critique commune de l'utilisation d'événements et d'auditeurs est qu'il peut cacher la logique commerciale dans des endroits inattendus. Donc, si les nouveaux développeurs rejoignent l'équipe, s'ils sont déclenchés par des événements modèles, ils ne savent peut-être pas où ou pourquoi certaines opérations se produisent.

Cependant, si vous souhaitez toujours utiliser des événements et des auditeurs pour une telle logique, vous pourriez envisager d'utiliser une approche plus explicite. Par exemple, vous pouvez planifier un événement de la classe de service pour déclencher l'auditeur. De cette façon, vous pouvez toujours utiliser les avantages du découplage des événements et des auditeurs, mais vous avez un meilleur contrôle sur le moment où les événements sont prévus.

Par exemple, nous pouvons mettre à jour la méthode AppServicesPostService ci-dessus dans notre exemple createPost pour planifier les événements:

declare(strict_types=1);

namespace App\Listeners;

use App\Events\UserRegistered;
use App\Notifications\WelcomeNotification;
use Illuminate\Support\Facades\Mail;

final readonly class SendWelcomeEmail
{
    public function handle(UserRegistered $event): void
    {
        $event->user->notify(new WelcomeNotification());
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

En utilisant la méthode ci-dessus, nous pouvons toujours avoir un auditeur séparé pour faire des demandes d'API et envoyer des notifications à Twitter. Mais nous avons un meilleur contrôle sur le moment où ces opérations sont exécutées, elles ne sont donc pas exécutées lors des tests à l'aide de l'usine du modèle.

Il n'y a pas de règle d'or pour décider d'utiliser l'une de ces méthodes. Tout dépend de vous, de votre équipe et des fonctionnalités que vous construisez. Cependant, j'ai tendance à suivre les règles de base suivantes:

  • Si les opérations de l'auditeur n'apportent que des modifications mineures au modèle, envisagez d'utiliser des événements du modèle. Exemple: générer des limaces, calculer le temps de lecture, etc.
  • Si l'opération affectera un autre modèle (qu'il soit automatiquement créé, mis à jour ou supprimé), il est plus clair et n'utilise pas d'événements de modèle.
  • Si l'opération fonctionne avec des processus externes (appels API, traitement de fichiers, notifications de déclenchement, travaux en file d'attente), il est plus clair que vous n'utilisez pas d'événements de modèle.

Avantages et inconvénients de l'utilisation d'événements modèles


Pour résumer rapidement ce que nous avons introduit dans cet article, voici quelques-uns des avantages et des inconvénients de l'utilisation d'événements modèles:

#pros

  • vous encourage à découpler le code.
  • vous permet de déclencher automatiquement des actions, peu importe où le modèle est créé / mis à jour / supprimer. Par exemple, si le modèle a été créé dans Laravel Nova, vous pouvez déclencher une logique métier.
  • Vous n'avez pas besoin de vous souvenir de planifier des événements chaque fois que vous créez / mettez à jour / supprimez un modèle.

#disadvantages

  • peut provoquer des effets secondaires inattendus. Vous voudrez peut-être créer / mettre à jour / supprimer le modèle sans déclencher certains auditeurs, mais cela peut conduire à un comportement inattendu. Ceci est particulièrement problématique lors de la rédaction de tests.
  • La logique commerciale peut être cachée dans des endroits inattendus difficiles à suivre. Cela rendra le flux de code plus difficile à comprendre.

Conclusion


J'espère que cet article donne un aperçu de ce que sont les événements de modèle et des différentes façons de les utiliser. Cela devrait également vous montrer comment tester les codes d'événements du modèle et certains problèmes à connaître lors de leur utilisation.

Vous devriez maintenant avoir suffisamment de confiance pour utiliser des événements de modèle dans votre application Laravel.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal