Laravel Eloquent 之 Fill 方法解析

上一次分析了 Laravel 中的模型事件與觀察者模式,此次來解析一下 Eloquent 中的 fillphp

Laravel 的童鞋應該都知道,fill 方法是一個給 Eloquent 實例賦值屬性的方法,讓咱們點開 fill 方法先看一看它的源碼:數組

這裏筆者所使用的版本爲 Laravel 5.5最新版,爲了方便閱讀,刪除掉了註釋框架

public function fill(array $attributes)
{
    $totallyGuarded = $this->totallyGuarded();

    foreach ($this->fillableFromArray($attributes) as $key => $value) {
        $key = $this->removeTableFromKey($key);

        if ($this->isFillable($key)) {
            $this->setAttribute($key, $value);
        } elseif ($totallyGuarded) {
            throw new MassAssignmentException($key);
        }
    }

    return $this;
}

首先能夠看到,Laravel 會先去調用一個自身的 totallyGuarded 方法,讓咱們點開這個方法:函數

public function totallyGuarded()
{
   return count($this->getFillable()) == 0 && $this->getGuarded() == ['*'];
}

能夠看到這個方法的做用就是去獲取自身的 fillableguarded,而後判斷他們是否都爲 不可批量賦值 狀態,最後返回一個布爾值this

// 返回一個 True or False 的布爾值
// 若是未設置 fillable 與 guarded,則會返回 True (注意,在這種狀況下,此 `Model` 是不容許批量賦值任何屬性的哦)
// 反之則返回 False
$totallyGuarded = $this->totallyGuarded();

Ok,讓咱們回到剛纔的 fill 方法繼續往下看設計

接下來是一個 foreach 循環,可是在循環以前,Laravel 對傳入的賦值屬性執行了 fillableFromArray 這個方法,再點進去看一下,code

protected function fillableFromArray(array $attributes)
{
    if (count($this->getFillable()) > 0 && ! static::$unguarded) {
        return array_intersect_key($attributes, array_flip($this->getFillable()));
    }

    return $attributes;
}

此方法會檢測你是否在 fillable 數組中定義了值,若是定義了值,則會返回 fillableattributes 相交的值,若是沒有,則返回 attributes 自身事件

而後回到 fill ,在調用 fillableFromArray 對參數進行處理以後,如今返回的值只剩咱們容許批量賦值的屬性了 (若是你定義了)ip

循環第一行,先使用 removeTableFromKey 對參數的 Key 進行處理,刪除鍵中的表名,此方法就不作過多講解,只是一個字符串拆分取值的函數rem

$key = $this->removeTableFromKey($key);

接着往下看,Laravel對將要進行填充的每一個屬性都調用了 isFillable 方法來確保此屬性是能夠被填充的,讓咱們看一看它的源碼:

public function isFillable($key)
{
   if (static::$unguarded) {
       return true;
   }

   if (in_array($key, $this->getFillable())) {
       return true;
   }

   if ($this->isGuarded($key)) {
       return false;
   }

   return empty($this->getFillable()) &&
       ! Str::startsWith($key, '_');
}

能夠看到,在此方法中 Laravel 先判斷了此 Model 是否禁用了守衛 (guarded),若是此 Model 並未啓用守衛,那麼直接返回 True

if (static::$unguarded) {
    return true;
}

若是啓用了守衛,那麼會判斷一下此屬性是否存在於 fillable 數組中,若是存在,則返回 True,

if (in_array($key, $this->getFillable())) {
    return true;
}

若是此屬性不存在於 fillable 數組中,那麼 Laravel 會再次判斷此屬性是否存在於 guarded 數組中,若是存在於此數組中,那麼此屬性就不是一個能夠被批量賦值的屬性,那麼就會直接返回 False

if ($this->isGuarded($key)) {
    return false;
}

若是以上都不符合,那麼 Laravel 在最後會判斷一下自身的 fillable 數組是爲空而且此屬性是以 _ 開頭,而後返回一個布爾值

return empty($this->getFillable()) && ! Str::startsWith($key, '_');

而後回到 fill 方法接着看,若是此屬性經過了 isFillable 方法的過濾,那麼將此屬性賦值給自身 (由於時間有限,setAttribute 這個方法就不細講啦~),

$this->setAttribute($key, $value);

若是沒有經過 isFillable 方法的過濾,那麼 Laravel 會判斷一下自身 Model 是否處於不限制任何屬性批量賦值的狀態,若是不是,那麼 Laravel 會直接拋出一個 Exception

// 判斷此屬性是否經過了檢測
if ($this->isFillable($key)) {
    // 將此屬性賦值給自身
    $this->setAttribute($key, $value);

// 若是沒有經過檢測,那麼判斷一下自身 `Model` 是否爲所有不可批量賦值狀態,若是是,那麼會拋出一個 `Exception`
} elseif ($totallyGuarded) {
    throw new MassAssignmentException($key);
}

在對全部的屬性進行檢測而且賦值後, Laravel 會將自身返回

return $this;

解析完畢,以上就是 fill 方法的源碼啦~,最後來一個小結

在你調用 fill 方法的時候,Laravel 首先就會去檢測當前 Model 的狀態,

當你設置了 fillable 數組,沒有設置 guarded 數組時,那麼此 Model 會處於 僅可批量賦值指定屬性 的狀態
當你沒有設置 fillable 數組,卻設置了 guarded 數組時,那麼此 Model 會處於 可批量賦值任何屬性 的狀態
至於你同時設置了 fillableguarded 數組的狀況就不去討論了,由於這樣作自己就是被 Laravel 所禁止的

而後調用 fillableFromArray 去獲取 attributesfillable 數組的交集,若是你沒有定義 fillable 或者禁用掉了守衛,那麼此方法會直接返回 attributes

而後 Laravel 會對返回的數組作一個循環,在這個循環中 Laravel 會對每個屬性調用 isFillable 方法檢測這個屬性是否能夠被填充,若是沒有經過此方法的檢測(不存在於fillable 數組中而且沒有設置 guarded 數組或存在於 guarded 數組中),那麼 Laravel會檢測當前 Model 是否處於 僅可批量賦值指定屬性 狀態,若是是,那麼會直接拋出一個 Exception

而後 Laravel 會返回完成賦值操做後的 $this

以上就是 Eloquentfill 方法的源碼解析啦~,Laravel 的源碼讀下來仍是很清晰易懂的~,不得再也不次佩服 Laravel 的設計,不愧爲 巨匠級框架

相關文章
相關標籤/搜索