vendor zur automatischen Erkennung hinzufügen müssen, reduzieren Sie die Annahmen bei Installation, Update und Cache-Erstellung.
Diese Seite untersucht die Implementierung in Laravel Framework v13.36.0 und wendet die grundlegenden Operationen aus Events auf die langfristige Wartung von Paketen an. Zum Laden von Providern siehe Paketerkennung, zur Testumgebung siehe Pakete testen.
Listener eines Pakets explizit registrieren
Verarbeitungen, die ein Paket standardmäßig ausführt, können Sie inboot() eines regulären Illuminate\Support\ServiceProvider mit Event::listen() registrieren. Das Standardziel der automatischen Listener-Erkennung in Laravel ist app/Listeners der Anwendung; src/Listeners innerhalb eines Pakets wird nicht automatisch durchsucht.
Als Beispiel erstellen wir ein Paket, das ein Event für eine abgeschlossene Zustellung protokolliert. Das Event ist lediglich eine Klasse, die die für die Benachrichtigung benötigten Werte enthält.
handle().
extra.laravel.providers in Composer oder eine explizite Registrierung durch die Nutzer bereit. Wenn das Event sowohl bei der HTTP-Verarbeitung als auch in Queue-Workern benötigt wird, schränken Sie die Registrierung nicht mit runningInConsole() ein.
Registrierung und Instanziierung erfolgen zu unterschiedlichen Zeitpunkten
Dispatcher::listen() fügt Listener für einen regulären Event-Namen einem internen Array hinzu. Wenn Sie wie oben einen Klassennamen übergeben, wird an dieser Stelle noch keine Listener-Instanz erzeugt.
Bei synchronen Listenern löst createClassCallable() die Klasse nach dem Auslösen des Events über make() des Containers auf. Daher können Sie Abhängigkeitsinjektion im Konstruktor nutzen.
Auf diesem Weg wird für handle() kein call() des Containers ausgeführt. Entwerfen Sie Listener so, dass beliebige Services in den Konstruktor injiziert werden und handle() das Event entgegennimmt. Gehen Sie nicht davon aus, dass es sich um denselben Mechanismus wie bei der Abhängigkeitsinjektion in handle() von Artisan-Befehlen handelt.
Hier geht es um synchrone Listener. Wenn Sie ShouldQueue implementieren, wird ein separater Pfad für Queues verwendet. Prüfen Sie daher zu Transaktionen, Wiederholungsversuchen und Abhängigkeitsauflösung auch Events in der Queue verarbeiten und Queues.
event:cache verhindert keine explizite Registrierung
event:cache ist kein Befehl, der sämtliche im Event-Dispatcher registrierten Listener vollständig serialisiert.
EventCacheCommand::getEvents() listet Illuminate\Foundation\Support\Providers\EventServiceProvider und davon abgeleitete Provider auf und speichert für jeden Provider die Ergebnisse der automatischen Erkennung sowie die Zuordnungen aus listens(). Event::listen() in ServiceProvider::boot() eines regulären Providers gehört nicht zu den gesammelten Einträgen.
Andererseits wird boot() regulärer Provider auch bei einem Start mit vorhandenem Cache ausgeführt. Dass eine Registrierung nicht im Cache enthalten ist, bedeutet nicht, dass sie bei vorhandenem Cache nicht registriert wird.
Ein Paket kann auch vom Foundation-
EventServiceProvider erben und $listen verwenden. In der untersuchten Implementierung bezieht sich der Standardwert von shouldDiscoverEvents() jedoch auf die Basisklasse selbst. Allein durch das Erben wird das Listener-Verzeichnis des Pakets nicht automatisch erkannt.
Außerdem werden $subscribe und $observers dieses Providers getrennt von der Schleife verarbeitet, die die Ergebnisse von getEvents() registriert. Schließen Sie nicht allein aus dem Cache für $listen, dass auch diese Registrierungen übersprungen werden.
Doppelregistrierung mit der automatischen Erkennung vermeiden
Wenn Nutzer das Listener-Verzeichnis eines Pakets überwithEvents(discover: [...]) hinzufügen und der Provider des Pakets denselben Listener zusätzlich explizit registriert, kann die Verarbeitung bei einem einzigen Event mehrfach ausgeführt werden.
Dispatcher::listen() fügt für reguläre Events Einträge zu einem Array hinzu und entfernt Duplikate desselben Klassennamens nicht automatisch für den gesamten Dispatcher. Auch array_unique(), das der Foundation-EventServiceProvider innerhalb seiner eigenen Zuordnungen anwendet, fasst keine expliziten Registrierungen aus anderen Providern zusammen.
Legen Sie die Verantwortung für die Registrierung auf eine Seite fest.
- Wenn das Paket die Standard-Listener registriert, verlangen Sie von Nutzern nicht, dieses Verzeichnis zur automatischen Erkennung hinzuzufügen.
- Wenn Nutzer die benötigten Listener auswählen, stellt das Paket die Event- und Listener-Klassen bereit und registriert denselben Listener nicht standardmäßig.
- Wenn Sie von der automatischen Erkennung zur expliziten Registrierung wechseln, weisen Sie darauf hin, dass auch die Erkennungseinstellungen auf Nutzerseite und alte Event-Caches aktualisiert werden müssen.
Das Verhalten vor und nach Updates prüfen
Um den Registrierungsstatus zu untersuchen, führen Sieevent:list in einer Testanwendung aus, in der das Paket installiert ist. Stellen Sie sicher, dass der betreffende Listener sowohl ohne als auch mit Cache vorhanden ist.
event:list allein garantiert nicht, dass der Listener seine Verarbeitung abschließt oder nur einmal ausgeführt wird. Fügen Sie zusätzlich Tests hinzu, die tatsächlich Events auslösen.
Als Beispiel registrieren Sie CourierServiceProvider im Basis-TestCase von Testbench und prüfen, dass der Logger genau einmal aufgerufen wird.
Event::fake() ist praktisch, um das Auslösen von Events zu prüfen, verhindert aber normalerweise die Ausführung der echten Listener. Da dieser Test Registrierung und Verarbeitung prüft, wird es hier nicht verwendet. Prüfen Sie die Kombination mit der automatischen Erkennung und den Start mit vorhandenem Cache ebenfalls in einer separaten Testanwendung bzw. einer neuen Anwendungsinstanz.
Checkliste für die langfristige Wartung
- Dokumentieren Sie Event-Klassennamen, öffentliche Eigenschaften und die Strategie zur Listener-Registrierung als Vertrag gegenüber den Nutzern.
- Wenn Sie Namen oder Payloads von Events ändern, die Nutzer abonnieren, kommunizieren Sie die Änderung gemäß der Versionskompatibilitätsverwaltung.
- Nehmen Sie bei Updates mit Änderungen an der automatischen Erkennung oder an
$listendie Neuerstellung vonevent:cachein den Deployment-Ablauf auf. - Unterscheiden Sie zwischen den Standard-Listenern des Pakets und eigenen Listenern der Nutzer, und lassen Sie denselben Standard-Listener nicht doppelt registrieren.
- Führen Sie für jede unterstützte PHP- und Laravel-Version fortlaufend Tests durch, die sicherstellen, dass Listener genau einmal ausgeführt werden.