问题
Laravel Version: 5.5.*
PHP Version: 7.1.*
According to the docs https://laravel.com/docs/5.5/notifications it should be super simple to subscribe to Notification events. I've followed the steps in the docs, but my Notifications implement ShouldQueue
and they weren't properly populating the event listener. I'm wonder if the issue seems to be in the framework code.
Notice that in the framework github (linked right above), that new Events\NotificationSent($notifiable, $notification, $channel, $response)
is only fired from the sendToNotifiable
function, which in turn is only fired from the sendNow
function. The send
function itself, is like this:
public function send($notifiables, $notification)
{
$notifiables = $this->formatNotifiables($notifiables);
if ($notification instanceof ShouldQueue) {
return $this->queueNotification($notifiables, $notification);
}
return $this->sendNow($notifiables, $notification);
}
That is, as it reads to me, the event will not fire if it is a case of if ($notification instanceof ShouldQueue) {
as queueNotification
never triggers an event listener. I assume it goes into the queue and then will need to re-trigger the event, but I don't think this is happening, because my NotificationSent
listener isn't populated with any data from that class constructor.
EventServiceProvider:
protected $listen = [
'Illuminate\Notifications\Events\NotificationSent' => [
'App\Listeners\NewNotificationListener',
],
NewNotificationListener:
<?php
namespace App\Listeners;
use Illuminate\Notifications\Events\NotificationSent;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Jobs\SendEmailForNotifications;
use Illuminate\Support\Facades\Log;
class NewNotificationListener
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
public function handle(NotificationSent $event)
{
Log:info('Notification Listener:'.' '.var_dump($event));
SendEmailForNotifications::dispatch($event->notification)->delay(now()->addMinutes(10));
}
}
var_dump
here is empty, I get nothing in my log, just Notification Listener:
.
So my question is, why is this and how can I have a Notification event listener while leveraging the Queue as I need to do. Is it something I am doing wrong or is it the framework?
回答1:
Quick answer: Have you restarted your queue worker when you made these modifications?
The NotificationSent
on my box is triggered and captured as expected when it's being queued and handled.
When Laravel hit this piece of code in NotificationSender
:
if ($notification instanceof ShouldQueue) {
return $this->queueNotification($notifiables, $notification);
}
It queues the notification using the Queue Dispatcher and store it into your queue. And when your worker pick it up, it unserialise the command, and launches SendQueuedNotifications
. This class will then handle the queued notifications, and handle the queue (source):
public function handle(ChannelManager $manager)
{
$manager->sendNow($this->notifiables, $this->notification, $this->channels);
}
And ChannelManager
does this (source):
public function sendNow($notifiables, $notification, array $channels = null)
{
return (new NotificationSender(
$this, $this->app->make(Bus::class), $this->app->make(Dispatcher::class))
)->sendNow($notifiables, $notification, $channels);
}
And there you go. The sendNow
in NotificationSender
is called. The NotificationSent
event should be called in this function.
Edit
This is how I tested it:
Make sure your queue has been set up correctly. I use a database queue, with jobs/failed_jobs table combo.
Create the file
app/Listeners/TestListener.php
<?php namespace App\Listeners; use Illuminate\Notifications\Events\NotificationSent; class TestListener { public function handle(NotificationSent $event) { \Log::info(get_class($event)); } }
Edit
app/Providers/EventServiceProvider.php
<?php namespace App\Providers; use App\Listeners\TestListener; use Illuminate\Notifications\Events\NotificationSent; use Laravel\Lumen\Providers\EventServiceProvider as ServiceProvider; class EventServiceProvider extends ServiceProvider { /** * The event listener mappings for the application. * * @var array */ protected $listen = [ NotificationSent::class => [ TestListener::class ] ]; }
Create a dummy notification (send an Hello email):
<?php namespace App\Notifications\Users; use App\Notifications\Notification; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Channels\MailChannel; use Illuminate\Notifications\Messages\MailMessage; class WelcomeNotification extends Notification implements ShouldQueue { use Queueable; public function via($notifiable) { return [MailChannel::class]; } public function toMail($notifiable) { return (new MailMessage()) ->line('Hello'); } }
Restart your queue worker. I simply restart my
php artisan queue:work
.Send the notification
$user->notify(new WelcomeNotification());
Check
laravel.log
, you should have the class name ofNotificationSent
printed there.[2018-03-06 09:51:02] production.INFO: Illuminate\Notifications\Events\NotificationSent
来源:https://stackoverflow.com/questions/49101402/laravel-notifications-listener-is-useless-when-implementing-the-queue