记录下学习笔记(Laravel 中的事件监听)

1.什么是“事件监听“?

从字面上就可以看出来,无非就是监听一个事件。

2.使用场景

例句一个物流发货的场景:我有个小程序商城,用户下单后需要在后台发货,发完货后我想在微信发送个模块通知提示用户,我想了想用户不登录微信或者把消息提示关闭了,那岂不是不能实时通知用户已经发货了,我决定再加个短信通知用户。有了模块通知,短信通知后我还嫌不够...然后我继续加.... 通常我们会这么写:

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class OrderController extends Controller
{
    public function sendGoods()
    {
        //@todo:发货逻辑
        //@todo:模块通知逻辑
        //@todo:短信通知逻辑
        //@todo:等等....
    }
}

这样写不是不可以,但是逻辑功能越来越多,控制器只会变得臃肿起来,后期不便于维护。这时候可能会有人说,那我可以封装起来啊,是的,你可以封装起来,然后就可以用简短的代码来实现。但是实际项目中,会涉及多人开发,这样就不方便了。所以推荐使用laravel自带的“事件监听“...

3.使用”事件监听"优化代码

3.1 打开终端->切换到项目根目录->使用artisan命令创建事件监听文件

php artisan make:event OrderEvent

执行完命令,发现 app/Events 目录下多了个 OrderEvent.php 文件

记录下学习笔记(Laravel 中的事件监听)

我们可以打开看看...

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class OrderEvent
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('channel-name');
    }
}

简单的修改下构造函数,因为到时候我们可能会 传入 购买商品的 用户

<?php

namespace App\Events;

use App\User;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class OrderEvent
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $user;
    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('channel-name');
    }
}

3.2 绑定事件

打开 app/Providers/EventServiceProvider.php 文件,找到 成员属性 listen下:

    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
    ];

把事件关联起来,修改为:

    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
        'App\Events\OrderEvent' => [
            'App\Listeners\sendModel',
            'App\Listeners\sendPhone',
        ]
    ];

接着打开终端,执行 artisan 命令 生成 监听文件

php artisan event:generate

然后我们可以在 app/Listeners 文件下发现多了两个文件

记录下学习笔记(Laravel 中的事件监听)

打开这两个文件,依次修改为:

sendModel.php:

<?php

namespace App\Listeners;

use App\Events\OrderEvent;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

class sendModel
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  OrderEvent  $event
     * @return void
     */
    public function handle(OrderEvent $event)
    {
        $user = $event->user; // @todo: 当前用户
        //@todo:发送消息模板逻辑
        dump('发送消息模板成功');
    }
}

sendPhone.php:

<?php

namespace App\Listeners;

use App\Events\OrderEvent;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

class sendPhone
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  OrderEvent  $event
     * @return void
     */
    public function handle(OrderEvent $event)
    {
        $user = $event->user; // @todo: 当前用户
        //@todo:发送短信消息
        dump('发送短信消息成功');
    }
}

3.3 最后我们再打开 OrderController.php 修改为:

<?php
namespace App\Http\Controllers;
use App\Events\OrderEvent;
use App\User;
use Illuminate\Http\Request;
class OrderController extends Controller
{
    public function sendGoods()
    {
        $user = User::find(1);
        //@todo:发货逻辑
        dump('发货成功!!');
        event(new OrderEvent($user));
    }
}

3.4 绑定路由

Route::get('/sendGoods','OrderController@sendGoods');

3.5 访问路由结果:

记录下学习笔记(Laravel 中的事件监听)

4. 总结

这样是不是简单,便于维护了许多呢... 还不会的小伙伴赶紧去试试吧!如果对你有帮助,请给个赞,谢谢!

个人博客

原文

本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 2年前 自动加精
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 10
wanghan

快下班了,明天再消化消化😋

4年前 评论
Natural

@wanghan 第一次收到评论,好激动! :blush:

4年前 评论
wanghan

@NaturalGao O(∩_∩)O

4年前 评论
wanghan

@NaturalGao 今天实验了一下感觉挺好的,可是用event(new event)的方式不是很优雅

4年前 评论
Natural

@wanghan 那你有推荐的写法吗

4年前 评论

高内聚,低耦合,赞

4年前 评论
wanghan

@NaturalGao 没有没有,我很菜的

4年前 评论
nfangxu

订单发货成功的主体应该是 Order , 事件中注入的 Model 应该由 User 修改为 Order

4年前 评论
nfangxu

@wanghan 稍微优雅一点的方案有一个, 可以参考哈!

routes/web.php

Route::post('{order}/sendGoods', 'OrderController@sendGoods');

App\Models\Order


namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Order extends Model
{
    protected $dispatchesEvents = [
        'sended' => OrderSended::class, # 发货成功事件绑定
    ];

    public function sendGoods()
    {
        // 发货操作...

        // 触发事件
        $this->fireModelEvent('sended');
    }

    // 关联用户
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

App\Http\Controllers\OrderController

    // others

    // 发货
    public function sendGoods(Order $order)
    {
        $order->sendGoods();
    }

App\Events\OrderSended

class OrderSended
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $order;

    public function __construct(Order $order)
    {
        $this->order = $order;
    }
}

只写到事件抛出, 之后的处理参考楼主的就可以了
大佬勿喷, 不喜勿喷

4年前 评论

这样是不是每个涉及到通知的业务都得写监听、通知类,会不会太多了😂

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!