最近開發新的項目不是基於完整的 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.