ser / dto-request-bundle
将 Symfony 请求转换为 DTO 对象。
0.1.3
2024-03-03 10:28 UTC
Requires
- php: ^8.1
- ext-json: *
- symfony/config: ^6.2|^7.0
- symfony/dependency-injection: ^6.2|^7.0
- symfony/http-kernel: ^6.2|^7.0
Requires (Dev)
- phpunit/phpunit: ^10.0
- squizlabs/php_codesniffer: ^3.7
README
使用零配置在你的 DTO 对象上映射请求。这个库非常简单且快速。
安装
composer require ser/dto-request-bundle
支持
库支持所有 PHP8.2 功能。你可以使用只读类和属性、构造函数中的参数等。请查看示例。
使用方法
- 创建 DTO
class RegistrationData { public string $firstName; public string $lastName; public function __construct( public readonly string $email, public readonly string $password ) { } }
- 在控制器中使用你的 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); } }
映射器
你可以使用映射器将集合和类映射到属性。
示例
- 集合映射。
<?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 ) { } }
- 将类映射到接口或混合/对象值。
<?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。
- 使用约束创建 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 ) { } }
- 在服务或控制器中执行验证。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 行