【laravel】Eloquent 模型事件和监听方式
所有支持的模型事件
在 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
、 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)
- {
- //
- }
- }
可以把前面定义的 retrived
、deleting
、deleted
事件监听代码迁移过来,也可以将不需监听的事件方法移除,这里我们将编写保存模型时涉及的模型事件,包括 saving
、creating
、updating
、updated
、created
、saved
- <?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 模型事件和监听方式的更多相关文章
- Javascript事件模型系列(三)jQuery中的事件监听方式及异同点
作为全球最知名的js框架之一,jQuery的火热程度堪称无与伦比,简单易学的API再加丰富的插件,几乎是每个前端程序员的必修课.从读<锋利的jQuery>开始,到现在使用jQuery有一年 ...
- jQuery中的事件监听方式及异同点
jQuery中的事件监听方式及异同点 作为全球最知名的js框架之一,jQuery的火热程度堪称无与伦比,简单易学的API再加丰富的插件,几乎是每个前端程序员的必修课.从读<锋利的jQuery&g ...
- laravel中事件的监听和订阅
一.前言 更新员工部门主管的时候,需要重新更新一下缓存,这个会比较耗时.所以计划放到队列中来执行.后来想了想,其实用一下事件监听也能实现.人家都说好,然是我也没感觉到有什么好的. 二.正文 1. 在p ...
- Spring笔记(7) - Spring的事件和监听机制
一.背景 事件机制作为一种编程机制,在很多开发语言中都提供了支持,同时许多开源框架的设计中都使用了事件机制,比如SpringFramework. 在 Java 语言中,Java 的事件机制参与者有3种 ...
- nodejs事件的监听与事件的触发
nodejs事件(Events) 一.事件机制的实现 Node.js中大部分的模块,都继承自Event模块(http://nodejs.org/docs/latest/api/events.html ...
- 深入理解Spring的容器内事件发布监听机制
目录 1. 什么是事件监听机制 2. JDK中对事件监听机制的支持 2.1 基于JDK实现对任务执行结果的监听 3.Spring容器对事件监听机制的支持 3.1 基于Spring实现对任务执行结果的监 ...
- Spring Boot(六)自定义事件及监听
事件及监听并不是SpringBoot的新功能,Spring框架早已提供了完善的事件监听机制,在Spring框架中实现事件监听的流程如下: 自定义事件,继承org.springframework.con ...
- Spring Boot 事件和监听
Application Events and Listeners 1.自定义事件和监听 1.1.定义事件 package com.cjs.boot.event; import lombok.Data; ...
- uniapp仿h5+fire自定义事件触发监听
仿h5+fire自定义事件触发监听 uni-app调用 event.js 源码记录(点击查看) 1.js下载地址 [event.js](https://ext.dcloud.net.cn/plugin ...
随机推荐
- JDK8--06:Stream流
一.描述 Stream流提供了筛选与切片.映射.排序.匹配与查找.归约.收集等功能 筛选与切片: filter:接收lambda,从流中排除某些元素 limit(n):截断流,使其元素不超过n ski ...
- SpringBoot-读取classpath下文件
文章目录 开发过程中,必不可少的需要读取文件,对于打包方式的不同,还会存在一些坑,比如以jar包方式部署时,文件都存在于jar包中,某些读取方式在开发工程中都可行,但是打包后,由于文件被保存在jar中 ...
- 整理一下CSS最容易躺枪的二十规则,大家能躺中几条?
整理一下CSS最容易躺枪的二十规则,大家能躺中几条? 转载:API中文网 一.float:left/right 或者 position: absolute 后还写上 display:block? 二. ...
- laravel7使用auth进行用户认证
原文地址:https://www.wjcms.net/archives/laravel7使用auth进行用户认证 laravel7 版本移除了 auth,大家都知道以前版本是直接使用 php arti ...
- unity vscode 断点问题
困扰了很久的vscode老莫名其妙的断到网络通信那里. 后来发现是因为起来了一个线程并且调用的unity API 导致. unity 线程中是禁止调用unity API 的. 删掉用 DateTime ...
- BUUCTF-BJD(更新V1.0)
CTF-Day1 (PS:第一次写博客,就是想记录自己的一一步一步) Misc: 问卷调查 | SOLVED |题最简单的misc-y1ng | SOLVED |Real_EasyBaBa | SOL ...
- java NIO 实例之多人聊天
关键抽象 1.定义一个HashMap<String,SocketChannel>用户存储每个用户的管道. 2.服务端监听read事件,获取消息后轮询hashmap发送消息给用户模型内的所有 ...
- 06 Vue生命周期钩子
生命周期钩子 表示一个vue实例从创建到销毁的这个过程,将这个过程的一些时间节点赋予了对应的钩子函数 钩子函数: 满足特点条件被回调的方法 new Vue({ el: "#app" ...
- python 爬虫由于网络或代理不能用导致的问题处理方法
平时在爬取某些网页的时候,可能是由于网络不好或者代理池中的代理不能用导致请求失败.此时有们需要重复多次去请求,python中有现成的,相应的包供我们使用: 我们可以利用retry模块进行多次请求,如果 ...
- Maven 专题(二):vscode 创建一个java Maven项目(vscode)以HdfsClientDemo 为例
1.打开vs code软件,最好创建好自己的工程并使用vs code打开 2. 使用快捷键ctrl + shift + p按键,输入maven进行搜索,选中如图诉讼hi的create mavene ...