【问题标题】:Laravel Notifications Listener Is Useless When Implementing the QueueLaravel 通知监听器在实现队列时无用
【发布时间】:2018-08-12 13:45:58
【问题描述】:

Laravel 版本:5.5.*

PHP 版本:7.1.*

根据文档https://laravel.com/docs/5.5/notifications,订阅通知事件应该非常简单。我已按照文档中的步骤进行操作,但我的通知实现了 ShouldQueue 并且它们没有正确填充事件侦听器。我想知道问题是否似乎是 in the framework code

请注意,在框架 github(链接在上面)中,new Events\NotificationSent($notifiable, $notification, $channel, $response) 仅由 sendToNotifiable 函数触发,而后者又仅由 sendNow 函数触发。 send 函数本身是这样的:

public function send($notifiables, $notification)
    {
        $notifiables = $this->formatNotifiables($notifiables);

        if ($notification instanceof ShouldQueue) {
            return $this->queueNotification($notifiables, $notification);
        }

        return $this->sendNow($notifiables, $notification);
    }

也就是说,在我看来,如果是if ($notification instanceof ShouldQueue) { 的情况,事件不会触发,因为queueNotification 永远不会触发事件侦听器。我假设它进入队列,然后需要重新触发事件,但我认为这不会发生,因为我的 NotificationSent 侦听器没有填充来自该的 any 数据类构造函数。

事件服务提供者:

 protected $listen = [
       'Illuminate\Notifications\Events\NotificationSent' => [
        'App\Listeners\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 这里是空的,我的日志中什么也没有,只有Notification Listener:

所以我的问题是,为什么会这样,以及如何在我需要做的时候利用队列时有一个通知事件侦听器。是我做错了什么还是框架?

【问题讨论】:

    标签: laravel events laravel-5.5


    【解决方案1】:

    快速回答:您在进行这些修改时是否重新启动了队列工作程序?

    我的盒子上的NotificationSent 在排队和处理时按预期触发和捕获。


    当 Laravel 在NotificationSender 中碰到这段代码时:

    if ($notification instanceof ShouldQueue) {
        return $this->queueNotification($notifiables, $notification);
    }
    

    它使用 Queue Dispatcher 将通知排队并将其存储到您的队列中。当你的工人拿起它时,它会反序列化命令,并启动SendQueuedNotifications。然后这个类将处理排队的通知,并处理队列(source):

    public function handle(ChannelManager $manager)
    {
        $manager->sendNow($this->notifiables, $this->notification, $this->channels);
    }
    

    ChannelManager 会这样做 (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);
    }
    

    然后就可以了。调用NotificationSender 中的sendNow。应该在这个函数中调用NotificationSent 事件。


    编辑

    这是我测试它的方式:

    1. 确保您的队列已正确设置。我使用数据库队列,带有作业/失败作业表组合。

    2. 创建文件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));
          }
      }
      
    3. 编辑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
              ]
          ];
      }
      
    4. 创建一个虚拟通知(发送一封 Hello 电子邮件):

      <?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');
          }
      }
      
    5. 重新启动队列工作器。我只需重新启动我的php artisan queue:work

    6. 发送通知

      $user->notify(new WelcomeNotification());
      
    7. 检查laravel.log,你应该在那里打印NotificationSent的类名。

      [2018-03-06 09:51:02] production.INFO: Illuminate\Notifications\Events\NotificationSent  
      

    【讨论】:

    • 当您说我的盒子上的NotificationSent 在排队和处理时按预期触发和捕获时,您是否能够在侦听器handle() 函数中填充$event
    • 是的,我在handle的第一个参数中得到了NotificationSent事件的实例。
    • 仅供参考,我做了var_dump($event),它在运行队列的控制台中打印输出,但不在 laravel 日志中。尝试这样做:Log:info('Notification Listener:'.' '.var_dump($event-&gt;channel));,例如。
    • 不管我记录什么,$event 或其属性都不起作用。 ?
    • 你能把你的代码贴出来,这样我就可以准确地复制它,看看它是否有效......也许我的环境有问题......
    猜你喜欢
    • 2019-08-20
    • 2019-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-07
    • 2016-03-12
    • 2018-06-20
    • 2016-10-07
    相关资源
    最近更新 更多