Skip to content

Commit a60c1e6

Browse files
author
Iltar van der Berg
committed
Processed feedback from @wouterj
1 parent e67ee19 commit a60c1e6

File tree

1 file changed

+58
-43
lines changed

1 file changed

+58
-43
lines changed

cookbook/controller/argument_value_resolver.rst

Lines changed: 58 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -7,45 +7,46 @@ Extending Action Argument Resolving
77
.. versionadded:: 3.1
88
The ``ArgumentResolver`` and value resolvers are added in Symfony 3.1.
99

10-
In the book, you've learned that you can add the :class:`Symfony\\Component\\HttpFoundation\\Request`
11-
as action argument and it will be injected into the method. This is done via the
12-
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver`. The ``ArgumentResolver`` uses
13-
several value resolvers which allow you to extend the functionality.
10+
In the book, you've learned that you can get the :class:`Symfony\\Component\\HttpFoundation\\Request`
11+
object by adding a ``Request`` argument to your controller. This is done via the
12+
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver`. By creating and registering custom
13+
argument value resolvers, you can extend this functionality.
1414

1515

1616
Functionality Shipped With The HttpKernel
1717
-----------------------------------------
1818

1919
Symfony ships with four value resolvers in the HttpKernel:
20-
* The :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolver\\ArgumentFromAttributeResolver`
21-
attempts to find a request attribute that matches the name of the argument.
2220

23-
* The :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolver\\RequestValueResolver`
24-
injects the current ``Request`` if type-hinted with ``Request``, or a sub-class thereof.
21+
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolver\\ArgumentFromAttributeResolver`
22+
Attempts to find a request attribute that matches the name of the argument.
2523

26-
* The :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolver\\DefaultValueResolver`
27-
will set the default value of the argument if present and the argument is optional.
24+
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolver\\RequestValueResolver`
25+
Injects the current ``Request`` if type-hinted with ``Request``, or a sub-class thereof.
2826

29-
* The :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolver\\VariadicValueResolver`
30-
verifies in the request if your data is an array and will add all of them to the argument list.
27+
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolver\\DefaultValueResolver`
28+
Will set the default value of the argument if present and the argument is optional.
29+
30+
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolver\\VariadicValueResolver`
31+
Verifies in the request if your data is an array and will add all of them to the argument list.
3132
When the action is called, the last (variadic) argument will contain all the values of this array.
3233

3334
.. note::
3435

35-
In older versions of Symfony this logic was all resolved within the ``ControllerResolver``. The
36-
old functionality is moved to the ``LegacyArgumentResolver``, which contains the previously
36+
Prior to Symfony 3.1, this logic was resolved within the ``ControllerResolver``. The old
37+
functionality is moved to the ``LegacyArgumentResolver``, which contains the previously
3738
used resolving logic.
3839

39-
Adding a New Value Resolver
40-
---------------------------
40+
Adding a Custom Value Resolver
41+
------------------------------
4142

42-
Adding a new value resolver requires one class and one service defintion. In our next example, we
43-
will be creating a shortcut to inject the ``User`` object from our security. Given you write the following
44-
action::
43+
Adding a new value resolver requires one class and one service defintion. In the next example,
44+
you'll create a value resolver to inject the ``User`` object from the security system.. Given
45+
you write the following action::
4546

4647
namespace AppBundle\Controller;
4748

48-
use AppBundle\User;
49+
use AppBundle\Entity\User;
4950
use Symfony\Component\HttpFoundation\Response;
5051

5152
class UserController
@@ -56,7 +57,7 @@ action::
5657
}
5758
}
5859

