Eloquent Observer 的小坑
前言
最近开发新的项目不是基于完整的 laravel 框架,框架是基于 laravel ORM 的简单MVC模式。随着项目的成熟和业务需求,需要引入事件机制。简单地浏览了一下 symfony、laravel 的事件机制,都是依赖于 container 的。感觉如果引入的话开销有点大,在寻觅更好解决方案过程中发现 ORM 居然自带事件机制,完全足够目前的业务需求,又不需要改动框架,简直不能太棒!这里简单的记录一下orm observe 的使用吧。
事件触发流程
由于 ORM 事件是针对 Model 的,所以本身结合 Model 封装了一些基础的事件。感觉基本上是够使用了,如果需要添加额外事件的话,ORM 也提供了 setObservableEvents()供使用。
public function getObservableEvents()
{
return array_merge(
[
'creating', 'created', 'updating', 'updated',
'deleting', 'deleted', 'saving', 'saved',
'restoring', 'restored',
],
$this->observables
);
}
我们都知道 ORM 无论是 create 还是 update 本质是 save。因此分析一下 ORM save 时底层流程是:
public function save(array $options = [])
{
$query = $this->newQueryWithoutScopes();
//触发 saving 事件
if ($this->fireModelEvent('saving') === false) {
return false;
}
if ($this->exists) {
$saved = $this->performUpdate($query, $options);
}
else {
$saved = $this->performInsert($query, $options);
}
if ($saved) {
$this->finishSave($options);
}
return $saved;
}
protected function performInsert(Builder $query, array $options = [])
{
//触发 creating 事件
if ($this->fireModelEvent('creating') === false) {
return false;
}
if ($this->timestamps && Arr::get($options, 'timestamps', true)) {
$this->updateTimestamps();
}
$attributes = $this->attributes;
if ($this->getIncrementing()) {
$this->insertAndSetId($query, $attributes);
}
else {
$query->insert($attributes);
}
$this->exists = true;
$this->wasRecentlyCreated = true;
//触发 created 事件
$this->fireModelEvent('created', false);
return true;
}
protected function finishSave(array $options)
{
//触发 saved 事件
$this->fireModelEvent('saved', false);
$this->syncOriginal();
if (Arr::get($options, 'touch', true)) {
$this->touchOwners();
}
}
以上是阐述 creat 时事件触发流程,显而易见依次是 saving>creating>created>saved。
update 同理就不具体贴代码了, saving>updating>updated>saved。
而 delete 不涉及 save,因此依次只触发了 deleting 和deleted。 当 restore 软删除记录时触发了 restoring 和 restored 方法。
使用
只需在 model 添加 boot 方法,可以直接在 boot 方法中定义事件,也可以面向于 model 新建 modelObserver 集中处理对应的 model 事件。
public static function boot()
{
parent::boot();
static::setEventDispatcher(new \Illuminate\Events\Dispatcher());
//static::saving(function($model){ });
static::observe(new testObserver());
}
class testObserve{
public function saving($model)
{
$model->name=name.'test';
}
}
大坑
不得不感叹这个事件真的既简单又实用,但是!当我在开发过程中有一处 update 怎么都不会触发事件,捉急的很啊。菜鸟一下看不出问题本质,只能打断点一点点排查。发现是因为该处代码前调用了belongsToMany()。
- 痛点1:dispatcher 与 container 共生死单例。
多对多模型关联 boot 两个model,因此 boot model2 时,将 dispatcher 指向了 model2。 痛点2:model 只 boot 一次
bootIfNotBooted(),booted model 不会重新调用 boot 方法。- 结果:update model1 怎么都无法触发事件。
- 解决:目前能想到的便是在调用
belongsToMany()时,调用 ORM 的clearBootedModels()方法,清除 bootedModel,update model1 时再次 boot model1,强行将 dispatcher 指向 model1.
Eloquent Observer 的小坑的更多相关文章
- mciSendString 的两个小坑
刚刚修正了自己用的小闹钟的代码. 坑1:REPEAT 选项的作用范围 原来用得好好的,之后选择 .wav 文件,居然不出声音了…… 诶,MCI 肯定支持 .wav 的啊…… 仔细想想,我以前都是选 . ...
- 注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式
注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式 这个坑,必须要注意呀, 比如在用ListView的时候,如果在List_ ...
- C#中的Infinity有个小坑
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 昨天家里有事,上网也不方便,就没有推送文章.今天很累,也不长篇大论了.简单介绍一下最近遇到的 ...
- 使用EMMET中的小坑
使用EMMET写HTML的时候,是一个非常爽的事情.但是今天我使用时,发现一个小坑.以前倒也没有注意,不过需要非常的小心. form[action="/process" metho ...
- 关于CSS3中transform变换的小坑
2017年6月30日15:05:46 今天在写一个demo的时候,发现CSS3中transform变换的一个特性. 首先,我先描述一下我发现的情况(问题再现): <div class=" ...
- Vue中应用CORS实现AJAX跨域,及它在 form data 和 request payload 的小坑处理
基本概念部分(一):理解CORS 说道Vue的跨域AJAX,我想先梳理一遍CORS跨域,"跨域资源共享"(Cross-origin resource sharing),它是一个W3 ...
- go的变量redeclare的问题,golang的一个小坑
go的变量声明有几种方式: 1 通过关键字 var 进行声明 例如:var i int 然后进行赋值操作 i = 5 2 最简单的,通过符号 := 进行声明和赋值 例如: i:=5 golang会 ...
- MySQL中字段类型为timestamp的小坑
之前遇到过一个MySQL的字段为timestamp类型的小坑. MySQL中一个字段存储时间类型数据的时候,该字段的类型如果为timestamp类型的话,最多只能存储到2038-01-19 11:14 ...
- mysql url 连接配置的一个小坑。 工作中不会遇到。 学习的时候会
<property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> & ...
随机推荐
- 代码生成器 CodeSmith 的使用(四)
在上一篇的版本中,我们生成了数据库中的字段,使生成的属性更加简洁,可读性也提高了很多,但都是钍对一个数据库的单个表,如果要将数据库中的所有 的表都生成相应的类,表中的字段也都生成属性,运行一次就可以将 ...
- 显式锁(二)Lock接口与显示锁介绍
一.显式锁简介 显式锁,这个叫法是相对于隐式锁synchronized而言的,加锁和解锁都要用户显式地控制.显示锁Lock是在Java5中添加到jdk的,同synchronized一样,这也是一 ...
- UnicodeEncodeError: 'gbk' codec can't encode character '\xbb' in position
python实现爬虫遇到编码问题: error:UnicodeEncodeError: 'gbk' codec can't encode character '\xXX' in position XX ...
- angular 中怎么获取路径上的参数 参考:https://docs.angularjs.org/api/ng/service/$location
参考: https://docs.angularjs.org/api/ng/service/$location
- [ilink32 Error] Error: Unresolved external '__fastcall Data::Win::Adodb::TCustomADODataSet
[ilink32 Error] Error: Unresolved external '__fastcall Data::Win::Adodb::TCustomADODataSet::GetParam ...
- myeclipse 代码提示
from http://fuyiyuan2011.iteye.com/blog/1258264 在软件开发过程中,有了代码提示能使开发能够更加快捷与便利.但在Eclipse ,MyEclipse等ja ...
- delphi 泛型 c++builder 泛型
delphi 泛型 System.Generics.Collections.pas TList<T> http://docwiki.embarcadero.com/Libraries/Be ...
- Spring boot @ConfigurationProperties 和@Value
@ConfigurationProperties @Value 功能 批量注入配置文件中的属性 一个个指定 松散绑定(松散语法) 支持 不支持 SpEL 不支持 支持 JSR303数据校验 支持 ...
- 基于OpenGL编写一个简易的2D渲染框架-12 重构渲染器-BlockAllocator
BlockAllocator 的内存管理情况可以用下图表示 整体思路是,先分配一大块内存 Chunk,然后将 Chunk 分割成小块 Block.由于 Block 是链表的一个结点,所以可以通过链表的 ...
- 事件委托,js中的一种优化方法
在前端编程中,我们常会遇到一种叫做事件委托的方法. 那么, 什么是事件委托呢? 简单来说,事件就是指onclick,onmouseover,onmouseout等大部分事件,为什么说是大部分后面会提到 ...