在上一篇文章中,我们分析了 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中文网其他相关文章!