【Laravel-海賊王系列】第十五章,Model Observer 解析

簡介

能夠替代數據庫的觸發器功能。laravel

Observer 的建立

觀察者的功能來自與繼承的 Model 對象的 trait HasEvents 特質。數據庫

本章咱們使用 Laravel 默認的 User 模型來進行說明。數組

建立一個觀察者類bash

註冊 Observer

經過 provider 來註冊 Observeride

關於 provider 加載機制能夠移步【Laravel-海賊王系列】第八章, Provider 功能解析post

觀察過程解析

User::observe() 方法來自 Illuminate\Database\Eloquent\Concerns\HasEvents;ui

上面介紹過了,這個特質類是關鍵,我也主要圍繞這個類來分析。this

public static function observe($classes)
{
    // "指向 User 對象"
    $instance = new static;

    // "支持一次傳入數組或者字符串的型式統一包裝成數組"
    // "這裏能夠看出 observe() 方法支持一次觀察多個類"
    foreach (Arr::wrap($classes) as $class) {
        
        $instance->registerObserver($class);
    }
}
複製代碼

展開 $instance->registerObserver($class);spa

// "剛纔的傳入 $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 中的事件

上面循環了全部的提早指定事件,而後逐個檢查觀察者並進行註冊。rest

繼續分析 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::$dispatcherlluminate\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()

咱們本章只關心觀察者,查詢構建器後續在涉及!直接看最終調用方法

位於 ModelperformInsert 方法

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 事件。

到了這裏能夠知道官方給出的許多事件以及執行順序的緣由!

結語

LaravelModel 功能很是多,本章只是

簡單的介紹了其中一種功能「觀察者」,還有不少方法沒有分析

可是基本原理咱們只要知道一種其餘也都是同樣。

最後總結一下

Model 結合 laravel 事件來完成觀察者事件的監聽和觸發。

Provider 提供了觀察者在啓動過程的加載服務。

相關文章
相關標籤/搜索