nzour / symfony-advanced-resolving
Installs: 4
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
Type:symfony-bundle
Requires
- php: >=8.0
- symfony/serializer-pack: ^1.1
Requires (Dev)
- jetbrains/phpstorm-stubs: ^2022.1
- phpunit/phpunit: ^9.5
- psalm/plugin-symfony: ^3.1
- roave/security-advisories: dev-latest
- symfony/config: ^5.3
- symfony/dependency-injection: ^5.3
- symfony/http-kernel: ^5.3
- symfony/serializer: ^5.3
- vimeo/psalm: ^4.23
This package is auto-updated.
Last update: 2025-03-11 02:13:06 UTC
README
Requirements
- php >= 8.0
- symfony >= 5.3
Installation
composer require nzour/symfony-advanced-resolving
Important: Make sure bundle \AdvancedResolving\AdvancedResolvingBundle
become enabled, otherwise enable it in bundles.php
Examples
#1 Using #[FromQuery] attribute:
#[AsController, Route(path: '/foo')] final class FooController { #[Route(methods: ['GET'])] public static function index(#[FromQuery] string $value): JsonResponse { return new JsonResponse([ 'value' => $value, ]); } }
GET {host}/foo?value={value}
#2 Using #[FromQuery] attribute with different param name:
#[AsController, Route(path: '/foo')] final class FooController { #[Route(methods: ['GET'])] public static function index( #[FromQuery(paramName: 'foobar')] string $value, #[FromQuery] int $score, ): JsonResponse { return new JsonResponse([ 'value' => $value, 'score' => $score, ]); } }
GET {host}/foo?foobar={value}&score={score}
#3 Using #[FromQuery] with class typehint
final class FooQuery { public function __construct( public string $value, public int $score, ) { } } #[AsController, Route(path: '/foo')] final class FooController { #[Route(methods: ['GET'])] public static function index(#[FromQuery] FooQuery $fooQuery): JsonResponse { return new JsonResponse($fooQuery); } }
GET {host}/foo?value={value}&score={score}
Note: it's not possible to rename properties of FooQuery via additional attributes
#4 Using #[FromBody]
final class FooCommand { public function __construct( public string $foobar, public int $barfoo, ) { } } #[AsController, Route(path: '/foo')] final class FooController { #[Route(methods: ['POST'])] public static function command(#[FromBody] FooCommand $command): JsonResponse { return new JsonResponse([ 'command' => $command, ]); } }
Docs
Feature based on Symfony's ArgumentValueResolver flow, therefore make sure your controllers tagged with controller.service_arguments
or marked via #[AsController]
attribute.
Built in
-
bin/console debug:meta-resolvers
- View list of defined meta resolvers -
FromBody
Implementation class FromBodyMetaResolver
Uses symfony serializer to instantiate objects from plain data, default format of data is json. There is a way to specify another format:
#[FromBody(format: XmlEncoder::FORMAT)]
. It is not possible to change format globally. -
FromQuery
Implementation class FromQueryMetaResolver
You can specify different param name
#[FromQuery(paramName: 'foobar')]
Parameter FromQuery::$disableTypeEnforcement is responsible for flag AbstractObjectNormalizer::DISABLE_TYPE_ENFORCEMENT when resolve object. It's value true by default.
Not implemented yet
- FromHeader
- FromForm
Errors
- Symfony Serializer's Exceptions
- NonNullableArgumentWithNoDefaultValueFromQueryParamsException - Only for #[FromQuery]. Argument is not nullable, has no default value and there is also no value specified from request
- CouldNotCreateInstanceFromQueryParamsException - Just like above, but if argument's typehint is class
Extend by user land
If you want to create your own attribute and algoritm that resolves it, follow steps:
- Define your attribute or use existing attribute
- Define class-service, that implements MetaResolverInterface
- Method supportedAttribute should return class-string of which attribute it supports
- Mark your service with tag
meta-resolver
Limitations
-
Built in resolvers work with Symfony Serializer
-
No interop with Symfony Validator (yet, or maybe not yet)
-
Built in attributes work only with endpoint's parameters, it's not possible to combine attributes:
final class FooDto { public function __construct( #[FromQuery] public string $foobar, public int $barfoo, ) { } } #[AsController] final class FooController { #[Route(path: '/foo', methods: ['POST']) public function index(#[FromBody] FooDto $dto): void { // ... } }
The entire class FooDto would be compiled from Body parameters.
However property FooDto::$foobar is marked with attribute #[FromQuery], resolver would not try to find parameter foobar inside query-parameters and try set it as property's value.