前言

最近开发新的项目不是基于完整的 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 的小坑的更多相关文章

  1. mciSendString 的两个小坑

    刚刚修正了自己用的小闹钟的代码. 坑1:REPEAT 选项的作用范围 原来用得好好的,之后选择 .wav 文件,居然不出声音了…… 诶,MCI 肯定支持 .wav 的啊…… 仔细想想,我以前都是选 . ...

  2. 注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式

    注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式 这个坑,必须要注意呀, 比如在用ListView的时候,如果在List_ ...

  3. C#中的Infinity有个小坑

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 昨天家里有事,上网也不方便,就没有推送文章.今天很累,也不长篇大论了.简单介绍一下最近遇到的 ...

  4. 使用EMMET中的小坑

    使用EMMET写HTML的时候,是一个非常爽的事情.但是今天我使用时,发现一个小坑.以前倒也没有注意,不过需要非常的小心. form[action="/process" metho ...

  5. 关于CSS3中transform变换的小坑

    2017年6月30日15:05:46 今天在写一个demo的时候,发现CSS3中transform变换的一个特性. 首先,我先描述一下我发现的情况(问题再现): <div class=" ...

  6. Vue中应用CORS实现AJAX跨域,及它在 form data 和 request payload 的小坑处理

    基本概念部分(一):理解CORS 说道Vue的跨域AJAX,我想先梳理一遍CORS跨域,"跨域资源共享"(Cross-origin resource sharing),它是一个W3 ...

  7. go的变量redeclare的问题,golang的一个小坑

    go的变量声明有几种方式: 1 通过关键字 var 进行声明 例如:var i int   然后进行赋值操作 i = 5 2 最简单的,通过符号 := 进行声明和赋值 例如: i:=5 golang会 ...

  8. MySQL中字段类型为timestamp的小坑

    之前遇到过一个MySQL的字段为timestamp类型的小坑. MySQL中一个字段存储时间类型数据的时候,该字段的类型如果为timestamp类型的话,最多只能存储到2038-01-19 11:14 ...

  9. mysql url 连接配置的一个小坑。 工作中不会遇到。 学习的时候会

    <property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> & ...

随机推荐

  1. 异常处理的设计与重构 pdf

    百度网盘: https://pan.baidu.com/s/1hsQIEGk

  2. Wechall 部分WP

    前言: 开始打CTF,掌握一些新的姿势与知识. 这里我选择的平台是Wechall.这里从简单到难 WP部分: Training: Get SourcedAnswer: 查看网页源代码 Training ...

  3. python3调用C动态库

    软硬件环境 OS X EI Capitan Python 3.5.1 GCC 4.9 前言 最近在做python3开发中,碰到了一个问题,需要通过调用C的一个动态链接库来获取相应的值.扒了扒网络,动手 ...

  4. 不常用的容易忘记常见mysql操作数据表命令

    删除外键关联的约束 alter table tablename drop  foreign key keyname;

  5. 尝试了一些时间,最简单的apache上设置用IP访问一个虚拟目录

    就是其实新建一个 多域名访问的设置 <VirtualHost *:80> DocumentRoot /var/www/ ServerName IP</VirtualHost> ...

  6. git-采集编码搜索

    https://github.com/search?utf8=%E2%9C%93&q=%E9%87%87%E9%9B%86%E7%BC%96%E7%A0%81&type= https: ...

  7. eclipse使用ctrl+shift+F格式化代码失效

    通常情况出现这种问题是组合快捷键和别的软件快捷键冲突了, 最常见的是和搜狗输入法冲突, 在设置中找到搜狗输入法然后把冲突的快捷键取消掉就可以了.

  8. CSS选择器学习小结

    关于CSS选择器的问题,在实际项目中,以及一般的前端面试中会经常遇到.下面对此做一小结,梳理和巩固相关方面知识.(如有不妥之处,还望大家及时批评指正,以免误导他人) 一.选择器种类 1.id选择器(# ...

  9. ResponseUtil数据传递至前端

    package com.java1234.util; import java.io.OutputStream; import java.io.PrintWriter; import javax.ser ...

  10. triton,docker,mesos

    triton user: jill /root/.sdc/docker/jill 下 root@1f6af9d8-8ed9-e940-9c6c-d9505ca25896:~/.sdc/docker/j ...