@@ -7,45 +7,46 @@ Extending Action Argument Resolving
7
7
.. versionadded :: 3.1
8
8
The ``ArgumentResolver `` and value resolvers are added in Symfony 3.1.
9
9
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.
14
14
15
15
16
16
Functionality Shipped With The HttpKernel
17
17
-----------------------------------------
18
18
19
19
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.
22
20
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 .
25
23
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 .
28
26
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.
31
32
When the action is called, the last (variadic) argument will contain all the values of this array.
32
33
33
34
.. note ::
34
35
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
37
38
used resolving logic.
38
39
39
- Adding a New Value Resolver
40
- ---------------------------
40
+ Adding a Custom Value Resolver
41
+ ------------------------------
41
42
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::
45
46
46
47
namespace AppBundle\Controller;
47
48
48
- use AppBundle\User;
49
+ use AppBundle\Entity\ User;
49
50
use Symfony\Component\HttpFoundation\Response;
50
51
51
52
class UserController
@@ -56,7 +57,7 @@ action::
56
57
}
57
58
}
58
59
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
60
61
by implementing the :class: `Symfony\\ Component\\ HttpKernel\\ Controller\\ ArgumentValueResolverInterface `.
61
62
This interface specifies that you have to implement two methods::
62
63
@@ -66,32 +67,32 @@ This interface specifies that you have to implement two methods::
66
67
public function resolve(Request $request, ArgumentMetadata $argument);
67
68
}
68
69
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 ``.
74
76
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.
80
81
81
82
.. note ::
82
83
83
84
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
85
86
factory will work on every supported PHP version but might give different results. E.g. the
86
87
``isVariadic() `` will never return true on PHP 5.5 and only on PHP 7.0 and higher it will give
87
88
you basic types when calling ``getType() ``.
88
89
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. ::
91
92
92
93
namespace AppBundle\ArgumentValueResolver;
93
94
94
- use AppBundle\User;
95
+ use AppBundle\Entity\ User;
95
96
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
96
97
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
97
98
@@ -106,7 +107,12 @@ you will have to get it from the ``TokenInterface`` which is in the ``TokenStora
106
107
107
108
public function supports(Request $request, ArgumentMetadata $argument)
108
109
{
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;
110
116
}
111
117
112
118
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
115
121
}
116
122
}
117
123
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
119
125
can be done by tagging the service with ``kernel.argument_resolver `` and adding a priority.
120
126
121
127
.. note ::
@@ -143,12 +149,19 @@ can be done by tagging the service with ``kernel.argument_resolver`` and adding
143
149
.. code-block :: xml
144
150
145
151
<!-- 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 >
152
165
153
166
.. code-block :: php
154
167
@@ -161,3 +174,5 @@ can be done by tagging the service with ``kernel.argument_resolver`` and adding
161
174
);
162
175
$definition->addTag('kernel.argument_resolver', array('priority' => 50));
163
176
$container->setDefinition('app.value_resolver.user', $definition);
177
+
178
+ .. _`yield` : http://php.net/manual/en/language.generators.syntax.php
0 commit comments