@@ -7,33 +7,34 @@ Extending Action Argument Resolving
7
7
.. versionadded :: 3.1
8
8
The ``ArgumentResolver `` and value resolvers were introduced in Symfony 3.1.
9
9
10
- In the book, you've learned that you can get the :class: `Symfony\\ Component\\ HttpFoundation\\ Request `
11
- object via an argument in your controller. This argument has to be type-hinted
12
- by the ``Request `` class in order to be recognized. This is done via the
10
+ In the book, you've learned that you can get the
11
+ :class: `Symfony\\ Component\\ HttpFoundation\\ Request ` object via an argument in
12
+ your controller. This argument has to be type-hinted by the ``Request `` class
13
+ in order to be recognized. This is done via the
13
14
:class: `Symfony\\ Component\\ HttpKernel\\ Controller\\ ArgumentResolver `. By
14
- creating and registering custom argument value resolvers, you can extend
15
- this functionality.
15
+ creating and registering custom argument value resolvers, you can extend this
16
+ functionality.
16
17
17
18
Functionality Shipped with the HttpKernel
18
19
-----------------------------------------
19
20
20
21
Symfony ships with four value resolvers in the HttpKernel component:
21
22
22
- :class: `Symfony\\ Component\\ HttpKernel\\ Controller\\ ArgumentValueResolver \\ ArgumentFromAttributeResolver `
23
+ :class: `Symfony\\ Component\\ HttpKernel\\ Controller\\ ArgumentResolver \\ RequestAttributeValueResolver `
23
24
Attempts to find a request attribute that matches the name of the argument.
24
25
25
- :class: `Symfony\\ Component\\ HttpKernel\\ Controller\\ ArgumentValueResolver \\ RequestValueResolver `
26
- Injects the current ``Request `` if type-hinted with ``Request ``, or a
27
- sub-class thereof .
26
+ :class: `Symfony\\ Component\\ HttpKernel\\ Controller\\ ArgumentResolver \\ RequestValueResolver `
27
+ Injects the current ``Request `` if type-hinted with ``Request `` or a class
28
+ extending `` Request `` .
28
29
29
- :class: `Symfony\\ Component\\ HttpKernel\\ Controller\\ ArgumentValueResolver \\ DefaultValueResolver `
30
+ :class: `Symfony\\ Component\\ HttpKernel\\ Controller\\ ArgumentResolver \\ DefaultValueResolver `
30
31
Will set the default value of the argument if present and the argument
31
32
is optional.
32
33
33
- :class: `Symfony\\ Component\\ HttpKernel\\ Controller\\ ArgumentValueResolver \\ VariadicValueResolver `
34
- Verifies in the request if your data is an array and will add all of
35
- them to the argument list. When the action is called, the last (variadic)
36
- argument will contain all the values of this array.
34
+ :class: `Symfony\\ Component\\ HttpKernel\\ Controller\\ ArgumentResolver \\ VariadicValueResolver `
35
+ Verifies if the request data is an array and will add all of them to the
36
+ argument list. When the action is called, the last (variadic) argument will
37
+ contain all the values of this array.
37
38
38
39
.. note ::
39
40
@@ -43,9 +44,10 @@ Symfony ships with four value resolvers in the HttpKernel component:
43
44
Adding a Custom Value Resolver
44
45
------------------------------
45
46
46
- Adding a new value resolver requires one class and one service defintion.
47
- In the next example, you'll create a value resolver to inject the ``User ``
48
- object from the security system. Given you write the following action::
47
+ Adding a new value resolver requires creatign one class and one service
48
+ definition. In the next example, you'll create a value resolver to inject the
49
+ ``User `` object from the security system. Given you write the following
50
+ controller::
49
51
50
52
namespace AppBundle\Controller;
51
53
@@ -56,12 +58,13 @@ object from the security system. Given you write the following action::
56
58
{
57
59
public function indexAction(User $user)
58
60
{
59
- return new Response('<html><body> Hello '.$user->getUsername().'!</body></html> ');
61
+ return new Response('Hello '.$user->getUsername().'!');
60
62
}
61
63
}
62
64
63
65
Somehow you will have to get the ``User `` object and inject it into the controller.
64
- This can be done by implementing the :class: `Symfony\\ Component\\ HttpKernel\\ Controller\\ ArgumentValueResolverInterface `.
66
+ This can be done by implementing the
67
+ :class: `Symfony\\ Component\\ HttpKernel\\ Controller\\ ArgumentValueResolverInterface `.
65
68
This interface specifies that you have to implement two methods:
66
69
67
70
``supports() ``
@@ -80,7 +83,8 @@ Now that you know what to do, you can implement this interface. To get the
80
83
current ``User ``, you need the current security token. This token can be
81
84
retrieved from the token storage::
82
85
83
- namespace AppBundle\ArgumentValueResolver;
86
+ // src/AppBundle/ArgumentResolver/UserValueResolver.php
87
+ namespace AppBundle\ArgumentResolver;
84
88
85
89
use AppBundle\Entity\User;
86
90
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
@@ -123,31 +127,22 @@ must fulfill the following requirements:
123
127
* A security token must be present;
124
128
* The value must be an instance of the ``User ``.
125
129
126
- When all those requirements are met and true is returned, the ``ArgumentResolver ``
127
- calls ``resolve() `` with the same values as it called ``supports() ``.
130
+ When all those requirements are met and ``true `` is returned, the
131
+ ``ArgumentResolver `` calls ``resolve() `` with the same values as it called
132
+ ``supports() ``.
128
133
129
134
That's it! Now all you have to do is add the configuration for the service
130
135
container. This can be done by tagging the service with ``controller.argument_resolver ``
131
136
and adding a priority.
132
137
133
- .. note ::
134
-
135
- While adding a priority is optional, it's recommended to add one to
136
- make sure the expected value is injected. The ``ArgumentFromAttributeResolver ``
137
- has a priority of 100. As this one is responsible for fetching attributes
138
- from the ``Request ``, it's also recommended to trigger your custom value
139
- resolver with a lower priority. This makes sure the argument resolvers
140
- are not triggered in (e.g.) subrequests if you pass your user along:
141
- ``{{ render(controller('AppBundle:User:index', {'user', app.user})) }} ``.
142
-
143
138
.. configuration-block ::
144
139
145
140
.. code-block :: yaml
146
141
147
142
# app/config/services.yml
148
143
services :
149
144
app.value_resolver.user :
150
- class : AppBundle\ArgumentValueResolver \UserValueResolver
145
+ class : AppBundle\ArgumentResolver \UserValueResolver
151
146
arguments :
152
147
- ' @security.token_storage'
153
148
tags :
@@ -162,7 +157,9 @@ and adding a priority.
162
157
xsi : schemaLocation =" http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd" >
163
158
164
159
<services >
165
- <service id =" app.value_resolver.user" class =" AppBundle\ArgumentValueResolver\UserValueResolver" >
160
+ <service id =" app.value_resolver.user"
161
+ class =" AppBundle\ArgumentResolver\UserValueResolver"
162
+ >
166
163
<argument type =" service" id =" security.token_storage" >
167
164
<tag name =" controller.argument_value_resolver" priority =" 50" />
168
165
</service >
@@ -176,44 +173,29 @@ and adding a priority.
176
173
use Symfony\Component\DependencyInjection\Definition;
177
174
178
175
$defintion = new Definition(
179
- 'AppBundle\ArgumentValueResolver \UserValueResolver',
176
+ 'AppBundle\ArgumentResolver \UserValueResolver',
180
177
array(new Reference('security.token_storage'))
181
178
);
182
179
$definition->addTag('controller.argument_value_resolver', array('priority' => 50));
183
180
$container->setDefinition('app.value_resolver.user', $definition);
184
181
185
- Creating an Optional User Resolver
186
- ----------------------------------
187
-
188
- When you want your user to be optional, e.g. when your page is behind a
189
- firewall that also allows anonymous authentication, you might not always
190
- have a security user. To get this to work, you only have to change your
191
- method signature to ` UserInterface $user = null ` .
182
+ While adding a priority is optional, it's recommended to add one to make sure
183
+ the expected value is injected. The `` RequestAttributeValueResolver `` has a
184
+ priority of 100. As this one is responsible for fetching attributes from the
185
+ `` Request ``, it's recommended to trigger your custom value resolver with a
186
+ lower priority. This makes sure the argument resolvers are not triggered when
187
+ the attribute is present. For instance, when passing the user along a
188
+ subrequests .
192
189
193
- When you take the ``UserValueResolver `` from the previous example, you can
194
- see there is no logic in case of failure to comply to the requirements. Default
195
- values are defined in the signature and are available in the ``ArgumentMetadata ``.
196
- When a default value is available and there are no resolvers that support
197
- the given value, the ``DefaultValueResolver `` is triggered. This Resolver
198
- takes the default value of your argument and yields it to the argument list::
190
+ .. tip ::
199
191
200
- namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
192
+ As you see in the ``UserValueResolver::supports() `` method, the user may
193
+ not be available (e.g. when the controller is not behind a firewall). In
194
+ these cases, the resolver will not be executed. If no argument value is
195
+ resolved, an exception will be throwed.
201
196
202
- use Symfony\Component\HttpFoundation\Request;
203
- use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
204
- use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
205
-
206
- final class DefaultValueResolver implements ArgumentValueResolverInterface
207
- {
208
- public function supports(Request $request, ArgumentMetadata $argument)
209
- {
210
- return $argument->hasDefaultValue();
211
- }
212
-
213
- public function resolve(Request $request, ArgumentMetadata $argument)
214
- {
215
- yield $argument->getDefaultValue();
216
- }
217
- }
197
+ To prevent this, you can add a default value in the controller (e.g. ``User
198
+ $user = null ``). The ``DefaultValueResolver `` is executed as last resolver
199
+ and will use the default value if no value is resolved already.
218
200
219
201
.. _`yield` : http://php.net/manual/en/language.generators.syntax.php
0 commit comments