在上一篇文章中,我們分析了 symfony 序列化器和驗證器元件如何充當基礎設施服務,為我們提供幫助我們在應用程式中執行常見任務的工具。我們也了解了為什麼 UserInputDTO 類別是屬於我們網域的元素,因為它包含業務規則以及如何建立應用程式層服務來執行提取和驗證資料流。
在第二部分中,我們將了解如何管理驗證錯誤,並且正如我們在第一部分中所做的那樣,我們將識別哪些部分屬於該網域。
依照使用驗證約束建立的規則驗證 UserInputDTO 後,Symfony 驗證器元件將傳回驗證錯誤。
public function processData(string $content, string $dtoClass): object { $requestData = json_decode($content, true); $userInputDTO = $serializer->denormalize($requestData, UserInputDTO::class); $errors = $validator->validate($userInputDTO); if(count($errors) > 0) { throw new ValidationFailedException($errors); } return $userInputDTO }
如您在上面的程式碼中所看到的,如果驗證方法發現錯誤,則會拋出 ValidationException 類型的例外。從這裡開始,我們必須決定如何向使用者顯示錯誤(網域/業務規則)以及我們將依賴哪些工具以便錯誤正確地到達使用者(基礎設施和應用程式)。
我們必須考慮的第一件事是,我們希望在驗證錯誤發生時捕獲它們。為了實現這一目標,我們將依賴基礎設施層。
Symfony 核心附帶了一組內建核心事件來監聽特殊事件。其中一個事件是內核異常事件,當拋出異常時會觸發該事件。讓我們用它來捕獲 ValidationException 錯誤。
class KernelSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ KernelEvents::EXCEPTION => 'onException' ]; } public function onException(ExceptionEvent $event): void { $exception = $event->getThrowable(); if($exception instanceof ValidationFailedException){ // Business rules to build the errors } } }
正如我們在上面的程式碼中所看到的,KernelSubscriber 不斷監聽KernelException 事件,並且僅當捕獲的異常是 ValidationFailedException 類。
從這裡開始,我們必須定義當
onException 方法偵測到這是一個驗證錯誤時將執行的邏輯。
class ValidationErrorsBuilder { public function buildErrors(ValidationFailedException $exception): array { $errors = []; foreach ($exception->getViolations() as $violation) { $errors[$violation->getPropertyPath()] = $violation->getMessage(); } return $errors; } }
ValidationErrorsBuilder 程式碼非常簡單:它循環違規錯誤並建立一個關聯數組,其中鍵是產生錯誤的屬性,值是錯誤訊息。
現在是時候使用我們的 ValidationErrorsBuilder 網域服務了。我們在 KernelSubscriber onException 方法上使用它。
public function processData(string $content, string $dtoClass): object { $requestData = json_decode($content, true); $userInputDTO = $serializer->denormalize($requestData, UserInputDTO::class); $errors = $validator->validate($userInputDTO); if(count($errors) > 0) { throw new ValidationFailedException($errors); } return $userInputDTO }
如您所見,在知道異常是 ValidationFailedException 後,我們使用網域服務來取得驗證錯誤陣列。
現在,讓我們來看看下面的程式碼:
class KernelSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ KernelEvents::EXCEPTION => 'onException' ]; } public function onException(ExceptionEvent $event): void { $exception = $event->getThrowable(); if($exception instanceof ValidationFailedException){ // Business rules to build the errors } } }
我們新增了新行,在其中設定 Symfony JsonResponse 將錯誤陣列儲存為新回應,並指定傳回的 HTTP 程式碼將是 400 Bad Request。
我們依賴 Symfony Response HTTP_BAD_REQUEST 常數來指定回應 HTTP 程式碼。由於我們在以網域為中心的環境中工作,因此我們可以建立自訂網域類別(例如php 枚舉),但是,由於我們只需要處理標準HTTP 程式碼並且沒有特定的自訂需求,因此我們可以使用Symfony HTTP 程式碼雖然這讓我們更依賴這個框架。
到目前為止我們還沒有討論應用層。我們在文章一開始就說過,Symfony 框架附帶了一個有用的內建事件,例如我們使用的事件:核心異常事件。此外,symfony框架也為我們提供了EventSubscriberInterface,透過它我們可以建立自訂事件訂閱者並監聽我們需要的事件。
從這些資訊中,我們可以得出結論,symfony 為我們提供了內核異常事件和 EventSubscriberInterface 但我們必須使用該介面來建立訂閱者,指定我們要監聽哪些事件。讓我們繼續:
這聽起來很熟悉嗎?是的,事件訂閱者負責在拋出異常後管理驗證錯誤的編排和協調,因此我們可以說事件訂閱者將充當應用程式服務。
如果我們想更進一步,我們可以建立一個應用程式層服務並在訂閱者中使用它。
class ValidationErrorsBuilder { public function buildErrors(ValidationFailedException $exception): array { $errors = []; foreach ($exception->getViolations() as $violation) { $errors[$violation->getPropertyPath()] = $violation->getMessage(); } return $errors; } }
public function onException(ExceptionEvent $event): void { $exception = $event->getThrowable(); if($exception instanceof ValidationFailedException){ $errors = $this->validationErrorsBuilder->buildErrors($exception); } }
現在,ValidationErrorsProcessor 將充當協調驗證錯誤回應管理並使用 ValidationErrorsBuilder 網域服務的應用程式服務。
在本系列的第二篇文章中,我們已經確定了驗證錯誤管理過程的哪些元件屬於該網域、我們使用了基礎設施的哪些元素以及核心訂閱者如何充當應用程式服務。
下一篇我們將實體持久化到資料庫中,並分析如何分離將DTO轉換為可持久化實體的邏輯。
以上是創建專注的領域應用程式。 Symfony 方法(管理驗證錯誤)的詳細內容。更多資訊請關注PHP中文網其他相關文章!