ser/dto-request-bundle

将 Symfony 请求转换为 DTO 对象。

0.1.3 2024-03-03 10:28 UTC

This package is auto-updated.

Last update: 2024-09-09 07:57:00 UTC


README

使用零配置在你的 DTO 对象上映射请求。这个库非常简单且快速。

安装

composer require ser/dto-request-bundle

支持

库支持所有 PHP8.2 功能。你可以使用只读类和属性、构造函数中的参数等。请查看示例。

使用方法

  1. 创建 DTO
class RegistrationData
{
    public string $firstName;
    public string $lastName;

    public function __construct(
        public readonly string $email,
        public readonly string $password
    ) {
    }
}
  1. 在控制器中使用你的 DTO,例如。
<?php
   declare(strict_types=1);
   
   namespace App\Controller\User;
   
   use Symfony\Component\HttpFoundation\JsonResponse;
   use App\Dto\RegistrationData;
   
   class RegistrationController
   {
        public function __invoke(RegistrationData $dto): JsonResponse
        {
            return new JsonResponse($dto);
        }
   }

映射器

你可以使用映射器将集合和类映射到属性。

示例

  1. 集合映射。
<?php

declare(strict_types=1);

namespace App\Dto;

use Ser\DtoRequestBundle\Attributes\MapToArrayOf;

class Address
{
    public readonly string $city;
    public readonly string $country;
}

class RegistrationData
{
    public string $firstName;
    public string $lastName;

    #[MapToArrayOf(Address::class)]
    public array $addresses;

    public function __construct(
        public readonly string $email,
        public readonly string $password
    ) {
    }
}
  1. 将类映射到接口或混合/对象值。
<?php

declare(strict_types=1);

namespace App\Dto;

use Ser\DtoRequestBundle\Attributes\MapTo;
use DateTimeInterface;

class AddressInterface {}

class Address implements AddressInterface
{
    public readonly string $city;
    public readonly string $country;
}

class RegistrationData
{
    public string $firstName;
    public string $lastName;

    #[MapTo(Address::class)]
    public AddressInterface $addresses;
    
    #[MapTo(DateTime::class)]
    public DateTimeInterface $birthday;

    public function __construct(
        public readonly string $email,
        public readonly string $password
    ) {
    }
}

验证

对于验证,你可以使用 SymfonyValidator。

  1. 使用约束创建 DTO
<?php

declare(strict_types=1);

namespace App\Dto;

use App\Constraint\UniqueEmail;
use Symfony\Component\Validator\Constraints as Assert;

class RegistrationData
{
    #[Assert\Length(min: 3, max: 75)]
    #[Assert\NotBlank]
    public string $firstName;

    #[Assert\Length(min: 3, max: 75)]
    #[Assert\NotBlank]
    public string $lastName;

    public function __construct(
        #[Assert\NotBlank]
        #[Assert\Email]
        #[UniqueEmail] // this is custom constraint
        public readonly string $email,
        #[Assert\NotBlank]
        public readonly string $password
    ) {
    }
}
  1. 在服务或控制器中执行验证。2.1. 在服务中的验证(最佳选项)
<?php

declare(strict_types=1);

namespace App\Controller\User;

use App\Service\ErrorInterface;
use App\Service\ResponseFactoryInterface;
use App\Dto\RegistrationData;
use App\Service\RegistrationService;
use Symfony\Component\HttpFoundation\Response;

final class RegistrationController
{
    public function __construct(
        private readonly RegistrationService $registrationService,
        private readonly ResponseFactoryInterface $responseFactory,
    ) {
    }

    public function __invoke(RegistrationData $registrationData): Response
    {
        $result = $this->registrationService->register($registrationData);

        if ($result instanceof ErrorInterface) {
            return $this->responseFactory->createResponse(ErrorView::create($result), 400);
        }
        
        return $this->responseFactory->createResponse(UserView::create($result), 201);
    }
}
<?php

declare(strict_types=1);

namespace App\Service\User;

use App\Entity\User;
use App\Service\ErrorInterface;
use App\Dto\RegistrationData;
use App\Model\UserInterface;
use App\Repository\UserRepositoryInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;

final class RegistrationService
{
    public function __construct(
        private readonly UserRepositoryInterface $userRepository,
        private readonly UserPasswordHasherInterface $userPasswordHasher,
        private readonly ValidatorInterface $validator,
    ) {
    }

    public function register(RegistrationData $registrationData): UserInterface|ErrorInterface
    {
        $violations = $this->validator->validate($registrationData);
        
        if ($violations->count() !== 0) {
            return new Error($validationError);
        }
        
        $user = new User($registrationData->email, $registrationData->password);

        // save user to DB

        return $user;
    }

嵌套 DTO 的验证。

对于嵌套 DTO 的验证,使用包含 dto 的类的约束 级联。示例

<?php

declare(strict_types=1);

namespace App\Dto;

use Symfony\Component\Validator\Constraints as Assert;

class Address
{
    #[Assert\Length(min: 3, max: 75)]
    #[Assert\NotBlank]
    public readonly string $city;
    
    #[Assert\Length(min: 3, max: 75)]
    #[Assert\NotBlank]
    public readonly string $country;
}

#[Assert\Cascade]
class UserData
{
    #[Assert\Length(min: 3, max: 75)]
    #[Assert\NotBlank]
    public string $firstName;

    #[Assert\Length(min: 3, max: 75)]
    #[Assert\NotBlank]
    public string $lastName;
    
    #[Assert\NotNull]
    public ?Address $address;
}

待办事项:构建对象后添加验证器 TODO:添加从字符串到整数和其他铸造器的转换

检查第 68 行