Eloquent CRUD:__construct

假設我們在寫一個電子商務網站。建立訂單的第一步大概長這樣:

或是

背後發生了什麼事呢?讓我們一一來看。

首先當然是建構式:

第一步先檢查是否需要「啟動」:

利用一個類別的靜態陣列紀錄是否已啟動,並且觸發啟動前與啟動後的事件。
看來一個類別在一次request內只會被啟動一次。啟動在做什麼呢?

文件中有提到Accessors & Mutators
原來,啟動是為了支援客製化的屬性讀取、寫入功能。
最後一句跟PHP的traits功能有關,你需要先了解PHP traits。
bootTraits會檢查所有traits、看是否有需要「啟動」的部份。舉例來說,Soft Deleting就是利用了traits。

注意class_uses_recursive並不是PHP內建函數,是Larave自定義的helper輔助函數。
再來是建構式第二句的方法:

你會發現original跟attributes都還只是空陣列。在建構式執行這句,乍看之下沒有意義?
我詢問過Laravel原作者,這是他的答覆
翻閱文件,會發現其實可以override attributes陣列。

建構式的最後一句,也是唯一有對傳入建構式的參數做處理的方法來了:

首先檢查所有屬性是否都被「防護」。這是避免使用者直接把瀏覽器丟過來的value,直接塞給Eloquent當屬性、造成資安漏洞的設計。參閱Mass Assignment

接著fillableFromArray會檢查參數陣列中,有哪些是可以寫入的屬性:

你會發現有unguarded變數可以關閉防護機制。原始碼中有三個方法可以直接操作這個變數,官方文件沒有寫進去。
array_intersect_key跟array_flip的巧妙搭配運用,找到了可寫入的屬性。

接著若通過isFillable,就setAttribute。
為什麼要再次檢查isFillable呢?不是都用fillableFromArray只找出可寫入的屬性了嗎?

原來是要檢查有沒有在guarded陣列裡面。

再來,終於要寫入屬性了:

一開始的Mutator檢查…嗯我還沒搞懂,先略過。
接著是檢查是否為日期屬性、轉成字串。就是Date Mutator這段的描述。
沒問題的話,就存進attributes陣列裡頭。
咦?怎麼是存進attributes陣列、不是直接設成物件屬性呀?
那我取出屬性時不就要透過attributes陣列?
別擔心,別忘了PHP有__get這種神奇函數。

複習

好,最後我們來複習一遍。
Eloquent建構式會依序執行三個方法。
一、執行啟動程序(支援客製化屬性讀寫、執行所有traits的啟動程序)
二、載入使用者自定義屬性(使用者定義的$this->attributes陣列)
三、將傳入建構式的參數寫入為屬性

以上大致就是一個Eloquent子類別在建構式中會做的事情。是不是比想像中複雜地多呢:)

by 阿川先生