創建專注的領域應用程式。 Symfony 方法(第 1 部分)

Patricia Arquette
發布: 2024-11-03 10:52:29
原創
667 人瀏覽過

介紹

這是我決定創建的系列文章的第一篇,旨在解釋我如何組織我的 symfony 應用程式以及如何嘗試編寫盡可能面向領域的程式碼。
下面,您可以找到我將在所有系列部分中使用的流程圖。在每篇文章中,我將重點放在該圖的特定部分,並嘗試分析所涉及的流程並檢測哪些部分屬於我們的領域以及如何使用外部層與其他部分解耦。

Creating focused domain applications. A Symfony approach (Part 1)

分解資料處理

在第一部分中,我們將專注於資料擷取和驗證過程。對於資料擷取過程,我們假設請求資料的格式為 JSON。

擷取數據

基於我們知道請求資料位於 JSON 請求負載中的事實,提取請求負載(在本例中,提取意味著從 JSON 負載中獲取數組)就像使用 php json_decode 函數一樣簡單。

class ApiController extends AbstractController
{
    #[Route('/api/entity', name: 'api_v1_post_entity', methods: ['POST'])]
    public function saveAction(Request $request,): JsonResponse
    {
        $requestData = json_decode($request->getContent(), true);
        // validate data
    }
}
登入後複製
登入後複製
登入後複製

驗證數據

為了驗證數據,我們需要三個元素:

  • 用來定義驗證規則。
  • 用於將請求的資料轉換為有效的物件。
  • 用於根據這些規則驗證提取的資料。

定義驗證規則

對於第一個,我們將建立一個 DTO(資料傳輸物件)來表示傳入的數據,我們將使用 Symfony 驗證約束屬性來指定如何驗證此資料。

readonly class UserInputDTO {
    public function __construct(
        #[NotBlank(message: 'Email cannot be empty')]
        #[Email(message: 'Email must be a valid email')]
        public string $email,
        #[NotBlank(message: 'First name cannot be empty')]
        public string $firstname,
        #[NotBlank(message: 'Last name cannot be empty')]
        public string $lastname,
        #[NotBlank(message: 'Date of birth name cannot be empty')]
        #[Date(message: 'Date of birth must be a valid date')]
        public string $dob
    ){}
}
登入後複製

如您所見,我們在最近建立的 DTO 中定義了輸入資料驗證規則。這些規則如下:

  • 電子郵件:不能為空且必須是有效的電子郵件
  • 名字:不能為空
  • 姓氏: 不能為空
  • dob(出生日期):不能為空且必須是有效日期。

將請求資料非規範化到 DTO 中

對於第二個,我們將使用 Symfony 標準化器元件,透過它我們能夠將請求傳入資料對應到我們的 DTO 中。

class ApiController extends AbstractController
{
    #[Route('/api/entity', name: 'api_v1_post_entity', methods: ['POST'])]
    public function saveAction(Request $request, SerializerInterface $serializer): JsonResponse
    {
        $requestData = json_decode($request->getContent(), true);
        $userInputDTO = $serializer->denormalize($requestData, UserInputDTO::class);
    }
}
登入後複製

如上所示,denormalize 方法完成這些工作,並且只需一行程式碼,我們就可以用傳入的資料填入 DTO。

驗證 DTO

最後,為了驗證數據,我們將依賴 Symfony 驗證器服務,該服務將接收我們最近非規範化的 DTO 實例(它將攜帶傳入資料),並根據 DTO 規則驗證資料。

class ApiController extends AbstractController
{
    #[Route('/api/entity', name: 'api_v1_post_entity', methods: ['POST'])]
    public function saveAction(Request $request,): JsonResponse
    {
        $requestData = json_decode($request->getContent(), true);
        // validate data
    }
}
登入後複製
登入後複製
登入後複製

識別域

到目前為止,我們已經將提取驗證資料的過程分為四個部分:

  • 從 JSON 請求負載中提取數組。
  • 建立一個 DTO 來表示傳入資料及其驗證規則。
  • 將陣列非規範化為包含驗證規則的 DTO。
  • 驗證 DTO。

現在的問題是:這些部分中哪些屬於我們的領域?
為了回答這個問題,我們來分析一下涉及的流程:

1.- 擷取資料:這部分只使用「json_decode」函數將傳入的資料從 json 轉換為陣列。它不添加業務邏輯,因此這不屬於該域。

