簡介
可以替代資料庫的觸發器功能。
Observer
的建立
觀察者的功能來自與繼承的 Model
物件的 trait HasEvents
特質。
本章我們使用 Laravel
預設的 User
模型來進行說明。
建立一個觀察者類
註冊 Observer
類
通過 provider
來註冊 Observer
關於
provider
載入機制可以移步【Laravel-海賊王系列】第八章, Provider 功能解析
觀察過程解析
User::observe()
方法來自 Illuminate\Database\Eloquent\Concerns\HasEvents;
上面介紹過了,這個特質類是關鍵,我也主要圍繞這個類來分析。
public static function observe($classes)
{
// "指向 User 物件"
$instance = new static;
// "支援一次傳入陣列或者字串的型式統一包裝成陣列"
// "這裡可以看出 observe() 方法支援一次觀察多個類"
foreach (Arr::wrap($classes) as $class) {
$instance->registerObserver($class);
}
}
複製程式碼
展開 $instance->registerObserver($class)
;
// "剛才的傳入 $class = 'App\UserObserver'"
protected function registerObserver($class)
{
$className = is_string($class) ? $class : get_class($class);
// "這裡就是獲取指定的事件名稱"
$this->getObservableEvents() = array_merge(
[
'retrieved', 'creating', 'created', 'updating', 'updated',
'saving', 'saved', 'restoring', 'restored',
'deleting', 'deleted', 'forceDeleted',
],
$this->observables, // "這個是提供給使用者自己定義的方法"
);
foreach ($this->getObservableEvents() as $event) {
// "還記得 'App\UserObserver' 中定義的方法嗎!"
if (method_exists($class, $event)) {
static::registerModelEvent($event, $className.'@'.$event);
}
}
}
複製程式碼
註冊 Observer
中的事件
上面迴圈了所有的提前指定事件,然後逐個檢查觀察者並進行註冊。
繼續分析 static::registerModelEvent($event, $className.'@'.$event);
protected static function registerModelEvent($event, $callback)
{
if (isset(static::$dispatcher)) {
$name = static::class;
static::$dispatcher->listen("eloquent.{$event}: {$name}", $callback);
}
}
複製程式碼
statci::$dispatcher
是 lluminate\Events\Dispatcher
物件
所以其實這裡迭代呼叫了,可以看到就是繫結一個個事件,同時將事件
指向UserObserver@functionName
的對應方法中。
static::$dispatcher->listen("eloquent.retrieved: App\User", 'App\UserObserver@retrieved');
static::$dispatcher->listen("eloquent.creating: App\User", 'App\UserObserver@creating');
static::$dispatcher->listen("eloquent.created: App\User", 'App\UserObserver@created');
..... 省略類似程式碼
static::$dispatcher->listen("eloquent.forceDeleted: App\User", 'App\UserObserver@forceDeleted');
複製程式碼
關於事件的繫結以及觸發機制請移步【Laravel-海賊王系列】第九章, Events 功能解析
經歷過上面種種繫結我們已經繫結了需要的事件,並且監聽者就是 UserObserver
物件。
接下來就是如何觸發的問題了。
觸發 Observer
監聽的事件
我們來看常用的生成使用者的方法。
User::create(
[
'name' => "big pig's feet",
'email' => 'hello@world.com',
'password' => password_hash('123456', PASSWORD_BCRYPT, ['cost' => 12,]),
]
);
複製程式碼
⚠️這裡
create
方法在Model
中並不存在,會呼叫魔術方法__call()
我們本章只關心觀察者,查詢構建器後續在涉及!直接看最終呼叫方法
位於 Model
的 performInsert
方法
protected function performInsert(Builder $query)
{
if ($this->fireModelEvent('creating') === false) {
return false;
}
if ($this->usesTimestamps()) {
$this->updateTimestamps();
}
$attributes = $this->getAttributes();
if ($this->getIncrementing()) {
$this->insertAndSetId($query, $attributes);
}else {
if (empty($attributes)) {
return true;
}
$query->insert($attributes);
}
$this->exists = true;
$this->wasRecentlyCreated = true;
$this->fireModelEvent('created', false);
return true;
}
複製程式碼
這裡我們不詳解如何執行事件的程式碼,我們只關心執行了什麼!
執行邏輯分析:
首先觸發模型之前繫結的
creating
方法。
呼叫最後插入資料的邏輯。
設定一些放重複的屬性
呼叫繫結的
created
事件。
到了這裡可以知道官方給出的許多事件以及執行順序的原因!
結語
Laravel
的 Model
功能非常多,本章只是
簡單的介紹了其中一種功能“觀察者”,還有很多方法沒有分析
但是基本原理我們只要知道一種其他也都是一樣。
最後總結一下
Model
結合laravel
事件來完成觀察者事件的監聽和觸發。
Provider
提供了觀察者在啟動過程的載入服務。