59-
Somehow you will have to get the ``User`` object and inject it into our action. This can be done
60+
Somehow you will have to get the ``User`` object and inject it into the controller. This can be done
6061
by implementing the :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolverInterface`.
6162
This interface specifies that you have to implement two methods::
6263

@@ -66,32 +67,32 @@ This interface specifies that you have to implement two methods::
6667
public function resolve(Request $request, ArgumentMetadata $argument);
6768
}
6869

69-
* The ``supports()`` method is used to check whether the resolver supports the given argument. It will
70-
only continue if it returns ``true``.
71-
72-
* The ``resolve()`` method will be used to resolve the actual value just acknowledged by
73-
``supports()``. Once a value is resolved you can ``yield`` the value to the ``ArgumentResolver``.
70+
``supports()``
71+
This method is used to check whether the value resolver supports the
72+
given argument. ``resolve()`` will only be executed when this returns ``true``.
73+
``resolve()``
74+
This method will resolve the actual value for the argument. Once the value
75+
is resolved, you should `yield`_ the value to the ``ArgumentResolver``.
7476

75-
* The ``Request`` object is the current ``Request`` which would also be injected into your
76-
action in the forementioned functionality.
77-
78-
* The :class:``Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata`` represents
79-
information retrieved from the method signature for the current argument it's trying to resolve.
77+
Both methods get the ``Request`` object, which is the current request, and an
78+
:class:`Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata`.
79+
This object contains all informations retrieved from the method signature for the
80+
current argument.
8081

8182
.. note::
8283

8384
The ``ArgumentMetadata`` is a simple data container created by the
84-
:class:``Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadataFactory``. This
85+
:class:`Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadataFactory`. This
8586
factory will work on every supported PHP version but might give different results. E.g. the
8687
``isVariadic()`` will never return true on PHP 5.5 and only on PHP 7.0 and higher it will give
8788
you basic types when calling ``getType()``.
8889

89-
Now that you know what to do, you can implement this interface. In order to get the current ``User``,
90-
you will have to get it from the ``TokenInterface`` which is in the ``TokenStorageInterface``::
90+
Now that you know what to do, you can implement this interface. To get the current ``User``, you need
91+
the current security token. This token can be retrieved from the token storage.::
9192

9293
namespace AppBundle\ArgumentValueResolver;
9394

94-
use AppBundle\User;
95+
use AppBundle\Entity\User;
9596
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
9697
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
9798

@@ -106,7 +107,12 @@ you will have to get it from the ``TokenInterface`` which is in the ``TokenStora
106107

107108
public function supports(Request $request, ArgumentMetadata $argument)
108109
{
109-
return ($token = $this->tokenStorage->getToken()) && $token->getUser() instanceof User;
110+
if (User::class !== $argument->getType()) {
111+
return false;
112+
}
113+
114+
$token = $this->tokenStorage->getToken()
115+
return $token->getUser() instanceof User;
110116
}
111117

112118
public function resolve(Request $request, ArgumentMetadata $argument)
@@ -115,7 +121,7 @@ you will have to get it from the ``TokenInterface`` which is in the ``TokenStora
115121
}
116122
}
117123

118-
This was pretty simple, now all you have to do is add the configuration for the service container. This
124+
That's it! Now all you have to do is add the configuration for the service container. This
119125
can be done by tagging the service with ``kernel.argument_resolver`` and adding a priority.
120126

121127
.. note::
@@ -143,12 +149,19 @@ can be done by tagging the service with ``kernel.argument_resolver`` and adding
143149
.. code-block:: xml
144150
145151
<!-- app/config/services.xml -->
146-
<services>
147-
<service id="app.value_resolver.user" class="AppBundle\ArgumentValueResolver\UserValueResolver">
148-
<argument type="service" id="security.token_storage">
149-
<tag name="kernel.argument_resolver" priority="50" />
150-
</service>
151-
</services>
152+
<?xml version="1.0" encoding="UTF-8" ?>
153+
<container xmlns="http://symfony.com/schema/dic/services"
154+
xmlns:xsi="'http://www.w3.org/2001/XMLSchema-Instance"
155+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
156+
157+
<services>
158+
<service id="app.value_resolver.user" class="AppBundle\ArgumentValueResolver\UserValueResolver">
159+
<argument type="service" id="security.token_storage">
160+
<tag name="kernel.argument_resolver" priority="50" />
161+
</service>
162+
</services>
163+
164+
</container>
152165
153166
.. code-block:: php
154167
@@ -161,3 +174,5 @@ can be done by tagging the service with ``kernel.argument_resolver`` and adding
161174
);
162175
$definition->addTag('kernel.argument_resolver', array('priority' => 50));
163176
$container->setDefinition('app.value_resolver.user', $definition);
177+
178+
.. _`yield`: http://php.net/manual/en/language.generators.syntax.php

0 commit comments

Comments
 (0)