New in Symfony 6.3: Targeted Value Resolvers
In Symfony, argument value resolvers allow to inject certain values in the
arguments of the controllers. For example, if you type-hint any controller
argument with the Request class from HttpFoundation, Symfony injects the
object that represents the current request.
Symfony provides lots of built-in resolvers to inject services, the session, UID
values, default PHP values, etc. In Symfony 6.3 we’re improving this feature to
make it more powerful. First, we’re introducing a new ValueResolver
attribute to explicitly select the resolver to use.
Consider the following example:
// src/Controller/SessionController.php
namespace AppController;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentHttpFoundationSessionSessionInterface;
use SymfonyComponentRoutingAnnotationRoute;
class SessionController
{
#[Route(‚/‘)]
public function __invoke(SessionInterface $session = null): Response
{
// …
}
}
Symfony will call all built-in argument resolvers by priority until one of them
provides a value for this argument. In this example, the SessionValueResolver
(priority 50) will be called before the DefaultValueResolver (priority -100).
That’s why the $session argument will have either the current Session
object or a null value.
If you know that in your application there will always be a session, then you
could do this:
// …
use SymfonyComponentHttpKernelAttributeValueResolver;
use SymfonyComponentHttpKernelControllerArgumentResolverSessionValueResolver;
class SessionController
{
#[Route(‚/‘)]
public function __invoke(
#[ValueResolver(SessionValueResolver::class)]
SessionInterface $session
): Response
{
// …
}
}
The new ValueResolver attribute allows you to explicitly tell Symfony which
resolver should be used to get the value of this argument. For convenience, the
name of all built-in resolvers is their FQCN (e.g. SessionValueResolver::class).
In addition to this, we’ve added another new AsTargetedValueResolver attribute
to create resolvers that can only be called explicitly. Consider the following
argument resolver which transforms booking id values into Booking objects:
// src/ValueResolver/IdentifierValueResolver.php
namespace AppValueResolver;
use SymfonyComponentHttpKernelAttributeAsTargetedValueResolver;
use SymfonyComponentHttpKernelControllerValueResolverInterface;
#[AsTargetedValueResolver(‚booking_id‘)]
class BookingIdValueResolver implements ValueResolverInterface
{
// …
}
Instead of letting Symfony call this resolver for all arguments of all controllers,
the new #[AsTargetedValueResolver] attribute tells Symfony to only use this
resolver is it’s called explicitly. Therefore, it will only be used in cases like
this:
// …
use SymfonyComponentHttpKernelAttributeValueResolver;
class BookingController
{
#[Route(‚/booking/{id}‘)]
public function show(#[ValueResolver(‚booking_id‘)] Booking $booking): Response
{
// …
}
}
Symfony Blog