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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// src/Controller/SessionController.php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Routing\Annotation\Route;
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// ...
use Symfony\Component\HttpKernel\Attribute\ValueResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\SessionValueResolver;
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:
1 2 3 4 5 6 7 8 9 10 11
// src/ValueResolver/IdentifierValueResolver.php
namespace App\ValueResolver;
use Symfony\Component\HttpKernel\Attribute\AsTargetedValueResolver;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
#[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 if it's called explicitly. Therefore, it will only be used in cases like
this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// ...
use Symfony\Component\HttpKernel\Attribute\ValueResolver;
class BookingController
{
#[Route('/booking/{id}')]
public function show(
#[ValueResolver('booking_id')]
Booking $booking
): Response
{
// ...
}
}
Amazing! It will allow to reduce DI configs while maintaining their features