mops1k / request-object-resolver-bundle
Bundle for resolving and validate http request to object
Installs: 2 101
Dependents: 0
Suggesters: 0
Security: 0
Stars: 9
Watchers: 1
Forks: 0
Open Issues: 0
Type:symfony-bundle
Requires
- php: >=8.1
- doctrine/inflector: ^2.0
- symfony/framework-bundle: ^6.0
- symfony/property-access: ^6.0
- symfony/serializer: ^6.0
- symfony/validator: ^6.0
Requires (Dev)
- doctrine/annotations: ^1.14
- phpstan/phpstan: ^1.10
- phpstan/phpstan-phpunit: ^1.3
- phpstan/phpstan-strict-rules: ^1.5
- phpunit/php-code-coverage: ^10.1
- phpunit/phpunit: ^10.5
- roave/security-advisories: dev-latest
- symplify/config-transformer: ^12.0
- symplify/easy-coding-standard: ^11.5
README
This bundle can help you to deserialize incoming request parameters from symfomy http request object to your DTO objects.
Deserialized objects are validated via symfony/validator, so when using such objects in controllers, we can be sure that the data format and their set in the object are correct and ready for further processing.
Bundle can deserialize:
- route parameters (attribute
RequestObjectResolverBundle\Attribute\Path
) - query parameters (attribute
RequestObjectResolverBundle\Attribute\Query
) - content body (supports all symfony serializer formats) (attribute
RequestObjectResolverBundle\Attribute\Content
) - form parameters (attribute
RequestObjectResolverBundle\Attribute\Form
) - uploaded files (attribute
RequestObjectResolverBundle\Attribute\Form
)
Install
composer require mops1k/request-object-resolver-bundle
Use
Example:
<?php use RequestObjectResolverBundle\Attribute\Query; use RequestObjectResolverBundle\Attribute\Path; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Validator\Constraints as Assert; class ExampleRequest { #[Assert\NotNull] #[Assert\GreaterThan(0)] public ?int $id = null; #[Assert\NotNull] #[Assert\NotBlank] public ?string $name = null; } /** * Request path example: /25?name=Julian */ class ExampleController extends AbstractController { #[Route('/{id}', methods: [Request::METHOD_GET])] public function __invoke(#[Query, Path] ExampleRequest $exampleRequest): JsonResponse { // some logic with $exampleRequest return new JsonResponse([ 'id' => $exampleRequest->id, 'name' => $exampleRequest->name, ]); } }
Map field to another name
Whole library attributes have a map parameter. With this parameter you can map from one field name to another.
Example:
<?php use RequestObjectResolverBundle\Attribute\Query; use RequestObjectResolverBundle\Attribute\Path; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Validator\Constraints as Assert; class ExampleRequest { #[Assert\NotNull] #[Assert\GreaterThan(0)] public ?int $id = null; #[Assert\NotNull] #[Assert\NotBlank] public ?string $title = null; } /** * Request path example: /25?name=Julian */ class ExampleController extends AbstractController { #[Route('/{id}', methods: [Request::METHOD_GET])] public function __invoke(#[Query(map: ['name' => 'title']), Path] ExampleRequest $exampleRequest): JsonResponse { // some logic with $exampleRequest return new JsonResponse([ 'id' => $exampleRequest->id, 'title' => $exampleRequest->name, ]); } }
Skip dto validation
If your logic does not need automatic validation of the request object for some reason, then you can disable it
with RequestObjectResolverBundle\Attribute\SkipValidation
attribute.
Example:
<?php use RequestObjectResolverBundle\Attribute\Query; use RequestObjectResolverBundle\Attribute\Path; use RequestObjectResolverBundle\Attribute\SkipValidation; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Validator\Constraints as Assert; class ExampleRequest { #[Assert\NotNull] #[Assert\GreaterThan(0)] public ?int $id = null; #[Assert\NotNull] #[Assert\NotBlank] public ?string $name = null; } /** * Request path example: /-1?name= */ class ExampleController extends AbstractController { #[Route('/{id}', methods: [Request::METHOD_GET])] public function __invoke(#[Query, Path, SkipValidation] ExampleRequest $exampleRequest): JsonResponse { // some logic with $exampleRequest return new JsonResponse([ 'id' => $exampleRequest->id, 'name' => $exampleRequest->name, ]); } }
Validation groups
If you want to use validation groups, then use attribute \RequestObjectResolverBundle\Attribute\ValidationGroups
.
Example:
<?php use RequestObjectResolverBundle\Attribute\Query; use RequestObjectResolverBundle\Attribute\Path; use RequestObjectResolverBundle\Attribute\ValidationGroups; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Validator\Constraints as Assert; class ExampleRequest { #[Assert\NotNull] #[Assert\GreaterThan(0, groups: ['default'])] public ?int $id = null; #[Assert\NotNull] #[Assert\NotBlank] public ?string $name = null; } /** * Request path example: /25?name=Julian */ class ExampleController extends AbstractController { #[Route('/{id}', methods: [Request::METHOD_POST])] public function __invoke(#[Query, Path, ValidationGroups(groups: 'default')] ExampleRequest $exampleRequest): JsonResponse { // some logic with $exampleRequest return new JsonResponse([ 'id' => $exampleRequest->id, 'name' => $exampleRequest->name, ]); } }
Serialization context
If you want to add some serialization context, then in attributes you can set serializationContext
property.
Example:
<?php use RequestObjectResolverBundle\Attribute\Query; use RequestObjectResolverBundle\Attribute\Path; use RequestObjectResolverBundle\Attribute\ValidationGroups; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; class ExampleRequest { #[Assert\NotNull] #[Assert\GreaterThan(0)] #[Groups(['default'])] public ?int $id = null; #[Assert\NotNull] #[Assert\NotBlank] public ?string $name = null; } /** * Request path example: /25?name=Julian */ class ExampleController extends AbstractController { #[Route('/{id}', methods: [Request::METHOD_POST])] public function __invoke(#[Query(serializerContext: ['groups': ['default']]), Path] ExampleRequest $exampleRequest): JsonResponse { // some logic with $exampleRequest return new JsonResponse([ 'id' => $exampleRequest->id, 'name' => $exampleRequest->name, // will throw error as uninitialized property ]); } }
If you want to set context to all request parts which you want to deserialize to object,
use \RequestObjectResolverBundle\Attribute\SerializerContext
attribute.
<?php use RequestObjectResolverBundle\Attribute\Query; use RequestObjectResolverBundle\Attribute\Path; use RequestObjectResolverBundle\Attribute\SerializerContext; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; class ExampleRequest { #[Assert\NotNull] #[Assert\GreaterThan(0)] #[Groups(['default'])] public ?int $id = null; #[Assert\NotNull] #[Assert\NotBlank] public ?string $name = null; } /** * Request path example: /25?name=Julian */ class ExampleController extends AbstractController { #[Route('/{id}', methods: [Request::METHOD_POST])] public function __invoke(#[Query, Path, SerializerContext(['groups': ['default']])] ExampleRequest $exampleRequest): JsonResponse { // some logic with $exampleRequest return new JsonResponse([ 'id' => $exampleRequest->id, 'name' => $exampleRequest->name, // will throw error as uninitialized property ]); } }
Overriding values with request parts combination
These are table of request parts priority overriding (if have same key name):
Example. If you handle Path
, Query
and Content
in same object and all of them have same field (id for example),
then resulting field value will be from Form
request part.