2.- DTO:DTO 包含與輸入資料關聯的屬性以及如何驗證它們。這意味著 DTO 包含業務規則(驗證規則),因此它屬於網域。

3.- 反規範化資料:這部分只是使用基礎設施服務(框架元件)將資料反規範化為物件。這不包含業務規則,因此這不屬於我們的網域。

4.- 驗證資料:與反規範化資料流程相同,驗證資料流程也使用基礎設施服務(框架元件)來驗證傳入資料。這不包含業務規則,因為它們是在 DTO 中定義的,因此它也不會是我們領域的一部分。

分析完最後一點後,我們可以得出結論,只有 DTO 才是我們領域的一部分。那麼,我們要如何處理其餘的程式碼呢?

創建應用程式服務

就我個人而言,我喜歡將這種過程(提取、反規範化和驗證資料)包含到應用程式層或服務層中。為什麼?我們來介紹一下應用層。

應用層

簡而言之,應用層負責編排與協調,將業務邏輯留給領域層。此外,它充當領域層和外部層(例如表示層(UI)和基礎設施層)之間的中介。
從上面的定義開始,我們可以將 ExtractingDenormalizingValidating 流程包含到應用程式層的服務中,因為:

  • 它協調傳入的資料處理。
  • 它使用基礎設施服務(PHP JSON 函數、Symfony 規範化元件和 Symfony 驗證元件)來處理傳入資料。
  • 它透過將 DTO 傳遞到驗證基礎設施服務來應用網域規則。

完美,我們將建立一個應用程式服務來管理此流程。我們要怎麼做呢?我們如何管理責任?

分析責任

單一職責原則(SRP)規定每個類別應該只負責應用程式行為的一部分。如果一個類別有多重職責,那麼理解、維護和修改就會變得更加困難。

這對我們有何影響?我們來分析一下。
到目前為止,我們知道我們的應用程式服務必須提取、反規範化並驗證傳入的資料。知道了這一點,就很容易提取出以下職責:

  • 擷取資料
  • 反規範化資料
  • 驗證資料

我們應該將這些職責分成 3 個不同的服務嗎?我不這麼認為。讓我解釋一下。

如我們所見,每個職責都由基礎設施功能或元件管理:

  • 提取責任:PHP json_decode 函數
  • 反規範化資料責任:Symfony 規範化元件
  • 驗證資料責任:Symfony 驗證元件

由於應用程式服務可以將這些職責委託給基礎架構服務,因此我們可以建立更抽象的職責(處理資料)並將其指派給應用程式服務。

class ApiController extends AbstractController
{
    #[Route('/api/entity', name: 'api_v1_post_entity', methods: ['POST'])]
    public function saveAction(Request $request,): JsonResponse
    {
        $requestData = json_decode($request->getContent(), true);
        // validate data
    }
}
登入後複製
登入後複製
登入後複製

如上所示,DataProcessor 應用程式服務使用 json_decode 函數以及 Symfony 規範器和驗證器服務來處理輸入請求並傳回新的且經過驗證的 DTO。所以我們可以說 DataProcessor 服務:

  • 協調與輸入資料處理相關的所有任務。
  • 透過域業務規則 (DTO) 與外界(基礎設施服務)進行通訊。

您可能已經注意到,當驗證過程發現錯誤時,DataProcessor 服務會拋出 Symfony ValidationException 。在本系列的下一篇文章中,我們將學習如何應用業務規則來建立錯誤並最終將其呈現給客戶。

我知道我們可以刪除 DataProcessor 服務並使用 MapRequestPayload 作為服務應用程式層來提取、反規範化和驗證數據,但是,考慮到本文的上下文,我認為這樣更方便這樣寫。

結論

在第一篇文章中,我們將重點放在從流程圖中提取和驗證資料流程。我們列出了此過程中涉及的任務,並且了解如何偵測哪些部分屬於該網域。
知道哪些部分屬於網域,我們編寫了一個應用程式層服務,連接域規則的基礎設施服務並協調提取和驗證資料過程。
在下一篇文章中,我們將探討如何定義業務規則來管理異常,我們還將建立一個網域服務,負責將輸入 DTO 轉換為持久實體。

以上是創建專注的領域應用程式。 Symfony 方法(第 1 部分)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板