在 Laravel 中,除了使用 dispatch
辅助函数通过 Illuminate\Bus\Dispatcher
显式推送队列任务外,还可以通过事件监听的方式隐式进行队列任务推送,在这个场景下,事件监听器实际上扮演了「任务类」的角色。
还是以文章浏览数更新为例。开始之前,我们先来给大家演示下事件监听和处理的基本实现。
事件监听基本使用
首先创建一个文章浏览事件类 PostViewed
:
sail artisan make:event PostViewed
然后编写这个事件类代码如下:
<?php namespace App\Events;use App\Models\Post;use Illuminate\Broadcasting\Channel;use Illuminate\Broadcasting\InteractsWithSockets;use Illuminate\Broadcasting\PrivateChannel;use Illuminate\Foundation\Events\Dispatchable;use Illuminate\Queue\SerializesModels;class PostViewed{
use Dispatchable, InteractsWithSockets, SerializesModels;public Post $post;/**
* Create a new event instance.
*
* @param Post $post
*/public function __construct(Post $post){
$this->post = $post;
}/**
* Get the channels the event should broadcast on.
*
* @return Channel|array
*/public function broadcastOn(){
return new PrivateChannel('channel-name');
}
}
事件类的作用就是装载事件相关的数据,这里我们引入了 Post
模型实例,以便在事件监听器中进行相应的处理,事件类中默认还有一个 broadcastOn
表示事件的广播通道,我们在后面介绍广播时再详细介绍这个方法。
有了事件之后,还要创建一个监听这个事件的处理器:
php artisan make:listener IncreasePostViews
编写处理器代码如下:
<?php namespace App\Listeners;use App\Events\PostViewed;use Illuminate\Support\Facades\Redis;class IncreasePostViews{
/**
* Create the event listener.
*
* @return void
*/public function __construct(){
//
}/**
* Handle the event.
*
* @param PostViewed $event
* @return void
*/public function handle(PostViewed $event){
if ($event->post->increment('views')) {
Redis::zincrby('popular_posts', 1, $event->post->id);
}
}
}
我们将之前队列任务类的 handle
方法代码搬到了事件监听器的 handle
方法中,作为文章浏览事件发生时的处理逻辑。
要建立事件与监听器之间的映射关系,保证事件发生时可以通过监听器对其进行处理,需要在 EventServiceProvider
中维护一个监听数组配置:
protected $listen = [
...
PostViewed::class => [
IncreasePostViews::class
],
];
以事件做键,事件监听器做值,表示一个事件可以同时被多个事件监听器监听和处理。
Laravel 还提供了事件自动发现功能,不过考虑到反射性能较差,我们这里还是使用传统的手动注册方式。
这样一来,当我们在 PostController
的 show
方法中触发 PostViewed
事件时:
// 浏览文章
public function show($id){
$post = $this->postRep