最近开发新的项目不是基于完整的 laravel 框架,框架是基于 laravel ORM 的简单MVC模式。随着项目的成熟和业务需求,须要引入事件机制。简单地浏览了一下 symfony、laravel 的事件机制,都是依赖于 container 的。感受若是引入的话开销有点大,在寻觅更好解决方案过程当中发现 ORM 竟然自带事件机制,彻底足够目前的业务需求,又不须要改动框架,简直不能太棒!这里简单的记录一下orm observe 的使用吧。laravel
因为 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 时底层流程是:ui
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。this
update 同理就不具体贴代码了, saving>updating>updated>saved。spa
而 delete 不涉及 save,所以依次只触发了 deleting 和deleted。 当 restore 软删除记录时触发了 restoring 和 restored 方法。rest
只需在 model 添加 boot 方法,能够直接在 boot 方法中定义事件,也能够面向于 model 新建 modelObserver 集中处理对应的 model 事件。code
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()
。orm
痛点2:model 只 boot 一次bootIfNotBooted()
,booted model 不会从新调用 boot 方法。symfony
belongsToMany()
时,调用 ORM 的 clearBootedModels()
方法,清除 bootedModel,update model1 时再次 boot model1,强行将 dispatcher 指向 model1.