1. 程式人生 > >Laravel 的中大型專案架構

Laravel 的中大型專案架構

 只有MVC 是不夠的,我們需要更完整的專案架構

初學者學習Laravel時分兩種,一種是乖乖的將程式填入MVC架構內,導致controller與model異常的肥大,日後一樣很難維護;一種是常常不知道程式該寫在哪一個class內而猶豫不決,畢竟傳統PHP都是一個頁面一個檔案。本文整理出最適合Laravel的中大型專案架構,兼具容易維護容易擴充容易重複使用的特點,並且容易測試

Version

Laravel 5.1.24

Controller 過於肥大

受RoR的影響,初學者常認為MVC架構就是modelviewcontroller:

  • Model 就是資料庫。
  • Controller 負責與HTTP 溝通,呼叫model 與view。
  • View 就是HTML。

假如依照這個定義,以下這些需求該寫在哪裡呢?

  1. 傳送Email,使用外部API。
  2. 使用PHP 寫的邏輯。
  3. 依需求將顯示格式作轉換。
  4. 依需求是否顯示某些資料。
  5. 依需求顯示不同資料。

其中1, 2 屬於商業邏輯,而3, 4, 5 屬於顯示邏輯,若依照一般人對MVC 的定義,model 是資料庫,而view 又是HTML,以上這些需求都不能寫在model 與view,只能勉強寫在controller。

因此初學者開始將大量程式寫在controller,造成controller 的肥大難以維護。

Model 過於肥大

 既然邏輯寫在controller 不方便維護,那我將邏輯都寫在model 就好了?

當你將邏輯從controller 搬到model 後,雖然controller 變瘦了,但卻肥了model,model 從原本代表資料庫,現在變成還要負擔商業邏輯與顯示邏輯,結果更慘。

Model代表資料庫嗎?把它想成是Eloquent class就好,資料庫邏輯應該寫在repository裡,這也是為什麼Laravel 5已經沒有models目錄,Eloquent class僅僅是放在app根目錄下而已。

中大型專案架構

那我們該怎麼寫呢?別將我們的思維侷限在MVC 內 :

  1. Model :僅當成Eloquent class。
  2. Repository :輔助model,處理資料庫邏輯,然後注入到service。
  3. Service :輔助controller,處理商業邏輯,然後注入到controller。
  4. Controller :接收HTTP request,呼叫其他service。
  5. Presenter :處理顯示邏輯,然後注入到view。
  6. View :使用blade將資料binding到HTML。

其中藍色為原本的MVC,而紫色為本文要介紹的的重點: Repository模式,Service模式與Presenter模式。

箭頭表示物件依賴注入的方向。11關於依賴注入,詳細請參考深入探討依賴注入

我們可以發現MVC架構還在,由於SOLID單一職責原則與依賴反轉原則:

  1. 我們將資料庫邏輯從model 分離出來,由repository 輔助model,將model 依賴注入進repository。
  2. 我們將商業邏輯從controller 分離出來,由service 輔助controller,將service 依賴注入進controller。
  3. 我們將顯示邏輯從view 分離出來,由presenter 輔助view,將presenter 依賴注入進view。

建立目錄

app目錄下建立RepositoriesServicesPresenters目錄。

 別害怕建立目錄!!

別害怕在Laravel預設目錄以外建立的其他目錄,根據SOLID單一職責原則,class功能越多,責任也越多,因此越違反單一職責原則,所以你應該將你的程式分割成更小的部分,每個部分都有它專屬的功能,而不是一個class功能包山包海,也就是所謂的萬能類別,所以整個專案不應該只有MVC三個部分,放手根據你的需求建立適當的目錄,並將適當的class放到該目錄下,只要我們的class有namespace幫我們分類即可。

Repository

由於篇幅的關係,將repository獨立成專文討論,請參考如何使用Repository模式?

Service

由於篇幅的關係,將service獨立成專文討論,請參考如何使用Service模式?

Presenter

由於篇幅的關係,將presenter獨立成專文討論,請參考如何使用Presenter模式?

單元測試

由於現在model、view、controller 的相依物件都已經拆開,也都使用依賴注入,因此每個部分都可以單獨的做單元測試,如要測試service,就將repository 加以mock,也可以將其他service 加以mock。

Presenter 也可以單獨跑單元測試,將其他service 加以mock,不一定要跑驗收測試才能測顯示邏輯。

Conclusion

  • 本文談到的架構只是開始,你可以依照實際需求增加更多的目錄與class,當你發現你的MVC違反SOLID原則時,就大膽的將class從MVC拆開重構,然後依照以下手法:

    1. 建立新的class 或interface。
    2. 將相依物件依賴注入到class。
    3. 在class 內處理他的職責。
    4. 將class 或interface 注入到controller 或view。
  • 最後搭配單元測試,測試重構後的架構是否與原來的需求結果相同。