Laravel通知事件监听器未定义属性

Sum*_*per 11 php laravel laravel-5 laravel-5.3

我有以下错误:

未定义的属性:Illuminate\Notifications\Events\NotificationSent :: $ user in /var/www/app/app/Listeners/NoticationListener.php:31

这里发生错误:

<?php

namespace App\Listeners;

use Illuminate\Notifications\Events\NotificationSent;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

class NoticationListener implements ShouldQueue
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  NotificationSent  $event
     * @return void
     */
    public function handle(NotificationSent $event)
    {
       $notification = $event->notifiable;
       $addressee = $notification; //error here
       $address = $notification; 
       $type = "Notification";
       dispatch(new SendEmail($type,$addressee,$address));
    }
}
Run Code Online (Sandbox Code Playgroud)

我不明白这个未定义的属性,特别是在这一行上.我怎么dd()能从这里来?我试图记录$event但我无法记录,只有这个错误.

我的通知在应用程序中运行得很好,我只想要一封电子邮件陪伴他们,这就是为什么我有这个事件监听器/工作.

谢谢.

编辑

调度通知的存储库代码如下:

public function notify($asset)
{
    $users = User::where("id","!=",Auth::user()->id)->get();
    Notification::send($users, new NewAsset($asset));
}
Run Code Online (Sandbox Code Playgroud)

Notification课程的扩展如下:

class NewAsset extends Notification
{
    use Queueable;

    /**
     * Create a new notification instance.
     *
     * @return void
     */
    protected $asset;

    public function __construct($asset)
    {
        $this->asset = $asset;
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return ['database'];
    }

    /**
     * Get the array representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [
            'asset_id' => $this->asset->id
        ];
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑2

如果有人可以建议如何在此时进行一些错误检查,那么这可能会有所帮助.因为代码在服务器上是异步的,所以它不会将数据返回给客户端,当我尝试将其发送到它时,Log它似乎不会在错误中被捕获之前这样做.

如何在这种情况下进行调试?

我查看了框架的源代码,并且不知道$ user属性的来源.我认为它与$event->notifiable绑定到User模型有关,但如果它从应用程序内为所有受影响的用户正确激发,为什么它的属性应该undefined在这个上下文中呢?

请帮助,谢谢.

Cy *_*nol 4

这是一个奇怪的问题。正如您发现的那样,Laravel 不会$user 在该对象本身上设置属性,因此必须涉及其他内容。以下是我对这个过程的理解:

  1. Notification::send()NewAsset每个用户的排队通知
  2. 将内部作业出队以获取NewAsset通知 → 发送通知
  3. 火灾NotificationSent事件→入NotificationListener队处理程序

这里似乎发生错误:

  1. 处理程序的内部作业NotificationListener出队 → 处理事件
  2. 调度作业SendEmail[→ 入队 if ShouldQueue]
  3. SendEmail[如果→则使作业出列ShouldQueue] 发送通知电子邮件

正如您所看到的,在将通知作业入队和出队时,会进行大量的序列化和反序列化操作。看起来框架正在尝试在从队列中$user反序列化事件时设置属性NotificationSent,但是如果没有完整的堆栈跟踪,很难从您的问题中看出,并且我不确定在$user没有更多可见性的情况下添加到序列化数据中的内容代码。

以下是一些可以尝试的调试建议:

重新启动队列工作程序:

队列工作程序启动后,如果自动加载器已导入文件,则 PHP 进程不会从磁盘重新加载对源代码的更改。似乎有人将$user属性添加到对象但没有重新启动工作程序,因此它从未接受更改。在开发过程中,只要可排队项目的代码发生更改,我们就需要重新启动队列工作程序。部署到生产环境时,最好在部署过程中重新启动队列工作线程。

或者,可以使用该artisan queue:listen命令而不是queue:work在开发期间使用。此模式会为每个作业重新启动整个框架。

设置:QUEUE_DRIVERsync

这会阻止框架的事件系统序列化事件数据。如果通知电子邮件发送时没有任何错误,那么我们就知道某处的自定义代码正在$user向事件添加属性。

检查序列化队列数据:

从您的应用程序使用哪个队列驱动程序的问题中尚不清楚。如果您 使用sync,我们可以查看队列中的待处理作业以尝试查找差异(在数据库、Redis 等中)。

  1. 停止所有队列工作人员。
  2. 通过应用程序触发通知。
  3. 运行php artisan queue:work --once以手动处理一项作业,直到排队的作业运行并触发NotificationSent事件。
  4. 检查队列中创建的作业来处理NotificationSent事件

我们还可以使用这种方法dd()在队列作业期间转储数据,因为artisan queue:work --once在前台运行。

不要将NotificationSent事件处理程序排入队列:

由于通知已配置为在排队后台作业中处理,因此我们不一定需要将通知事件处理程序排入队列。尝试删除该ShouldQueue接口,看看是否可以解决问题。

正如其他评论者提到的,使用 Laravel 的邮件通知可以更好地解决这个问题,它完全不需要单独的NotificationSent事件处理程序。