大規模 Laravel 應用

文章轉發自專業的Laravel開發者社區,原始連接:learnku.com/laravel/t/3…php

(若是你只想查看解決方案, 單擊此處 )laravel

Laravel是迄今爲止最流行的PHP框架,目錄結構明確清晰,語法優雅。在中小型項目中使用Laravel提供的默認目錄結構效果是很是好的,可是當有一個超過50個模型的大型應用,代碼庫可能就有點讓人窒息。程序員

維護一個大型的應用程序並不簡單,尤爲是當組織錯亂,而Laravel的默認結構對這樣的場景確定沒有很大幫助。web

首先,咱們看看Laravel默認結構以及它對大型應用程序的影響。json

Laravel的默認應用程序結構:api

|- app/
   |- Console/
      |- Commands/
   |- Events/
   |- Exceptions/
   |- Http/
      |- Controllers/
      |- Middleware/
   |- Jobs/
   |- Listeners/
   |- Providers/
   |- User.php
|- database/
   |- factories/
   |- migrations/
   |- seeders/
|- config/
|- routes/
|- resources/
   |- assets/
   |- lang/
   |- views/
複製代碼

結構沒什麼問題。可是,當咱們在大型應用程序中工做時,咱們一般將業務邏輯劃分爲存儲庫、轉換器等……以下所示:bash

|- app/
   |- Console/
      |- Commands/
   |- Events/
   |- Exceptions/
   |- Http/
      |- Controllers/
      |- Middleware/
   |- Jobs/
   |- Listeners/
   |- Models/
   |- Presenters/
   |- Providers/
   |- Repositories/
   |- Services/
   |- Transformers/
   |- Validators/
|- database/
   |- factories/
   |- migrations/
   |- seeders
|- config/
|- routes/
|- resources/
   |- assets/
   |- lang/
   |- views/
複製代碼

這顯然是一個結構良好的Laravel項目。如今,讓咱們看看models文件夾:架構

|- app/
  |- Models/
     |- User.php
     |- Role.php
     |- Permission.php
     |- Merchant.php
     |- Store.php
     |- Product.php
     |- Category.php
     |- Tag.php
     |- Client.php
     |- Delivery.php
     |- Invoice.php
     |- Wallet.php
     |- Payment.php
     |- Report.php
複製代碼

咱們還需處理全部業務邏輯的服務。還有Repositories, Transformers, Validators文件夾,其中包含相同或更多的類。可是,處理單個Entity/Model須要瀏覽不一樣的文件夾和文件。app

問題不在於瀏覽不一樣的文件夾,而在於維護代碼和服務之間的通訊。composer

分析代碼庫,咱們發現:

  • 它是一個總體 應用程序
  • 對於開發人員來講很難 維護
  • 開發效率 低 (須要時刻考慮相互聯繫)
  • Scaling 存在問題

解決方案顯而易見-微服務。即便咱們使用soa(面向服務的體系結構),咱們仍然必須將咱們的總體應用程序分解成更小的獨立部分來分別擴展它們。

一般分離服務須要兩個簡單的步驟:

  • 將服務的子程序 (Models, Repositories, Transformers etc.) 移動到一個新的較小的php微服務應用程序中。
  • 從新設置服務函數調用,將目標重定向到微服務(例如:建立http請求).

如今須要找到與該服務相關的全部文件,你可能會發現經過繞過該服務而在代碼中的其餘地方使用了它的模型或存儲庫。總結一下可能遇到的問題:

  • 要考慮的文件繁多
  • 犯錯的概率很高
  • 產生煩躁
  • 有時須要從新考慮域邏輯
  • 有新的程序員祭天

最後一個緣由很是重要,由於新開發人員很難在短期內掌握整個應用程序。可是,項目經理不會給他太多時間。這會致使胡亂打補丁,錯誤的代碼放置,讓下一個新開發人員將更加困惑。

幸運的是,咱們已經有了一個解決方案 -HMVC。將整個應用程序分紅較小的部分,每一個部分都有本身的文件和文件夾(例如 app/ 文件夾),可是HMVC增長了更多的複雜性,而且當咱們要將特定模塊移入微服務時也是如此。咱們仍然須要將控制器,中間件等保留在主代碼庫中。在大多數狀況下,轉向微服務須要從新定義路由和控制器。所以,咱們必須作多餘的工做。所以,我不是這種結構的忠實擁護者。由於,我只想分開我(必須)沒必要分開的東西。並經過composer.json自動加載方式加載,以下所示:

|- auth/
   |- Exceptions/
   |- Http/
   |- Listeners/
   |- Models/
   |- Presenters/
   |- Providers/
   |- Repositories/
   |- Services/
   |- Transformers/
   |- Validators/
|- merchant/
   |- Console/
   |- Events/
   |- Exceptions/
   |- Http/
   |- Jobs/
   |- Listeners/
   |- Models/
   |- Presenters/
   |- Providers/
   |- Repositories/
   |- Services/
   |- Transformers/
   |- Validators/
|- database/
   |- factories/
   |- migrations/
   |- seeders
|- config/
|- routes/
|- resources/
   |- assets/
   |- lang/
   |- views/
複製代碼

可是HMVC增長了更多的複雜性,而且當咱們要將特定模塊移入微服務時也是如此。咱們仍然須要將控制器,中間件等保留在主代碼庫中。在大多數狀況下,轉向微服務須要從新定義路由和控制器,咱們必須作多餘的工做。可是,我只想分開我(必須)不得不分開的東西。

領域驅動設計

本文再也不對領域驅動設計作過多介紹,Developerul DeLaUnu 在 這裏對DDD進行了很好的描述。

