上一次分析了 Laravel
中的模型事件與觀察者模式,此次來解析一下 Eloquent
中的 fill
php
用 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() == ['*']; }
能夠看到這個方法的做用就是去獲取自身的 fillable
與 guarded
,而後判斷他們是否都爲 不可批量賦值
狀態,最後返回一個布爾值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
數組中定義了值,若是定義了值,則會返回 fillable
與 attributes
相交的值,若是沒有,則返回 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
會處於可批量賦值任何屬性
的狀態
至於你同時設置了fillable
與guarded
數組的狀況就不去討論了,由於這樣作自己就是被Laravel
所禁止的
而後調用 fillableFromArray
去獲取 attributes
與 fillable
數組的交集,若是你沒有定義 fillable
或者禁用掉了守衛,那麼此方法會直接返回 attributes
而後 Laravel
會對返回的數組作一個循環,在這個循環中 Laravel
會對每個屬性調用 isFillable
方法檢測這個屬性是否能夠被填充,若是沒有經過此方法的檢測(不存在於fillable
數組中而且沒有設置 guarded
數組或存在於 guarded
數組中),那麼 Laravel
會檢測當前 Model
是否處於 僅可批量賦值指定屬性
狀態,若是是,那麼會直接拋出一個 Exception
而後 Laravel
會返回完成賦值操做後的 $this
以上就是 Eloquent
中 fill
方法的源碼解析啦~,Laravel
的源碼讀下來仍是很清晰易懂的~,不得再也不次佩服 Laravel
的設計,不愧爲 巨匠級框架