Laravel 通知事件侦听器未定义 属性
Laravel Notifications Event Listener Undefined Property
我有以下错误:
Undefined property:
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));
}
}
我不明白这个未定义的 属性,尤其是这一行。我怎样才能从这里dd()
?我尝试记录 $event
但无法记录,只收到此错误。
我的通知在应用程序中工作得很好,我只想要一封电子邮件,这就是为什么我有这个 event-listener/job。
谢谢。
编辑
发送通知的存储库代码如下:
public function notify($asset)
{
$users = User::where("id","!=",Auth::user()->id)->get();
Notification::send($users, new NewAsset($asset));
}
Notification
class 的分机如下:
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
];
}
}
编辑 2
如果有人可以建议此时如何进行一些错误检查,那将对以后的发展有所帮助。因为代码在服务器上是异步的,所以它不会将数据返回给客户端,当我尝试将它返回到 Log
时,它似乎在陷入错误之前并没有这样做。
在这种情况下我该如何进行调试?
我查看了框架的 source code,但不知道 $user 属性 的来源。我假设它与 $event->notifiable
绑定到 User
模型有关,但如果它从应用程序内为所有受影响的用户正确触发,为什么它的 属性 是 undefined
在这种情况下?
请帮忙,谢谢。
这是一个奇怪的问题。正如您自己发现的那样,Laravel 并未在该对象本身上设置 $user
属性,因此必须涉及其他内容。这是我对这个过程的理解:
Notification::send()
→ 为每个用户排队 NewAsset
通知
NewAsset
通知的内部作业出队 → 发送通知
- 触发
NotificationSent
事件 → 入队 NotificationListener
处理程序
此处似乎出现错误:
- 将
NotificationListener
处理程序的内部作业出队 → 处理事件
- 为
SendEmail
调度作业 [→ 如果 ShouldQueue
] 入队
- [如果
ShouldQueue
将 SendEmail
的作业出队 →] 发送通知电子邮件
如您所见,在为通知作业入队和出队时,会进行大量序列化和反序列化。似乎框架在反序列化队列中的 NotificationSent
事件时试图设置 $user
属性,但是如果没有完整的堆栈跟踪,很难从你的问题中分辨出来,我在没有更多代码可见性的情况下,我不确定是什么将 $user
添加到序列化数据中。
这里有一些可以尝试的调试建议:
重启队列工作者:
队列工作程序启动后,如果自动加载器已导入文件,PHP 进程不会从磁盘重新加载对源代码的更改。似乎有人将 $user
属性 添加到对象但没有重新启动工作人员,因此它从未接受更改。在开发过程中,每当可排队项的代码更改时,我们都需要重新启动队列工作程序。部署到生产环境时,最好在部署过程中重新启动队列工作程序。
或者,在开发过程中使用 artisan queue:listen
命令而不是 queue:work
。此模式为每个作业重新启动整个框架。
将QUEUE_DRIVER
设置为sync
:
这会阻止框架的事件系统序列化事件数据。如果通知电子邮件发送没有任何错误,那么我们就知道某处的自定义代码正在向事件添加 $user
属性。
检查序列化队列数据:
从您的应用程序使用哪个队列驱动程序的问题中不清楚。如果您 而不是 使用 sync
,我们可以查看队列中的待处理作业以尝试找出差异(在数据库、Redis 等中)。
- 停止所有队列工作器。
- 通过应用程序触发通知。
- 运行
php artisan queue:work --once
手动处理一项作业,直到排队的作业运行并触发 NotificationSent
事件。
- 检查队列中创建的作业以处理
NotificationSent
事件
我们也可以使用这种方法在队列作业期间使用 dd()
转储数据,因为 artisan queue:work --once
在前台运行。
不要将 NotificationSent
事件处理程序加入队列:
因为通知已经配置为在排队的后台作业中处理,所以我们不一定需要将通知事件处理程序也加入队列。尝试删除 ShouldQueue
接口以查看是否可以解决问题。
正如其他评论者提到的,使用 Laravel 的 Mail Notifications 可以更好地解决这个问题,它完全不需要单独的 NotificationSent
事件处理程序。
我有以下错误:
Undefined property: 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));
}
}
我不明白这个未定义的 属性,尤其是这一行。我怎样才能从这里dd()
?我尝试记录 $event
但无法记录,只收到此错误。
我的通知在应用程序中工作得很好,我只想要一封电子邮件,这就是为什么我有这个 event-listener/job。
谢谢。
编辑
发送通知的存储库代码如下:
public function notify($asset)
{
$users = User::where("id","!=",Auth::user()->id)->get();
Notification::send($users, new NewAsset($asset));
}
Notification
class 的分机如下:
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
];
}
}
编辑 2
如果有人可以建议此时如何进行一些错误检查,那将对以后的发展有所帮助。因为代码在服务器上是异步的,所以它不会将数据返回给客户端,当我尝试将它返回到 Log
时,它似乎在陷入错误之前并没有这样做。
在这种情况下我该如何进行调试?
我查看了框架的 source code,但不知道 $user 属性 的来源。我假设它与 $event->notifiable
绑定到 User
模型有关,但如果它从应用程序内为所有受影响的用户正确触发,为什么它的 属性 是 undefined
在这种情况下?
请帮忙,谢谢。
这是一个奇怪的问题。正如您自己发现的那样,Laravel 并未在该对象本身上设置 $user
属性,因此必须涉及其他内容。这是我对这个过程的理解:
Notification::send()
→ 为每个用户排队NewAsset
通知NewAsset
通知的内部作业出队 → 发送通知- 触发
NotificationSent
事件 → 入队NotificationListener
处理程序
此处似乎出现错误:
- 将
NotificationListener
处理程序的内部作业出队 → 处理事件 - 为
SendEmail
调度作业 [→ 如果ShouldQueue
] 入队 - [如果
ShouldQueue
将SendEmail
的作业出队 →] 发送通知电子邮件
如您所见,在为通知作业入队和出队时,会进行大量序列化和反序列化。似乎框架在反序列化队列中的 NotificationSent
事件时试图设置 $user
属性,但是如果没有完整的堆栈跟踪,很难从你的问题中分辨出来,我在没有更多代码可见性的情况下,我不确定是什么将 $user
添加到序列化数据中。
这里有一些可以尝试的调试建议:
重启队列工作者:
队列工作程序启动后,如果自动加载器已导入文件,PHP 进程不会从磁盘重新加载对源代码的更改。似乎有人将 $user
属性 添加到对象但没有重新启动工作人员,因此它从未接受更改。在开发过程中,每当可排队项的代码更改时,我们都需要重新启动队列工作程序。部署到生产环境时,最好在部署过程中重新启动队列工作程序。
或者,在开发过程中使用 artisan queue:listen
命令而不是 queue:work
。此模式为每个作业重新启动整个框架。
将QUEUE_DRIVER
设置为sync
:
这会阻止框架的事件系统序列化事件数据。如果通知电子邮件发送没有任何错误,那么我们就知道某处的自定义代码正在向事件添加 $user
属性。
检查序列化队列数据:
从您的应用程序使用哪个队列驱动程序的问题中不清楚。如果您 而不是 使用 sync
,我们可以查看队列中的待处理作业以尝试找出差异(在数据库、Redis 等中)。
- 停止所有队列工作器。
- 通过应用程序触发通知。
- 运行
php artisan queue:work --once
手动处理一项作业,直到排队的作业运行并触发NotificationSent
事件。 - 检查队列中创建的作业以处理
NotificationSent
事件
我们也可以使用这种方法在队列作业期间使用 dd()
转储数据,因为 artisan queue:work --once
在前台运行。
不要将 NotificationSent
事件处理程序加入队列:
因为通知已经配置为在排队的后台作业中处理,所以我们不一定需要将通知事件处理程序也加入队列。尝试删除 ShouldQueue
接口以查看是否可以解决问题。
正如其他评论者提到的,使用 Laravel 的 Mail Notifications 可以更好地解决这个问题,它完全不需要单独的 NotificationSent
事件处理程序。