Eloquent 模型会触发许多事件,让你在模型的生命周期的多个时间点进行监控:
retrieved, creating, created, updating,updated,
saving, saved,deleting, deleted, restoring, restored。
事件让你在每当有特定模型类进行数据库保存或更新时,执行代码。
上面是 laravel china 上 laravel 手册中对于 laravel Eloquent 的事件描述。
并且上面提供了两种在 Eloquent 模型中添加事件的方法:
$dispatchesEvents
属性。 /**
* 此模型的事件映射.
*
* @var array
*/
protected $dispatchesEvents = [
'saved' => UserSaved::class,
'deleted' => UserDeleted::class,
];
Observer
,并将观察者在服务提供者中的 boot 方法中注册。这两种方法都很不错,但是在有些场景下应该会有更好的方法来实现 Eloquent 事件。
现在我举一个大家开发中应该很常见的一个场景:
添加操作者信息,
有人会说添加操作者还不简单啊,在每个对数据操作的地方将操作者信息数据一并写入就好了。
确认这样是可以,但是我觉得这样写不简洁优雅。
既然我们在用一个很优雅的框架,那么为什么我们不思考一下用更简洁的方式来实现呢。
下面我就用自己认为较为简洁的方式简单分享出来:
<?php
/**
* Created by PhpStorm.
* User: coderChen
* Date: 2018/9/2
* Time: 16:51
*/
namespace App\Models\Traits;
use App\Observers\OperatorObserve;
trait OperatorTrait
{
//这里模型实例化的时候,会执行该静态方法。
public static function bootOperatorTrait(){
//给模型绑定操作人监听器
static::observe(OperatorObserve::class);
}
}
<?php
namespace App\Observers;
// creating, created, updating, updated, saving,
// saved, deleting, deleted, restoring, restored
use Illuminate\Database\Eloquent\Model;
class OperatorObserver
{
//新增修改会触发该方法
public function saving(Model $model){
//这里面做写入操作人处理逻辑
}
//删除会出发该方法
public function deleting(Model $model){
//这里面做写操作人处理逻辑
}
}
<?php
namespace App;
use App\Models\Traits\OperatorTrait;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
//通过 use OperatorTrait 来实现操作人自动写入。
use OperatorTrait;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password','operator'
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
}
到这里,通过给模型添加 Trait 来实现模型事件就完成了,可能有些同学会有一写疑问,为什么模型会自动执行 trait 中的某些方法,答案就在下面,
注意,这里你应该了解什么是静态延迟绑定,不然会被多个 static 调用给绕晕:
我们先看 Illuminate\Database\Eloquent
命名空间下的 Model 抽象类,
该类是所有 Eloquent 模型的基类,我们看到它的构造函数:
/**
* Create a new Eloquent model instance.
*
* @param array $attributes
* @return void
*/
public function __construct(array $attributes = [])
{
$this->bootIfNotBooted();
$this->syncOriginal();
$this->fill($attributes);
}
接下来我们去看到构造函数中调用的 bootIfNotBooted() 方法:
/**
* Check if the model needs to be booted and if so, do it.
*
* @return void
*/
protected function bootIfNotBooted()
{
//如果该模型未被实例化过,就去执行 if 里面的代码,去实例化它。
if (! isset(static::$booted[static::class])) {
//将模型标注为已实例化。
static::$booted[static::class] = true;
$this->fireModelEvent('booting', false);
//通过静态延迟绑定去执行该模型的 boot() 启动方法
static::boot();
$this->fireModelEvent('booted', false);
}
}
接下来看到在 bootIfNotBooted() 中的 boot() 方法,另外两个 fireModelEvent() 暂时先不管:
/**
* The "booting" method of the model.
*
* @return void
*/
protected static function boot()
{
static::bootTraits();
}
接下来去看到 boot() 方法中的 bootTraits() 方法,欸,等下,我们关注一下这个方法的名字,启动 traits,在模型中能自动运行 trait 中的某些方法应该就是它的功劳了:
/**
* Boot all of the bootable traits on the model.
*
* @return void
*/
protected static function bootTraits()
{
//获取该模型的类名,包含其命名空间,比如这样:App\User
$class = static::class;
//用于存放已经执行过的方法缓存
$booted = [];
//class_user_recursive 方法获取该类以及该类的父类所有的 trait
foreach (class_uses_recursive($class) as $trait) {
//通过给 trait 名称前面添加 boot 来生成对应 trait 中的 启动方法
$method = 'boot'.class_basename($trait);
//检查模型类中是否存在 trait 中的 自动启动方法,并且检查该方法是否已经被执行过。
if (method_exists($class, $method) && ! in_array($method, $booted)) {
//执行 trait 中的方法
forward_static_call([$class, $method]);
//将已经执行过的方法放入放到 已执行方法的缓存中,防止重复执行
$booted[] = $method;
}
}
}
好了,到这儿就算是已经知道了 Eloquent 模型中的启动方法执行的原理了,
在 githab 上有一个 laravel Eloquent 的数据验证包也是运用的上面的原理,链接在此,有兴趣的同学可以去研究下。
其实这里还要注意的一点就是:
对于 trait 中的启动方法命名应该是在 trait 名称前面添加 boot 字符。
当然,这里只是说了如何通过 trait 来添加监听器,也只是分析了添加监听器的原理。
往后有时间我会继续分享一下监听器的工作原理,其实也就是事件的工作原理。
当然以上都是作者自己的看法,如果大家认为我的看法可以更进一步改进的话,欢迎留言讨论。
Original url: Access
Created at: 2018-10-10 15:41:17
Category: default
Tags: none
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
java windows火焰图_mob64ca12ec8020的技术博客_51CTO博客 - 在windows下不可行,不知道作者是怎样搞的 监听SpringBoot 服务启动成功事件并打印信息_监听springboot启动完毕-CSDN博客 SpringBoot中就绪探针和存活探针_management.endpoint.health.probes.enabled-CSDN博客 u2u转换板 - 嘉立创EDA开源硬件平台 Spring Boot 项目的轻量级 HTTP 客户端 retrofit 框架,快来试试它!_Java精选-CSDN博客 手把手教你打造一套最牛的知识笔记管理系统! - 知乎 - 想法有重合-理论可参考 安宇雨 闲鱼 机械键盘 客制化 开贴记录 文本 linux 使用find命令查找包含某字符串的文件_beijihukk的博客-CSDN博客_find 查找字符串 ---- mac 也适用 安宇雨 打字音 记录集合 B站 bilibili 自行搭建 开坑 真正的客制化 安宇雨 黑苹果开坑 查找工具包maven pom 引用地 工具网站 Dantelis 介绍的玩轴入坑攻略 --- 关于轴的一些说法 --- 非官方 ---- 心得而已 --- 长期开坑更新 [本人问题][新开坑位]关于自动化测试的工具与平台应用 机械键盘 开团 网站记录 -- 能做一个收集的程序就好了 不过现在没时间 -- 信息大多是在群里发的 - 你要让垃圾佬 都去一个地方看难度也是很大的 精神支柱 [超级前台]sprinbboot maven superdesk-app 记录 [信息有用] [环境准备] [基本完成] [sebp/elk] 给已创建的Docker容器增加新的端口映射 - qq_30599553的博客 - CSDN博客 [正在研究] Elasticsearch, Logstash, Kibana (ELK) Docker image documentation elasticsearch centos 安装记录 及 启动手记 正式服务器 39 elasticsearch 问题合集 不断更新 6.1.1 | 6.5.1 两个版本 博客程序 - 测试 - bug记录 等等问题 laravel的启动过程解析 - lpfuture - 博客园 OAuth2 Server PHP 用 Laravel 搭建带 OAuth2 验证的 RESTful 服务 | Laravel China 社区 - 高品质的 Laravel 和 PHP 开发者社区 利用Laravel 搭建oauth2 API接口 附 Unauthenticated 解决办法 - 煮茶的博客 - SegmentFault 思否 使用 OAuth2-Server-php 搭建 OAuth2 Server - 午时的海 - 博客园 基于PHP构建OAuth 2.0 服务端 认证平台 - Endv - 博客园 Laravel 的 Artisan 命令行工具 Laravel 的文件系统和云存储功能集成 浅谈Chromium中的设计模式--终--Observer模式 浅谈Chromium中的设计模式--二--pre/post和Delegate模式 浅谈Chromium中的设计模式--一--Chromium中模块分层和进程模型 DeepMind 4 Hacking Yourself README.md update 20211011
Laravel China 简书 知乎 博客园 CSDN博客 开源中国 Go Further Ryan是菜鸟 | LNMP技术栈笔记 云栖社区-阿里云 Netflix技术博客 Techie Delight Linkedin技术博客 Dropbox技术博客 Facebook技术博客 淘宝中间件团队 美团技术博客 360技术博客 古巷博客 - 一个专注于分享的不正常博客 软件测试知识传播 - 测试窝 有赞技术团队 阮一峰 语雀 静觅丨崔庆才的个人博客 软件测试从业者综合能力提升 - isTester IBM Java 开发 使用开放 Java 生态系统开发现代应用程序 pengdai 一个强大的博主 HTML5资源教程 | 分享HTML5开发资源和开发教程 蘑菇博客 - 专注于技术分享的博客平台 个人博客-leapMie 流星007 CSDN博客 - 舍其小伙伴 稀土掘金 Go 技术论坛 | Golang / Go 语言中国知识社区
最新评论