Laravel 5.5 Horizon:队列事件监听器自定义任务标签问题
解决Horizon队列事件监听器自定义任务标签无法获取模型数据的问题
我之前也踩过这个坑!Horizon文档里的示例是针对普通队列任务的,直接在构造函数注入模型的方式并不适用于队列事件监听器,核心原因是两者的生命周期完全不一样:
普通队列任务在入队时会序列化模型,构造函数注入能直接拿到对应实例;但事件监听器的构造函数是在监听器被实例化(任务刚入队)时执行的,这时候事件实例还没被传递进来,自然拿不到你需要的模型数据。
正确的实现方式
你需要在监听器的handle()方法中接收事件实例,把它存到监听器的属性里,再在tags()方法中使用这个属性来获取模型数据:
1. 事件监听器代码
namespace App\Listeners; use App\Events\OrderShipped; use Illuminate\Contracts\Queue\ShouldQueue; class SendShipmentNotification implements ShouldQueue { // 定义属性存储事件实例 protected $event; /** * 处理事件 */ public function handle(OrderShipped $event) { // 把当前事件实例赋值给属性 $this->event = $event; // 这里写你的监听器业务逻辑 // 比如发送通知、更新订单状态等 } /** * 定义Horizon任务标签 */ public function tags() { // 通过事件实例获取模型数据生成标签 return [ 'order:'.$this->event->order->id, 'customer:'.$this->event->order->customer_id ]; } }
2. 确保事件类正确传递模型
你的事件类需要包含对应的模型属性,并且在构造时传入模型实例:
namespace App\Events; use App\Models\Order; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; class OrderShipped { use Dispatchable, SerializesModels; // 公开属性,让监听器可以直接访问 public $order; public function __construct(Order $order) { $this->order = $order; } }
为什么之前的方法不行?
Horizon文档里的示例是给普通队列任务用的,比如这样的任务:
namespace App\Jobs; use App\Models\Order; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; class ProcessOrder implements ShouldQueue { protected $order; public function __construct(Order $order) { $this->order = $order; } public function handle() { // 处理订单逻辑 } public function tags() { return ['order:'.$this->order->id]; } }
这种任务在入队时会把Order模型序列化,构造函数能直接拿到实例;但事件监听器的核心是处理事件对象,模型是包含在事件里的,所以必须先拿到事件,才能拿到模型。
按照上面的方式修改后,你就能在Horizon的任务列表里看到带有自定义模型ID的标签了!
内容的提问来源于stack exchange,提问作者Wonka
相关产品推荐
相关产品推荐

