所有支持的模型事件

在 Eloquent 模型类上进行查询、插入、更新、删除操作时,会触发相应的模型事件,不管你有没有监听它们。这些事件包括:

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

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

通过监听这些事件,我们可以在 Eloquent 模型实例生命周期的特定阶段执行特定操作。在 Laravel 中我们有多种方式来监听模型事件。

通过静态方法监听模型事件

通过在模型类上调用要监听事件对应的静态方法,一般我们会在某个服务提供者的 boot 方法中完成这项工作,比如 EventServiceProvider。举个例子,假设我们要监听每次获取模型实例的事件并在日志中记录查询到的用户信息,可以这么做:

// app/Providers/EventServiceProvider.php

public function boot()
{
parent::boot();
// 监听模型获取事件
User::retrieved(function ($user) {
Log::info('从模型中获取用户[' . $user->id . ']:' . $user->name);
});
}

上面这段代码中表示我们在 User 模型上监听 retrieved 事件,然后通过一个闭包函数执行对应的处理逻辑,该闭包函数传入参数是模型实例,在处理逻辑中,我们通过 Log 门面记录日志信息。

通过订阅者监听模型事件

①先创建对应的事件类

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

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

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

// app/Events/UserDeleted.php
// app/Events/UserDeleting.php public $user;
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 模型的观察者

laravel5.7以上可以使用以下命令进行创建观察者,laravel5.7以下需要手动创建

php artisan make:observer UserObserver --model=Model/User

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

<?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)
{
//
}
}

可以把前面定义的 retriveddeletingdeleted 事件监听代码迁移过来,也可以将不需监听的事件方法移除,这里我们将编写保存模型时涉及的模型事件,包括 savingcreatingupdatingupdatedcreatedsaved

<?php

namespace App\Observers;

use App\Model\User;
use 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模型的观察者
User::observe(UserObserver::class);
}

结语

关于三种监听 Eloquent 模型事件的方式,如何选择,视情况而定。如果只是监听一两个模型事件,第一种方式比较合适;如果仅仅监听系统支持的模型事件,并且要监听多个模型的多个事件,观察者是最佳选择;如果还要在模型类上监听更多系统模型事件之外的自定义事件,则使用订阅者来监听比较合适。

【laravel】Eloquent 模型事件和监听方式的更多相关文章

  1. Javascript事件模型系列(三)jQuery中的事件监听方式及异同点

    作为全球最知名的js框架之一,jQuery的火热程度堪称无与伦比,简单易学的API再加丰富的插件,几乎是每个前端程序员的必修课.从读<锋利的jQuery>开始,到现在使用jQuery有一年 ...

  2. jQuery中的事件监听方式及异同点

    jQuery中的事件监听方式及异同点 作为全球最知名的js框架之一,jQuery的火热程度堪称无与伦比,简单易学的API再加丰富的插件,几乎是每个前端程序员的必修课.从读<锋利的jQuery&g ...

  3. laravel中事件的监听和订阅

    一.前言 更新员工部门主管的时候,需要重新更新一下缓存,这个会比较耗时.所以计划放到队列中来执行.后来想了想,其实用一下事件监听也能实现.人家都说好,然是我也没感觉到有什么好的. 二.正文 1. 在p ...

  4. Spring笔记(7) - Spring的事件和监听机制

    一.背景 事件机制作为一种编程机制,在很多开发语言中都提供了支持,同时许多开源框架的设计中都使用了事件机制,比如SpringFramework. 在 Java 语言中,Java 的事件机制参与者有3种 ...

  5. nodejs事件的监听与事件的触发

    nodejs事件(Events) 一.事件机制的实现 Node.js中大部分的模块,都继承自Event模块(http://nodejs.org/docs/latest/api/events.html  ...

  6. 深入理解Spring的容器内事件发布监听机制

    目录 1. 什么是事件监听机制 2. JDK中对事件监听机制的支持 2.1 基于JDK实现对任务执行结果的监听 3.Spring容器对事件监听机制的支持 3.1 基于Spring实现对任务执行结果的监 ...

  7. Spring Boot(六)自定义事件及监听

    事件及监听并不是SpringBoot的新功能,Spring框架早已提供了完善的事件监听机制,在Spring框架中实现事件监听的流程如下: 自定义事件,继承org.springframework.con ...

  8. Spring Boot 事件和监听

    Application Events and Listeners 1.自定义事件和监听 1.1.定义事件 package com.cjs.boot.event; import lombok.Data; ...

  9. uniapp仿h5+fire自定义事件触发监听

    仿h5+fire自定义事件触发监听 uni-app调用 event.js 源码记录(点击查看) 1.js下载地址 [event.js](https://ext.dcloud.net.cn/plugin ...

随机推荐

  1. RocketMQ入门到入土(一)新手也能看懂的原理和实战!

    学任何技术都是两步骤: 搭建环境 helloworld 我也不例外,直接搞起来. 一.RocketMQ的安装 1.文档 官方网站 http://rocketmq.apache.org GitHub h ...

  2. 四. django template模版

    往前端浏览器pull一些字符串,这些字符串是一些数据, 那如果想让这些数据按我们的某种格式美化一点/增加样式/图片,就需要用到django提供的模版--模版就是为了让数据看起更美观. 加载模版 dja ...

  3. Spring事务的传播级别

    一.简单说明 传播属性 描述 PROPAGATION_REQUIRED 如果当前没有事务,就创建一个事务,如果当前存在事务,就加入该事务. PROPAGATION_REQUIRED_NEW 当前的方法 ...

  4. C++中string转换为char*类型返回后乱码问题

    问题来源: 在写二叉树序列化与反序列化时发现序列化函数为char* Serialize1(TreeNode *root)  其函数返回类型为char*,但是我在实现的过程中为了更方便的操作添加字符串使 ...

  5. 神奇的建图方式(Tarjan)——小z玩游戏

    原题来自与:洛谷 P5676(GZOI2017)  链接: https://www.luogu.com.cn/problem/P5676 题面: 题意比较明显,如果已经建好了边,那么跑个Tarjan ...

  6. asp.net mvc企业实战技能汇总

  7. .net面试技术要点总结

    [整理]待毕业.Net码农就业求职储备   本文题目来源于互联网,仅供即将从学校毕业的.Net码农(当然,我本人也是菜逼一个)学习之用.当然,学习了这些题目不一定会拿到offer,但是针对就业求职做些 ...

  8. 使用virtualBox 创建虚拟机

    第一次使用感觉并没有VMware好用,尤其是鼠标在虚拟机和宿主机之间切换的时候很烦,需要按键盘右边ctrl虽然有提示right ctrl但是第一次使用硬是折腾了好半天.感觉不记录一下对不起这个下午. ...

  9. redis(五):Redis 键(key)(python)

    # -*- coding: utf-8 -*- import redis #这个redis 连接不能用,请根据自己的需要修改 r =redis.Redis(host="123.516.174 ...

  10. linux专题(六):Vim编辑器

    http://dwz.date/UDf 什么是Vim编辑器 Vim是从 vi 发展出来的一个文本编辑器.代码补完.编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用. 简单的来说, vi 是 ...