The bundle provides a simple way to map requests into DTO(Data Transfer Object), validate and inject into Your Symfony project controller. It automatically deserealize request content into provided DTO, validates it (if required) and injects DTO into your controller argument(Symfony Argument Resolver), and finally you have a fully valid DTO in your controller.
- Request deserialization into dto with configurable serializer
- Automatic configurable validation using Symfony validator
- Easy to configure converter options for each request/DTO via annotations/PHP8 attributes(preload, serializer, validator options etc)
- Entity preload into DTO before request deserialization
- PHP 7.4+|8.x
- Symfony 4.4+|5.3+|6.0+
Open a command console, enter your project directory and execute the following command to download the latest version of this bundle:
composer require pfilsx/dto-param-converter-bundle
Register bundle into config/bundles.php
(Flex did it automatically):
return [
...
Pfilsx\DtoParamConverter\DtoParamConverterBundle::class => ['all' => true],
];
Documentation can be found here.
- Create DTO class with converter annotation/attribute
use Pfilsx\DtoParamConverter\Annotation\Dto;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @Dto()
*/
final class SomeDto
{
/**
* @Assert\NotBlank
*/
public ?string $title = null;
...
}
- Use DTO in your controller
public function postAction(SomeDto $someDto): Response
{
// here dto already loaded and validated
}
- Link DTO with entity(if preload required)
/**
* @Dto(linkedEntity=SomeEntity::class)
*/
final class SomeDto
{
...
}
- Create entity-dto mapper(if preload required)
use Pfilsx\DtoParamConverter\Contract\DtoMapperInterface;
final class SomeDtoMapper implements DtoMapperInterface
{
public static function getDtoClassName(): string
{
return SomeDto::class;
}
/**
* @param object|SomeEntity $entity
* @param SomeDto|object $dto
*/
public function mapToDto(object $entity, object $dto): void
{
// your entity to dto mapping logic
$dto->title = $entity->getTitle();
...
}
}
You can configure bundle globally via config/packages/dto_param_converter.yaml
:
dto_param_converter:
preload: # entity preload into dto configuration
enabled: true # enable/disable entity preloading before request mapping
methods: ['GET', 'PATCH'] # request methods that require the entity preload
optional: false # if false the converter will throw NotFoundHttpException on entity for preloading not found otherwise it will ignore preloading
entity_manager_name: null # entity manager name to use for entity preloading. useful on multiple managers
serializer: # request deserialization configuration
service: serializer # serializer should be used for request deserialization
normalizer_exception_class: 'Pfilsx\DtoParamConverter\Exception\NotNormalizableConverterValueException' # exception class that should be thrown on normalization errors. not actual after 5.4 symfony/serializer
strict_types: # types enforcement on denormalization
enabled: true
excluded_methods: ['GET'] # excluded request methods for types enforcement
validation: # dto validation configuration
enabled: true # enable/disable validation of dto
excluded_methods: ['GET'] # excluded request methods for validation
exception_class: 'Pfilsx\DtoParamConverter\Exception\ConverterValidationException' # exception class that should be thrown on validation errors
Or You can configure converter for each action
/**
* @DtoResolver(options={
* DtoArgumentResolver::OPTION_SERIALIZER_CONTEXT: {},
* DtoArgumentResolver::OPTION_VALIDATOR_GROUPS: {},
* DtoArgumentResolver::OPTION_PRELOAD_ENTITY: true,
* DtoArgumentResolver::OPTION_STRICT_PRELOAD_ENTITY: true,
* DtoArgumentResolver::OPTION_ENTITY_ID_ATTRIBUTE: null,
* DtoArgumentResolver::OPTION_ENTITY_MANAGER: null,
* DtoArgumentResolver::OPTION_ENTITY_MAPPING: {}
* DtoArgumentResolver::OPTION_ENTITY_EXPR: null,
* DtoArgumentResolver::OPTION_VALIDATE: false
* })
*/
public function someAction(SomeDto $someDto): Response
{
...
}
This bundle is released under the MIT license.
If you'd like to contribute, feel free to propose a pull request, create issue or just contact me :)