vendor à la découverte automatique réduit les hypothèses à respecter lors de l’installation, de la mise à jour et de la création du cache.
Cette page examine l’implémentation de Laravel Framework v13.36.0 et applique les opérations de base des événements à la maintenance à long terme d’un package. Pour le chargement du provider, consultez Découverte automatique des packages, et pour l’environnement de test, consultez Tester des packages.
Enregistrer explicitement les écouteurs du package
Les traitements que le package exécute par défaut peuvent être enregistrés avecEvent::listen() dans la méthode boot() d’un Illuminate\Support\ServiceProvider ordinaire. L’emplacement de découverte automatique des écouteurs par défaut de Laravel est le répertoire app/Listeners de l’application ; le framework ne parcourt pas automatiquement le répertoire src/Listeners d’un package.
À titre d’exemple, créons un package qui journalise un événement de livraison terminée. L’événement est une simple classe contenant les valeurs nécessaires à la notification.
handle().
extra.laravel.providers dans Composer ou un enregistrement explicite par l’utilisateur. Si l’événement est nécessaire aussi bien lors du traitement HTTP que dans les workers de file d’attente, ne restreignez pas l’enregistrement avec runningInConsole().
L’enregistrement et l’instanciation ont lieu à des moments distincts
Dispatcher::listen() ajoute l’écouteur à un tableau interne pour un nom d’événement ordinaire. Lorsque vous passez un nom de classe comme ci-dessus, l’instance de l’écouteur n’est pas créée à ce stade.
Pour les écouteurs synchrones, createClassCallable() résout la classe via make() du conteneur après le déclenchement de l’événement. Vous pouvez donc utiliser l’injection de dépendances dans le constructeur.
Ce chemin n’effectue pas de call() du conteneur sur handle(). Concevez l’écouteur de sorte que les services arbitraires soient injectés dans le constructeur et que handle() reçoive l’événement. Ne considérez pas ce mécanisme comme identique à l’injection de dépendances dans handle() des commandes Artisan.
Il est ici question des écouteurs synchrones. Si vous implémentez ShouldQueue, un chemin distinct propre aux files d’attente s’applique : consultez également la mise en file d’attente des événements et Files d’attente concernant les transactions, les nouvelles tentatives et la résolution des dépendances.
event:cache n’empêche pas l’enregistrement explicite
event:cache n’est pas une commande qui sérialise intégralement tous les écouteurs enregistrés auprès du Dispatcher d’événements.
EventCacheCommand::getEvents() énumère Illuminate\Foundation\Support\Providers\EventServiceProvider et ses providers dérivés, puis enregistre les résultats de la découverte automatique et le mappage listens() de chaque provider. Les appels à Event::listen() écrits dans un ServiceProvider::boot() ordinaire ne font pas partie de cette collecte.
En revanche, même lors d’un démarrage avec cache, la méthode boot() des providers ordinaires est exécutée. Ne pas figurer dans le cache et ne pas être enregistré lorsque le cache existe sont deux choses différentes.
Un package qui hérite de l’
EventServiceProvider de Foundation peut aussi utiliser $listen. Toutefois, dans l’implémentation examinée, la valeur par défaut de shouldDiscoverEvents() est évaluée pour la classe de base elle-même. Le simple fait d’hériter ne déclenche pas la découverte automatique du répertoire des écouteurs du package.
Par ailleurs, $subscribe et $observers de ce même provider sont traités séparément de la boucle qui enregistre les résultats de getEvents(). Ne concluez pas, en vous fondant uniquement sur le cache de $listen, que ces enregistrements sont également omis.
Éviter le double enregistrement avec la découverte automatique
Si l’utilisateur ajoute le répertoire des écouteurs du package viawithEvents(discover: [...]) et que le provider du package enregistre aussi explicitement les mêmes écouteurs, le traitement peut s’exécuter plusieurs fois pour un seul événement.
Dispatcher::listen() ajoute l’écouteur au tableau pour les événements ordinaires, et le Dispatcher ne déduplique pas automatiquement les noms de classes identiques à l’échelle globale. L’array_unique() effectué par l’EventServiceProvider de Foundation au sein de son propre mappage ne fusionne pas non plus les enregistrements explicites effectués par d’autres providers.
Attribuez la responsabilité de l’enregistrement à un seul côté.
- Si le package enregistre les écouteurs par défaut, n’exigez pas de l’utilisateur qu’il ajoute ce répertoire à la découverte automatique.
- Si l’utilisateur choisit les écouteurs nécessaires, le package fournit les classes d’événements et d’écouteurs, mais n’enregistre pas ces mêmes écouteurs par défaut.
- Lors d’une migration de la découverte automatique vers l’enregistrement explicite, indiquez que la configuration de découverte côté utilisateur et l’ancien cache d’événements doivent également être mis à jour.
Vérifier le comportement avant et après une mise à jour
Pour examiner l’état de l’enregistrement, exécutezevent:list dans une application de vérification où le package est installé. Vérifiez que l’écouteur concerné est présent, avec et sans cache.
event:list ne garantit à lui seul ni que l’écouteur termine son traitement, ni qu’il ne s’exécute qu’une seule fois. Ajoutez également des tests qui déclenchent réellement l’événement.
À titre d’exemple, après avoir enregistré CourierServiceProvider dans le TestCase de base de Testbench, vérifiez que le logger n’est appelé qu’une seule fois.
Event::fake() est pratique pour vérifier le déclenchement d’un événement, mais il empêche normalement l’exécution des vrais écouteurs. Ce test vérifiant l’enregistrement et le traitement, il ne l’utilise pas. Vérifiez également la combinaison avec la découverte automatique et le démarrage avec cache dans une autre application de vérification, avec une nouvelle instance d’application.
Liste de contrôle pour la maintenance à long terme
- Documentez les noms des classes d’événements, leurs propriétés publiques et la politique d’enregistrement des écouteurs comme un contrat destiné aux utilisateurs.
- Lorsque vous modifiez le nom ou la charge utile d’un événement auquel les utilisateurs s’abonnent, communiquez le changement conformément à la gestion de la compatibilité des versions.
- Pour les mises à jour qui modifient la découverte automatique ou
$listen, incluez la régénération deevent:cachedans la procédure de déploiement. - Distinguez les écouteurs par défaut du package des écouteurs personnalisés de l’utilisateur, et ne faites pas enregistrer deux fois le même écouteur par défaut.
- Maintenez, pour chaque version de PHP et de Laravel prise en charge, des tests vérifiant que l’écouteur ne s’exécute qu’une seule fois.