返回顶部

解析Laravel事件系统的使用方法

[复制链接]
supermanLv.2 显示全部楼层 发表于 2021-10-27 18:06:01 |阅读模式 打印 上一主题 下一主题

Laravel 事件系统用法总结

Laravel 的事件提供了一个简单的观察者实现,能够订阅和监听应用中发生的各种事件。事件类保存在 app/Events 目录中,而这些事件的的监听器则被保存在 app/Listeners 目录下。这些目录只有当你使用 Artisan 命令来生成事件和监听器时才会被自动创建。

事件机制是一种很好的应用解耦方式,因为一个事件可以拥有多个互不依赖的监听器。例如,如果你希望每次订单发货时向用户发送一个 Slack 通知。你可以简单地发起一个 OrderShipped 事件,让监听器接收之后转化成一个 Slack 通知,这样你就可以不用把订单的业务代码跟 Slack 通知的代码耦合在一起了。

生成一个事件类

比如通过 artisan 命令生成一个 UserLogin 事件:
  1. php artisan make:event UserLogin
复制代码


在 app/Events 中就会自动生成一个 UserLogin.php 文件,内容不多,如下:

  1.   

  2. namespace App\Events;

  3.   

  4. use Illuminate\Broadcasting\Channel;

  5. use Illuminate\Queue\SerializesModels;

  6. use Illuminate\Broadcasting\PrivateChannel;

  7. use Illuminate\Broadcasting\PresenceChannel;

  8. use Illuminate\Broadcasting\InteractsWithSockets;

  9. use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

  10.   

  11. class UserLogin

  12. {

  13.     use InteractsWithSockets, SerializesModels;

  14.   

  15.     /**

  16.      * Create a new event instance.

  17.      *

  18.      * @return void

  19.      */

  20.     public function __construct()

  21.     {

  22.         //

  23.     }

  24.   

  25.     /**

  26.      * Get the channels the event should broadcast on.

  27.      *

  28.      * @return Channel|array

  29.      */

  30.     public function broadcastOn()

  31.     {

  32.         return new PrivateChannel('channel-name');

  33.     }

  34. }
复制代码


定义监听器

一个事件可以被一个或多个监听器监听,也就是观察者模式,我们可以定义多个监听器,当这个事件发生,执行一系列逻辑。

在 EventServiceProvider 的 $listen 中可以定义事件和监听器,如下:
  1. protected $listen = [

  2.     'App\Events\UserLogin' => [

  3.         'App\Listeners\DoSomething1',

  4.         'App\Listeners\Dosomething2',

  5.     ],

  6. ];
复制代码



然后执行 artisan 命令,就可以自动在 app/Listeners 目录生成监听器。
  1. php artisan event:generate
复制代码


可以看到 app/Listeners 目录多了 DoSomething1.php 和 DoSomething2.php 两个文件,我们看看其中一个内容:
  1. ?php

  2.   

  3. namespace App\Listeners;

  4.   

  5. use App\Events\UserLogin;

  6. use Illuminate\Queue\InteractsWithQueue;

  7. use Illuminate\Contracts\Queue\ShouldQueue;

  8.   

  9. class DoSomething1

  10. {

  11.     /**

  12.      * Create the event listener.

  13.      *

  14.      * @return void

  15.      */

  16.     public function __construct()

  17.     {

  18.         //

  19.     }

  20.   

  21.     /**

  22.      * Handle the event.

  23.      *

  24.      * @param  UserLogin  $event

  25.      * @return void

  26.      */

  27.     public function handle(UserLogin $event)

  28.     {

  29.         info('do something1');

  30.     }

  31. }
复制代码


在两个监听器的 handle 方法中我们打印一个日志来测试一下,如代码 handle 方法所示。

分发和触发事件

我们在某个控制器的方法中来分发事件,也就是触发事件,看监听器是否正常工作。

就是一句话:
  1. event(new UserLogin());
复制代码


然后我们请求这个控制器,观察日志,发现打印了日志:
  1. [2018-06-17 10:04:29] local.INFO: do something1 [2018-06-17 10:04:29] local.INFO: do something2
复制代码

那么这个事件-监听机制就正常工作了。

队列异步处理

如果某个监听器需要执行的操作比较慢,可以放到消息队列进行异步处理。

比如把上面的 DoSomething1 改成需要放入队列的,只需要 implements ShoulQueue 接口。
  1. class DoSomething1 implements ShouldQueue
复制代码

也可以指定队列驱动,如下代码。
  1. /**

  2.      * 任务应该发送到的队列的连接的名称

  3.      *

  4.      * @var string|null

  5.      */

  6.     public $connection = 'redis';

  7.   

  8.     /**

  9.      * 任务应该发送到的队列的名称

  10.      *

  11.      * @var string|null

  12.      */

  13.     public $queue = 'listeners';
复制代码

我们再次执行控制器方法。

日志里没有打印 do something1,只有 do something2,但是在 redis 队列里发现了一个名为 queues:default 的列表。
  1. {"job":"Illuminate\\Events\\CallQueuedHandler@call","data":{"class":"App\\Listeners\\DoSomething1","method":"handle","data":"a:1:{i:0;O:20:"App\\Events\\UserLogin":1:{s:6:"socket";N;}}"},"id":"3D7VDUwueYGtUvsazicWsifwWQxnnLID","attempts":1}
复制代码

这个时候需要使用 php artisan queue:work 执行队列任务,才是真正执行 DoSomething1 这个监听器的 handle 方法。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则