Wanneer je vanuit een package extra manieren wilt bieden om notificaties te bezorgen, ontwerp je de keuze van het kanaal en het bepalen van de bestemming los van elkaar. Op deze pagina gebruiken we een klein kanaal dat operationele gebeurtenissen naar de log schrijft als voorbeeld, en leggen we uit via welk pad de klassen uit je package worden geresolved en welke verificatie nodig is bij updates. Ook als je dit vervangt door verzending naar een externe dienst, blijft de verdeling van verantwoordelijkheden tussen kanaal en notificatie hetzelfde.
Deze pagina is gecontroleerd aan de hand van de implementatie van Laravel Framework v13.38.0. Zie Notificaties voor de basisbewerkingen van notificaties en Packages testen voor de testomgeving van een package.
De klassenaam is de bezorgwijze, de route is de bestemming
De kanaalklassenaam die je uit via() teruggeeft, bepaalt van welk object send() wordt aangeroepen. De waarde die je uit routeNotificationFor() ophaalt, is daarentegen de bestemming die dat kanaal gebruikt. De twee hoeven niet dezelfde naam te hebben.
NotificationSender geeft de kanaalnaam die via() heeft gekozen door aan ChannelManager::driver(). Als ChannelManager de naam niet vindt bij de ingebouwde of geregistreerde namen en de naam een bestaande klasse is, resolvet hij die klasse via de container. Als je het kanaal alleen via de klassenaam gebruikt, heb je geen Notification::extend() of service provider in je package nodig. Zorg er wel voor dat de klasse via de autoload van Composer gevonden wordt en dat de container de afhankelijkheden van de constructor kan resolven.
Het kanaal zelf vanuit het package leveren
Het voorbeeldpackage Acme\OperationsLog legt gebeurtenisnamen zonder gevoelige informatie vast, samen met de naam van het operationele team dat de notificatie ontvangt. In een Laravel-applicatie is Psr\Log\LoggerInterface gekoppeld aan de logservice, dus je kunt deze via de constructor ontvangen.
Het ontvangen object is naar verwachting een model dat de trait Notifiable gebruikt, of een on-demand bestemming die Notification::route() aanmaakt. In het eerste geval wordt de waarde van routeNotificationForOperationsLog() teruggegeven, in het tweede geval de waarde die met route('operationsLog', ...) is geregistreerd. Om te voorkomen dat een notificatie zonder bestemming als bezorgd wordt behandeld, gooit dit voorbeeld een exception. Ook als je dit vervangt door echte externe bezorging, controleer je de bestemming en het verzendresultaat, en ontwerp je het zo dat fouten niet stilletjes als succes worden behandeld.
Neem geen toegangstokens of persoonsgegevens op in de gebeurtenisnamen of bestemmingen die je naar de log schrijft. Dit voorbeeld is een logverzending om het resolven van kanalen en het testen te laten zien, en geen implementatie van bezorging naar een externe dienst.
Notificatie en bestemming definiëren aan de kant van de gebruiker
De notificatie in de applicatie geeft de kanaalklasse terug en definieert alleen het bericht dat aan het kanaal wordt doorgegeven. Met ShouldQueue en Queueable loopt een gewone aanroep van notify() via de wachtrij.
Als je de bestemming ter plekke opgeeft, is de sleutel van Notification::route() niet de kanaalklassenaam, maar de sleutel van routeNotificationFor('operationsLog', ...) die binnen het kanaal wordt aangeroepen.
Wil je vanuit een model in de applicatie verzenden, voeg dan de volgende methode toe aan het model dat Notifiable gebruikt.
Ook met $user->notify(new HealthCheckPassed()) op dit model wordt hetzelfde kanaal gekozen. Configureer een wachtrijverbinding en start een worker die de wachtrij operations-log verwerkt.
OperationsLogChannel zelf wordt per kanaal in de Manager vastgehouden. Sla de bestemming of de inhoud van de notificatie daarom niet op in properties van het kanaal, maar haal ze bij elke aanroep uit de argumenten van send(). Zo neemt ook een langlopende queue worker geen gegevens van een vorige notificatie mee.
Als je een korte alias nodig hebt
Alleen als je gebruikers in via() een korte naam wilt laten opgeven in plaats van een klassenaam, gebruik je Notification::extend() in de gewone service provider van je package.
Laat de provider laden voordat de bezorging begint, bijvoorbeeld via automatische packagedetectie. In notificaties die de alias kiezen, verander je via() in ['acme-operations-log'] en gebruik je dezelfde naam als sleutel in viaQueues(). operationsLog voor het ophalen van de bestemming is een aparte sleutel en hoeft niet te veranderen. Kies een naam die niet botst met de namen van ingebouwde kanalen.
De Manager houdt geresolvede kanalen per naam vast. Als je de aanmaakroutine van de alias in hetzelfde proces opnieuw registreert, wordt een al aangemaakte instantie niet vervangen. Verifieer wijzigingen in de registratie ook in een nieuw opgestarte applicatie of worker.
De bezorging los van fake testen
Notification::fake() is bedoeld om de intentie om een notificatie te verzenden te verifiëren. Je kunt er niet mee controleren of send() van het kanaal en het ophalen van de route werken. Gebruik voor het testen van de bezorging de echte notificatiemanager en vervang LoggerInterface door een testversie.
Het volgende voorbeeld draait vanuit de TestCase van Testbench. Met notifyNow() kun je de verwerking van het kanaal uitvoeren zonder een worker te starten, ook voor een ShouldQueue-notificatie.
Controleer daarnaast dat er een exception optreedt als er geen bestemming is, en dat een alias, als je die aanbiedt, vanaf een nieuwe start kan worden geresolved. Gebruik je het kanaal via de wachtrij, test dan ook in een aparte verificatieapplicatie met een draaiende queue worker dat jobs in de wachtrij operations-log aankomen en worden verwerkt.
NotificationSender splitst een ShouldQueue-notificatie per kanaal op in jobs en kiest de wachtrij aan de hand van de sleutels van viaQueues(). Als send() van het kanaal een exception gooit, vuurt hij NotificationFailed af en gooit de exception opnieuw. Keert send() normaal terug, dan vuurt hij NotificationSent af. De instellingen voor nieuwe pogingen in de wachtrij volgen de configuratie van de applicatie. Let op: als je exceptions binnen het kanaal stilletjes afvangt, wordt een mislukte bezorging als succes behandeld.
Geraadpleegde primaire bronnen