初學者學習 Laravel 時分兩種,一種是乖乖的將程式填入 MVC 架構內,導致 controller 與 model 異常的肥大,日後一樣很難維護;一種是經常不知道程式該寫在哪一個 class 內而猶豫不決,畢竟傳統 PHP 都是一個頁面一個檔案。本文整理出最適合 Laravel 的中大型專案架構,兼具容易維護、容易擴充與容易重複使用的特點,並且容易測試。laravel
Laravel 5.1.24app
受RoR的影響,初學者常認為 MVC 架構就是 model
, view
, controller
:svg
假如依照這個定義,如下這些需求該寫在哪裡呢?spa
其中 1, 2 屬於商業邏輯,而 3, 4, 5 屬於顯示邏輯,若依照通常人對 MVC 的定義,model 是資料庫,而 view 又是 HTML,以上這些需求都不能寫在 model 與 view,只能勉強寫在 controller。code
所以初學者開始將大量程式寫在 controller,形成 controller 的肥大難以維護。get
既然邏輯寫在 controller 不方便維護,那我將邏輯都寫在 model 就行了?it
當你將邏輯從 controller 搬到 model 後,雖然 controller 變瘦了,但卻肥了 model,model 從本來表明資料庫,現在變成還要負擔商業邏輯與顯示邏輯,結果更慘。io
Model 表明資料庫嗎?把它想成是 Eloquent class
就好,資料庫邏輯應該寫在 repository 裡,這也是為什麼 Laravel 5 已經沒有 models
目錄,Eloquent class 僅僅是放在 app
根目錄下而已。class
那我們該怎麼寫呢?別將我們的思維侷限在 MVC 內 :mock
其中藍色為本來的 MVC,而紫色為本文要介紹的的重點 : Repository 模式,Service 模式與 Presenter 模式。
箭頭表示物件依賴注入的方向。11關於依賴注入,詳細請參考深刻探討依賴注入
我們能夠發現 MVC 架構還在,由於 SOLID 的單一職責原則與依賴反轉原則 :
在 app
目錄下創建 Repositories
,Services
與 Presenters
目錄。
別懼怕創建目錄!!
別懼怕在 Laravel 預設目錄之外創建的其餘目錄,根據 SOLID 的單一職責原則,class 功能越多,責任也越多,所以越違反單一職責原則,因此你應該將你的程式分割成更小的部分,每個部分都有它專屬的功能,而不是一個 class 功能包山包海,也就是所謂的萬能類別,因此整個專案不應該只有 MVC 三個部分,放手根據你的需求創建適當的目錄,並將適當的 class 放到該目錄下,只要我們的 class 有 namespace 幫我們分類便可。
由於篇幅的關係,將 repository 獨立成專文討論,請參考如何使用 Repository 模式?
由於篇幅的關係,將 service 獨立成專文討論,請參考如何使用 Service 模式?
由於篇幅的關係,將 presenter 獨立成專文討論,請參考如何使用 Presenter 模式?
由於現在 model、view、controller 的相依物件都已經拆開,也都使用依賴注入,所以每個部分均可以單獨的作單元測試,如要測試 service,就將 repository 加以 mock,也能夠將其餘 service 加以 mock。
Presenter 也能夠單獨跑單元測試,將其餘 service 加以 mock,不必定要跑驗收測試才能測顯示邏輯。
本文談到的架構只是開始,你能夠依照實際需求增長更多的目錄與 class,當你發現你的 MVC 違反 SOLID 原則時,就大膽的將 class 從 MVC 拆開重構,然後依照如下手法 :
最後搭配單元測試,測試重構後的架構是否與原來的需求結果相同。