Skip to content

Commit

Permalink
Tried to make the default value resolving more clear
Browse files Browse the repository at this point in the history
  • Loading branch information
Iltar van der Berg committed Apr 18, 2016
1 parent c35b56f commit fdce9c6
Showing 1 changed file with 40 additions and 18 deletions.
58 changes: 40 additions & 18 deletions cookbook/controller/argument_value_resolver.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ Extending Action Argument Resolving
===================================

.. versionadded:: 3.1
The ``ArgumentResolver`` and value resolvers are added in Symfony 3.1.
The ``ArgumentResolver`` and value resolvers were introduced in Symfony 3.1.

In the book, you've learned that you can get the :class:`Symfony\\Component\\HttpFoundation\\Request`
object by adding a ``Request`` argument to your controller. This is done
via the :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver`.
By creating and registering custom argument value resolvers, you can extend
object via an argument in your controller. This argument has to be typehinted
by the ``Request`` class in order to be recognized. This is done via the
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver`. By
creating and registering custom argument value resolvers, you can extend
this functionality.

Functionality Shipped With The HttpKernel
Expand Down Expand Up @@ -74,7 +75,7 @@ This interface specifies that you have to implement two methods::
given argument. ``resolve()`` will only be executed when this returns ``true``.
``resolve()``
This method will resolve the actual value for the argument. Once the value
is resolved, you should `yield`_ the value to the ``ArgumentResolver``.
is resolved, you must `yield`_ the value to the ``ArgumentResolver``.

Both methods get the ``Request`` object, which is the current request, and an
:class:`Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata`.
Expand Down Expand Up @@ -131,24 +132,15 @@ retrieved from the token storage::
}

In order to get the actual ``User`` object in your argument, the given value
should fulfill the following requirements:
must fulfill the following requirements:

* The argument type (of the method signature) must be typehinted as ``User``;
* The security token must be present;
* The value should be an instance of the ``User``.
* An argument must be typehinted as ``User`` in your action method signature;
* A security token must be present;
* The value must be an instance of the ``User``.

When all those requirements are met and true is returned, the ``ArgumentResolver``
calls ``resolve()`` with the same values as it called ``supports()``.

.. tip::

You can leverage the ``DefaultValueResolver`` by making your resolver
accept only mandatory arguments. Given your signature is `User $user = null`,
the above example will not hit ``resolve()`` as one of the conditions
does not match. Eventually when the ``DefaultValueResolver`` is asked
to resolve this, it will simply add the default value from the method
signature, which results in ``null``.

That's it! Now all you have to do is add the configuration for the service
container. This can be done by tagging the service with ``kernel.argument_resolver``
and adding a priority.
Expand Down Expand Up @@ -206,3 +198,33 @@ and adding a priority.
$container->setDefinition('app.value_resolver.user', $definition);
.. _`yield`: http://php.net/manual/en/language.generators.syntax.php

Creating an Optional User Resolver
----------------------------------

When you want your user to be optional, e.g. when your page is behind a
firewall that also allows anonymous authentication, you might not always
have a security user. To get this to work, you only have to change your
method signature to `UserInterface $user = null`.

When you take the ``UserValueResolver`` from the previous example, you can
see there is no logic in case of failure to comply to the requirements. Default
values in are defined in the signature and are available in the ``ArgumentMetadata``.
When a default value is available and there are no resolvers that support
the given value, the ``DefaultValueResolver`` is triggered. This Resolver
takes the default value of your argument and yields it to the argument list::

namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;

final class DefaultValueResolver implements ArgumentValueResolverInterface
{
public function supports(Request $request, ArgumentMetadata $argument)
{
return $argument->hasDefaultValue();
}

public function resolve(Request $request, ArgumentMetadata $argument)
{
yield $argument->getDefaultValue();
}
}

0 comments on commit fdce9c6

Please sign in to comment.