[ Laravel 5.2 文档 ] 服务 -- 事件

php中文网
发布: 2016-06-20 12:37:59
原创
1223人浏览过

1、简介

laravel事件提供了简单的观察者模式实现,允许你订阅和监听应用中的事件。事件类通常存放在 app/events目录,监听器存放在 app/listeners。

2、注册事件/监听器

Laravel 自带的 EventServiceProvider为事件注册提供了方便之所。其中的 listen属性包含了事件(键)和对应监听器(值)数组。如果应用需要,你可以添加多个事件到该数组。例如,让我们添加 PodcastWasPurchased事件:

/** * 事件监听器映射 * * @var array */protected $listen = [    'AppEventsPodcastWasPurchased' => [        'AppListenersEmailPurchaseConfirmation',    ],];
登录后复制

2.1 生成事件/监听器类

当然,手动为每个事件和监听器创建文件是很笨重的,取而代之地,我们可见简单添加监听器和事件到 EventServiceProvider然后使用 event:generate命令。该命令将会生成罗列在 EventServiceProvider中的所有事件和监听器。当然,已存在的事件和监听器不会被创建:

php artisan event:generate
登录后复制

2.2 手动注册事件

一般我们需要将事件注册到 EventServiceProvider的 $listen数组,此外,我们还可以使用 Event门面或者 IlluminateContractsEventsDispatcher契约的具体实现类作为事件分发器手动注册事件:

/** * Register any other events for your application. * * @param  IlluminateContractsEventsDispatcher  $events * @return void */public function boot(DispatcherContract $events){    parent::boot($events);    $events->listen('event.name', function ($foo, $bar) {        //    });}
登录后复制

使用通配符作为事件监听器

你还可以使用通配符*来注册监听器,从而允许你通过同一个监听器捕获多个事件。通配符监听器接收整个事件数据数组作为参数:

$events->listen('event.*', function (array $data) {    //});
登录后复制

3、定义事件

事件类是一个处理与事件相关的简单数据容器,例如,假设我们生成的 PodcastWasPurchased事件接收一个Eloquent ORM对象:

<?phpnamespace AppEvents;use AppPodcast;use AppEventsEvent;use IlluminateQueueSerializesModels;class PodcastWasPurchased extends Event{    use SerializesModels;    public $podcast;    /**     * 创建新的事件实例     *     * @param  Podcast  $podcast     * @return void     */    public function __construct(Podcast $podcast)    {        $this->podcast = $podcast;    }}
登录后复制

正如你所看到的,该事件类不包含任何特定逻辑,只是一个存放被购买的 Podcast对象的容器,如果事件对象被序列化的话,事件使用的  SerializesModelstrait 将会使用 PHP 的 serialize函数序列化所有 Eloquent 模型。

4、定义监听器

接下来,让我们看看我们的示例事件的监听器,事件监听器在 handle方法中接收事件实例, event:generate命令将会自动在 handle方法中导入合适的事件类和类型提示事件。在 handle方法内,你可以执行任何需要的逻辑以响应事件。

<?phpnamespace AppListeners;use AppEventsPodcastWasPurchased;use IlluminateQueueInteractsWithQueue;use IlluminateContractsQueueShouldQueue;class EmailPurchaseConfirmation{    /**     * 创建事件监听器     *     * @return void     */    public function __construct()    {        //    }    /**     * 处理事件     *     * @param  PodcastWasPurchased  $event     * @return void     */    public function handle(PodcastWasPurchased $event)    {        // Access the podcast using $event->podcast...    }}
登录后复制

你的事件监听器还可以在构造器中类型提示任何需要的依赖,所有事件监听器通过服务容器解析,所以依赖会自动注入:

use IlluminateContractsMailMailer;public function __construct(Mailer $mailer){    $this->mailer = $mailer;}
登录后复制

停止事件继续往下传播

有时候,你希望停止事件被传播到其它监听器,你可以通过从监听器的 handle方法中返回 false来实现。

事件监听器队列

需要将事件监听器放到队列?没有比这更简单的了,只需要让监听器类实现 ShouldQueue接口即可,通过 Artisan 命令 event:generate生成的监听器类已经将接口导入当前命名空间,所有你可以立即拿来使用:

<?phpnamespace AppListeners;use AppEventsPodcastWasPurchased;use IlluminateQueueInteractsWithQueue;use IlluminateContractsQueueShouldQueue;class EmailPurchaseConfirmation implements ShouldQueue{    //}
登录后复制

就是这么简单,当监听器被事件调用,将会使用 Laravel 的队列系统通过队列分发器自动队列化。如果通过队列执行监听器的时候没有抛出任何异常,队列任务在执行完成后被自动删除。

手动访问队列

如果你需要手动访问底层队列任务的 delete和 release方法,在生成的监听器中默认导入的 IlluminateQueueInteractsWithQueuetrait 提供了访问这两个方法的权限:

<?phpnamespace AppListeners;use AppEventsPodcastWasPurchased;use IlluminateQueueInteractsWithQueue;use IlluminateContractsQueueShouldQueue;class EmailPurchaseConfirmation implements ShouldQueue{    use InteractsWithQueue;    public function handle(PodcastWasPurchased $event)    {        if (true) {            $this->release(30);        }    }}
登录后复制

5、触发事件

要触发一个事件,可以使用 Event门面,传递一个事件实例到 fire方法, fire方法会分发事件到所有监听器:

<?phpnamespace AppHttpControllers;use Event;use AppPodcast;use AppEventsPodcastWasPurchased;use AppHttpControllersController;class UserController extends Controller{    /**     * 显示指定用户属性     *     * @param  int  $userId     * @param  int  $podcastId     * @return Response     */    public function purchasePodcast($userId, $podcastId)    {        $podcast = Podcast::findOrFail($podcastId);        // Purchase podcast logic...        Event::fire(new PodcastWasPurchased($podcast));    }}
登录后复制

此外,你还可以使用全局的辅助函数 event来触发事件:

event(new PodcastWasPurchased($podcast));
登录后复制

6、 广播事件

在很多现代 Web 应用中,Web 套接字被用于实现实时更新的用户接口。当一些数据在服务器上被更新,通常一条消息通过 websocket 连接被发送给客户端处理。

为帮助你构建这样的应用,Laravel 让通过 websocket 连接广播事件变得简单。广播 Laravel 事件允许你在服务端和客户端 JavaScript 框架之间共享同一事件名。

6.1 配置

所有的事件广播配置选项都存放在 config/broadcasting.php配置文件中。Laravel 支持多种广播驱动: Pusher、Redis以及一个服务于本地开发和调试的日志驱动。每一个驱动都有一个配置示例。

Calliper 文档对比神器
Calliper 文档对比神器

文档内容对比神器

Calliper 文档对比神器 28
查看详情 Calliper 文档对比神器

广播预备知识

事件广播需要以下两个依赖:

  • Pusher:  pusher/pusher-php-server ~2.0
  • Redis:  predis/predis ~1.0

队列预备知识

在开始介绍广播事件之前,还需要配置并运行一个队列监听器。所有事件广播都通过队列任务来完成以便应用的响应时间不受影响。

6.2 将事件标记为广播

要告诉 Laravel 给定事件应该被广播,需要在事件类上实现 IlluminateContractsBroadcastingShouldBroadcast接口。 ShouldBroadcast接口要求你实现一个方法: broadcastOn。该方法应该返回事件广播“频道”名称数组:

<?phpnamespace AppEvents;use AppUser;use AppEventsEvent;use IlluminateQueueSerializesModels;use IlluminateContractsBroadcastingShouldBroadcast;class ServerCreated extends Event implements ShouldBroadcast{    use SerializesModels;    public $user;    /**     * 创建新的事件实例     *     * @return void     */    public function __construct(User $user)    {        $this->user = $user;    }    /**     * 获取事件广播频道     *     * @return array     */    public function broadcastOn()    {        return ['user.'.$this->user->id];    }}
登录后复制

然后,你只需要和正常一样触发该事件,事件被触发后,一个队列任务将通过指定广播驱动自动广播该事件。

6.3 广播数据

如果某个事件被广播,其所有的 public属性都会按照事件负载自动序列化和广播,从而允许你从 JavaScript 中访问所有 public数据,因此,举个例子,如果你的事件有一个单独的包含 Eloquent 模型的 $user属性,广播负载定义如下:

{    "user": {        "id": 1,        "name": "Jonathan Banks"        ...    }}
登录后复制

然而,如果你希望对广播负载有更加细粒度的控制,可以添加 broadcastWith方法到事件,该方法应该返回你想要通过事件广播的数组数据:

/** * 获取广播数据 * * @return array */public function broadcastWith(){    return ['user' => $this->user->id];}
登录后复制

6.4 自定义事件广播

自定义事件名

默认情况下,广播事件名就是事件类名,因此,如果事件的类名是 AppEventsServerCreated,对应的广播事件名就是 AppEventsServerCreated,你可以通过事件类上的 broadcastAs方法自定义广播事件名:

/** * 获取广播事件名称 * * @return string */public function broadcastAs(){    return 'app.server-created';}
登录后复制

自定义队列

默认情况下,每个被广播的事件都位于配置文件 queue.php中定义的默认队列连接中的默认队列中,你可以通过事件类的 onQueue方法自定义广播事件的队列名称。该方法会返回你期望使用的队列名:

/** * 设置事件所在队列的名称 * * @return string */public function onQueue(){    return 'your-queue-name';}
登录后复制

6.5 消费事件广播

Pusher

你可以通过 Pusher 的 JavaScript SDK 方便地使用 Pusher驱动消费事件广播。例如,让我们从之前的例子中消费 AppEventsServerCreated事件:

this.pusher = new Pusher('pusher-key');this.pusherChannel = this.pusher.subscribe('user.' + USER_ID);this.pusherChannel.bind('App\Events\ServerCreated', function(message) {    console.log(message.user);});
登录后复制

Redis

如果你在使用 Redis 广播,你将需要编写自己的 Redis pub/sub 消费者来接收消息并使用自己选择的 websocket 技术将其进行广播。例如,你可以选择使用 Node 编写的流行的 Socket.io库。

使用 Node 库 socket.io和 ioredis,你可以快速编写事件广播发布所有广播事件:

var app = require('http').createServer(handler);var io = require('socket.io')(app);var Redis = require('ioredis');var redis = new Redis();app.listen(6001, function() {    console.log('Server is running!');});function handler(req, res) {    res.writeHead(200);    res.end('');}io.on('connection', function(socket) {    //});redis.psubscribe('*', function(err, count) {    //});redis.on('pmessage', function(subscribed, channel, message) {    message = JSON.parse(message);    io.emit(channel + ':' + message.event, message.data);});
登录后复制

7、事件订阅者

事件订阅者是指那些在类本身中订阅到多个事件的类,从而允许你在单个类中定义一些事件处理器。订阅者应该定义一个 subscribe方法,该方法中传入一个事件分发器实例:

<?phpnamespace AppListeners;class UserEventListener{    /**     * 处理用户登录事件     */    public function onUserLogin($event) {}    /**     * 处理用户退出事件     */    public function onUserLogout($event) {}    /**     * 为订阅者注册监听器     *     * @param  IlluminateEventsDispatcher  $events     * @return array     */    public function subscribe($events)    {        $events->listen(            'AppEventsUserLoggedIn',            'AppListenersUserEventListener@onUserLogin'        );        $events->listen(            'AppEventsUserLoggedOut',            'AppListenersUserEventListener@onUserLogout'        );    }}
登录后复制

注册一个事件订阅者

订阅者被定义后,可以通过事件分发器进行注册,你可以使用 EventServiceProvider上的 $subcribe属性来注册订阅者。例如,让我们添加 UserEventListener:

<?phpnamespace AppProviders;use IlluminateContractsEventsDispatcher as DispatcherContract;use IlluminateFoundationSupportProvidersEventServiceProvider as ServiceProvider;class EventServiceProvider extends ServiceProvider{    /**     * 事件监听器映射数组     *     * @var array     */    protected $listen = [        //    ];    /**     * 要注册的订阅者     *     * @var array     */    protected $subscribe = [        'AppListenersUserEventListener',    ];}
登录后复制
最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号