在 Laravel
的世界中,你對 Eloquent
大多數操做都會或多或少的觸發一些模型事件,今天就來看一下模型事件的使用。php
Laravel
事先已經定義好了 10
個模型事件以供咱們使用,它們分別是:數據庫
creating
, created
, updating
, updated
, saving
, saved
, deleting
, deleted
, restoring
, restored
。數組
事件名稱都很淺顯易懂,相信若是你是用腦子寫代碼的話都應該能夠看明白,若是不明白的話能夠左轉百度。ide
不過你可能對 updating
, updated
, saving
, saved
這四個事件有所疑惑,因此咱們來詳細分析一下。ui
打開 Illuminate\Database\Eloquent\Model
,找到位於 517
行的 save
方法this
筆者使用的是
Laravel 5.5
最新版本,若是你使用的是其餘版本,請自行在官方文檔版本差別
中對比你的版本spa
public function save(array $options = []) { $query = $this->newQueryWithoutScopes(); if ($this->fireModelEvent('saving') === false) { return false; } if ($this->exists) { $saved = $this->isDirty() ? $this->performUpdate($query) : true; } else { $saved = $this->performInsert($query); if (! $this->getConnectionName() && $connection = $query->getConnection()) { $this->setConnection($connection->getName()); } } if ($saved) { $this->finishSave($options); } return $saved; }
能夠看到首先觸發的是 saving
:rest
$this->fireModelEvent('saving')
接着會判斷此 model
是否是新建立的。code
若是是新建立的,那麼則會進行 insert
操做,因爲本例是分析修改操做,因此這裏直接略過。orm
若是不是新建立的,那麼會調用 isDirty
方法判斷此 model
是否進行了修改。
若是進行了修改,那麼會調用 performUpdate
方法進行更新操做,若是沒有進行修改,則直接返回 true
。
讓咱們點開 performUpdate
方法。
protected function performUpdate(Builder $query) { if ($this->fireModelEvent('updating') === false) { return false; } if ($this->usesTimestamps()) { $this->updateTimestamps(); } $dirty = $this->getDirty(); if (count($dirty) > 0) { $this->setKeysForSaveQuery($query)->update($dirty); $this->fireModelEvent('updated', false); $this->syncChanges(); } return true; }
能夠看到這裏會觸發 updating
:
$this->fireModelEvent('updating')
若是返回的不是 false
,那麼會接着往下走,判斷一下此模型是否使用了 Timestamp
,若是使用了,那麼則先更新自身的 Timestamp
:
if ($this->usesTimestamps()) { $this->updateTimestamps(); }
接着調用 getDirty
,顧名思義,大概能夠知道這個方法是獲取自身的髒值,讓咱們點開看一下:
public function getDirty() { $dirty = []; foreach ($this->getAttributes() as $key => $value) { if (! $this->originalIsEquivalent($key, $value)) { $dirty[$key] = $value; } } return $dirty; }
意料之中,此方法內會返回自身被修改後的髒值,若是你打印過 Laravel
的 Model
實例,那麼相信你會看到實例中有 original
和 attributes
兩個數組。
其中 original
保存的是最初始的實例屬性,沒法被外部直接修改。
attributes
數組則是能夠被自有修改,此方法便是由判斷兩個數組的差別而返回髒值,因爲時間緣由,這裏不作過多詳解,有機會單開一個文章慢慢講。
繼續往下走,能夠看到這裏會判斷一下是否有髒值:
if (count($dirty) > 0)
只有在存在髒值的狀況下才會進入 if
內部,執行 update
操做,繼而觸發 updated
事件
在 update
結束後會執行一下 syncChanges
同步一下自身的數據
OK, performUpdate
方法解析完畢,讓咱們回到 save
方法,接着往下看,能夠看到 Laravel
最後作了一個判斷:
if ($saved) { $this->finishSave($options); }
只有在 update
成功的狀況下,纔會觸發 finishSave()
方法,此方法會接收一個參數 $options
,便是修改的屬性。
讓咱們點開此方法:
protected function finishSave(array $options) { $this->fireModelEvent('saved', false); if ($this->isDirty() && ($options['touch'] ?? true)) { $this->touchOwners(); } $this->syncOriginal(); }
能夠看到在此方法內會觸發 saved
事件
分析完畢,大概能夠作一個總結了。
當模型已存在,不是新建的時候,依次觸發的順序是:
saving
-> updating
-> updated
-> saved
當模型不存在,須要新增的時候,依次觸發的順序則是
saving
-> creating
-> created
-> saved
那麼 saving
,saved
和 updating
,updated
到底有什麼區別呢?
上面已經講過,Laravel
的 Eloquent
會維護實例的兩個數組,分別是 original
和 attributes
。
只有在 saved
事件觸發以後,Laravel
纔會對兩個數組執行 syncOriginal
操做,這樣就很好理解了。
updating
和 updated
會在數據庫中的真值修改先後觸發。
saving
和 saved
則會在 Eloquent
實例的 original
數組真值更改先後觸發。
這樣咱們就能夠根據業務場景來選擇更合適的觸發事件了~
若是你想在一個模型中監聽多個事件,那麼你能夠把它寫成一個類,類中的方法名稱便是你想要監聽的事件名稱
class UserObserver { /** * 監聽數據即將建立的事件。 * * @param User $user * @return void */ public function creating(User $user) { } /** * 監聽數據建立後的事件。 * * @param User $user * @return void */ public function created(User $user) { } /** * 監聽數據即將更新的事件。 * * @param User $user * @return void */ public function updating(User $user) { } /** * 監聽數據更新後的事件。 * * @param User $user * @return void */ public function updated(User $user) { } /** * 監聽數據即將保存的事件。 * * @param User $user * @return void */ public function saving(User $user) { } /** * 監聽數據保存後的事件。 * * @param User $user * @return void */ public function saved(User $user) { } /** * 監聽數據即將刪除的事件。 * * @param User $user * @return void */ public function deleting(User $user) { } /** * 監聽數據刪除後的事件。 * * @param User $user * @return void */ public function deleted(User $user) { } /** * 監聽數據即將從軟刪除狀態恢復的事件。 * * @param User $user * @return void */ public function restoring(User $user) { } /** * 監聽數據從軟刪除狀態恢復後的事件。 * * @param User $user * @return void */ public function restored(User $user) { } }
而後在 AppServiceProvider
中註冊此觀察者
<?php namespace App\Providers; use App\User; use App\Observers\UserObserver; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { /** * 運行全部應用. * * @return void */ public function boot() { // 爲 User 模型註冊觀察者 User::observe(UserObserver::class); } /** * 註冊服務提供. * * @return void */ public function register() { // } }
而後你就能夠在你註冊的 Observer
中觀測到各類事件啦~