laravel 模型事件监听

所有支持的模型事件
在 Eloquent 模型类上进行查询、插入、更新、删除操作时,会触发相应的模型事件(关于事件我们后面会单独讲),不管你有没有监听它们。这些事件包括:

- retrieved:获取到模型实例后触发
- creating:插入到数据库前触发
- created:插入到数据库后触发
- updating:更新到数据库前触发
- updated:更新到数据库后触发
- saving:保存到数据库前触发(插入/更新之前,无论插入还是更新都会触发)
- saved:保存到数据库后触发(插入/更新之后,无论插入还是更新都会触发)
- deleting:从数据库删除记录前触发
- deleted:从数据库删除记录后触发
- restoring:恢复软删除记录前触发
- restored:恢复软删除记录后触发

注:批量更新时不会触发相应事件,因为是直接走查询构建器完成的,绕过了模型方法。


通过订阅者监听模型事件
如果要通过自定义监听器监听模型事件,需要先创建对应的事件类,然后将 Eloquent 支持的模型事件与自定义的事件类建立映射关系,最后将事件类注册到监听器类中,从而完成模型事件监听闭环。

所以,我们先来创建自定义的事件类,这里我们以删除模型为例进行演示,分别定义一个删除前事件类和删除后事件类。我们通过 Artisan 命令来完成事件类初始化:

php artisan make:event UserDeleting
php artisan make:event UserDeleted

然后在这两个事件类中都添加 $user 属性并在构造函数中传入:

// app/Events/UserDeleted.php
// app/Events/UserDeleting.php

public $user;

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

在 User 模型类中建立模型事件与自定义事件类的映射,这可以通过 $dispatchesEvents 属性来完成:

protected $dispatchesEvents = [
    'deleting' => UserDeleting::class,
    'deleted' => UserDeleted::class
];

这样,当我们触发 deleting 和 deleted 事件时,底层会将其转化为触发 UserDeleting 和 UserDeleted 事件。

最后,我们还要监听上述自定义的事件类,我们可以通过在 EventServiceProvider 的 listen 属性中为每个事件绑定对应的监听器类,但是学院君更喜欢通过为某个模型类创建一个事件订阅者类来统一处理该模型中的所有事件。在 app/Listeners 目录下创建一个 UserEventSubscriber.php 文件作为订阅者类,编写代码如下

?php

namespace App\Listeners;

use App\Events\UserDeleted;
use App\Events\UserDeleting;
use Illuminate\Support\Facades\Log;

class UserEventSubscriber
{
    /**
     * 处理用户删除前事件
     */
    public function onUserDeleting($event) {
        Log::info('用户即将删除[' . $event->user->id . ']:' . $event->user->name);
    }

    /**
     * 处理用户删除后事件
     */
    public function onUserDeleted($event) {
        Log::info('用户已经删除[' . $event->user->id . ']:' . $event->user->name);
    }

    /**
     * 为订阅者注册监听器
     *
     * @param  Illuminate\Events\Dispatcher  $events
     */
    public function subscribe($events)
    {
        $events->listen(
            UserDeleting::class,
            UserEventSubscriber::class . '@onUserDeleting'
        );

        $events->listen(
            UserDeleted::class,
            UserEventSubscriber::class . '@onUserDeleted'
        );
    }
}

最后,我们在 EventServiceProvider 中注册这个订阅者,使其生效:

// app/Providers/EventServiceProvider.php

protected $subscribe = [
    UserEventSubscriber::class
];

通过观察者监听模型事件
针对模型事件这种特殊的事件类型,Laravel 还为我们提供了观察者类来处理模型事件的监听。观察者可以看作是上述订阅者处理模型事件的简化版本,我们不需要自定义事件类,不需要建立映射关系,只需要在观察者类中将需要监听的事件定义为同名方法,并在相应方法中编写业务处理代码即可。当某个模型事件触发时,Eloquent 底层会去该模型上注册的观察者类中通过反射查找是否定义了对应的方法,如果定义了则执行相应的逻辑,否则忽略。

下面我们以 saving 和 saved 事件为例演示如何通过观察者监听模型事件。

首先,我们通过 Artisan 命令初始化针对 User 模型的观察者

php artisan make:observer UserObserver --model=User

默认生成的 UserObserver 会为 created、 updated、deleted、restored、forceDeleted(强制删除) 事件定义一个空方法:

<?php

namespace App\Observers;

use App\User;

class UserObserver
{
    /**
     * Handle the user "created" event.
     *
     * @param  \App\User  $user
     * @return void
     */
    public function created(User $user)
    {
        //
    }

    /**
     * Handle the user "updated" event.
     *
     * @param  \App\User  $user
     * @return void
     */
    public function updated(User $user)
    {
        //
    }

    /**
     * Handle the user "deleted" event.
     *
     * @param  \App\User  $user
     * @return void
     */
    public function deleted(User $user)
    {
        //
    }

    /**
     * Handle the user "restored" event.
     *
     * @param  \App\User  $user
     * @return void
     */
    public function restored(User $user)
    {
        //
    }

    /**
     * Handle the user "force deleted" event.
     *
     * @param  \App\User  $user
     * @return void
     */
    public function forceDeleted(User $user)
    {
        //
    }
}

写入逻辑

<?php

namespace App\Observers;

use App\User;
use Illuminate\Support\Facades\Log;

class UserObserver
{
    public function saving(User $user)
    {
        Log::info('即将保存用户到数据库[' . $user->id . ']' . $user->name);
    }

    public function creating(User $user)
    {
        Log::info('即将插入用户到数据库[' . $user->id . ']' . $user->name);
    }

    public function updating(User $user)
    {
        Log::info('即将更新用户到数据库[' . $user->id . ']' . $user->name);
    }

    public function updated(User $user)
    {
        Log::info('已经更新用户到数据库[' . $user->id . ']' . $user->name);
    }

    public function created(User $user)
    {
        Log::info('已经插入用户到数据库[' . $user->id . ']' . $user->name);
    }

    public function saved(User $user)
    {
        Log::info('已经保存用户到数据库[' . $user->id . ']' . $user->name);
    }
}

编写好观察者后,需要将其注册到 User 模型上才能生效,我们可以在 EventServiceProvider 的 boot 方法中完成该工作:

public function boot()
{
    parent::boot();

    User::observe(UserObserver::class);

    ...
}

转自https://laravelacademy.org/post/9713.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容

  • Laravel框架一:原理机制篇 Laravel作为在国内国外都颇为流行的PHP框架,风格优雅,其拥有自己的一些特...
    Mr_Z_Heng阅读 3,674评论 0 13
  • Laravel 学习交流 QQ 群:375462817 本文档前言Laravel 文档写的很好,只是新手看起来会有...
    Leonzai阅读 7,848评论 2 12
  • 事件 简介 laravel 的事件提供了一种简单的观察者实现。它允许你在应用中进行订阅和监听事件。事件类通常都是存...
    Dearmadman阅读 3,569评论 0 3
  • Laravel 模型事件允许你监听模型生命周期内的多个关键点,甚至可以在阻止一个模型的保存或者删除。 Larave...
    summerbluet阅读 1,278评论 0 4
  • 安装模块如不指定版本号 默认会安装最新的版本 这个命令会在当前目录生成一个package.json文件,这个文件中...
    Cola丶ZYQ阅读 1,242评论 0 2