以本文的觀點,DDD(能夠)將Laravel應用程序分爲4部分(或3…  參見) :

  • 應用程序 — 一般包含,控制器,中間件,路由
  • 領域 — 一般包含業務邏輯(模型,存儲庫,變壓器,策略等)
  • 基礎架構 —一般擁有經常使用服務,例如日誌記錄,電子郵件等
  • 界面 —一般包含視圖,語言,資產

若是咱們這樣構造應用程序並使用命名空間會產生什麼結果呢?

|- app/
   |- Http/ (Application)
      |- Controllers/
      |- Middleware/
|- Domain/
   |- Models/
   |- Repositories/
   |- Presenters/
   |- Transformers/
   |- Validators/
   |- Services/
|- Infrastructure/
   |- Console/
   |- Exceptions/
   |- Providers/
   |- Events/
   |- Jobs/
   |- Listeners/
|- resources/ (Interface)
   |- assets/
   |- lang/
   |- views/
|- routes/
   |- api.php
   |- web.php
複製代碼

將項目化分紅這樣的文件夾是行不通的,這意味着咱們只添加了一個父命名空間。

解決方案

以下:

|- app/
   |- Http/
      |- Controllers/
      |- Middleware/
   |- Providers/
   |- Account/
      |- Console/
      |- Exceptions/
      |- Events/
      |- Jobs/
      |- Listeners/
      |- Models/
         |- User.php
         |- Role.php
         |- Permission.php
      |- Repositories/
      |- Presenters/
      |- Transformers/
      |- Validators/
      |- Auth.php
      |- Acl.php
   |- Merchant/
   |- Payment/
   |- Invoice/
|- resources/
|- routes/
複製代碼

該  Auth.php和  Acl.php 是內部的服務文件  app/Account/ 夾。控制器將僅訪問這兩個類並調用其函數。其餘類(域以外)將不會訪問到app/Account/ 文件夾中的其餘剩餘類  。這些服務中的功能將只接受基本的PHP數據類型,例如  array,  string,  int,  bool 和POPO(Plain Old PHP Object),但沒有類的實例。例如:

public function register(array $attr) {
    ...
}
public function login(array $credentials) {
    ... 
}
public function logout() {
    ...
}
複製代碼

須要注意,該  register 函數接收的  array 屬性而不是  User 對象。由於另外一個正在調用該函數的類不該該知道該User 模型的存在  。這是整個結構的基本規則。

當咱們想要分離代碼時

咱們的應用開始變得龐大而後咱們想要將 Account域單獨分離成一個微服務,而且將其轉化爲OAuth服務.

因此,咱們只需移動如下部分-

|- Account/
   |- Console/
   |- Exceptions/
   |- Events/
   |- Jobs/
   |- Listeners/
   |- Models/
      |- User.php
      |- Role.php
      |- Permission.php
   |- Repositories/
   |- Presenters/
   |- Transformers/
   |- Validators/
   |- Auth.php
   |- Acl.php
複製代碼

到一個新的 Laravel (或者 Lumen) 應用-

|- app/
   |- Http/
      |- Controllers/
      | - Middleware/
   |- Account/
      |- Events/
      |- Jobs/
      |- Listeners/
      |- Models/
         |- User.php
         |- Role.php
         |- Permission.php
      |- Repositories/
      |- Presenters/
      |- Transformers/
      |- Validators/
      |- Auth.php
      |- Acl.php
|- routes/
|- resources/
複製代碼

固然,咱們必須在控制器和路由編寫代碼使其成爲一個咱們須要的OAuth服務.

可是咱們須要在主代碼庫中修改什麼呢?

咱們只須要保留Auth.phpAcl.php的服務文件,並將其函數中的代碼更改成針對新建立的微服務的 HTTP 的請求(或者其餘消息傳遞的方法)。

...
public function login(array $credentials) {
 // change the code here
}
...
複製代碼

整個應用程序將保持不變. 應用程序結構以下所示 -

|- app/
   |- Console/
   |- Exceptions/
   |- Http/
      |- Controllers/
      |- Middleware/
   |- Providers/
   |- Account/
      |- Auth.php
      |- Acl.php
   |- Merchant/
   |- Payment/
   |- Invoice/
|- resources/
|- routes/
複製代碼

經過這一較少的努力,您能夠將代碼的一部分移動到徹底獨立的微服務中。我沒法想象還有其餘方法來經過更少的操做將代碼的一部分移動到另外一個微服務中去.

權衡

就像我以前所說的, 任何事情都須要權衡,這個解決方案也不例外. 這裏咱們有一個關於遷移的問題! 由於在上面的文件結構中(在分離以前),全部的遷移文件都在放置在database/migrations/目錄. 可是當咱們想要分離一個域名時,咱們也須要識別這些文件而且移動到新的域名下. 這多是很困難的事情,由於咱們沒有任何明確的跡象代表哪一個遷移文件屬於哪一個域名. 咱們須要知道如何在遷移文件中放置標識符.

該標識符能夠是域名前綴. 好比, 咱們能夠給遷移文件命名爲xxxxxxxxx_create_account_users_table.php而不是xxxxxxxxx_create_users_table.php . 若是須要,咱們還可使用account_users 表名代替users. 我更傾向於肯定哪些表須要在分離中移動. 分離遷移文件可能有點使人沮喪,可是若是咱們使用前綴或者其餘類型的標記,這個過程將會變得不那麼痛苦.

我仍然在試驗這個遷移結構,並計劃構建一個 Laravel 包,它將提供 artisan 命令在分離過程當中來自動生成文件 . 完成後我講在這裏放上包的連接.

相關文章
相關標籤/搜索