@@ -202,6 +202,83 @@ PSR-7 Objects Resolver:
202
202
:class: `Psr\\ Http\\ Message\\ RequestInterface ` or :class: `Psr\\ Http\\ Message\\ MessageInterface `.
203
203
It requires installing :doc: `the PSR-7 Bridge </components/psr7 >` component.
204
204
205
+ Managing Value Resolvers
206
+ ------------------------
207
+
208
+ For each argument, every resolver tagged with ``controller.argument_value_resolver ``
209
+ will be called until one provides a value. The order in which they are called depends
210
+ on their priority. For example, the ``SessionValueResolver `` (priority 50) will be
211
+ called before the ``DefaultValueResolver `` (priority -100) which allows to write e.g.
212
+ ``SessionInterface $session = null `` to get the session if there is one, or ``null ``
213
+ if there is none.
214
+
215
+ But what if you *know * there will be a session? In that case every resolver running
216
+ before ``SessionValueResolver `` is useless. Worse, some of these could actually
217
+ provide a value before ``SessionValueResolver `` has a chance to (don't worry though,
218
+ this won't happen with built-in resolvers). Since Symfony 6.3, this kind of issue
219
+ can be resolved by leveraging the
220
+ :class: `Symfony\\ Component\\ HttpKernel\\ Attribute\\ ValueResolver ` attribute::
221
+
222
+ // src/Controller/SessionController.php
223
+ namespace App\Controller;
224
+
225
+ use Symfony\Component\HttpFoundation\Response;
226
+ use Symfony\Component\HttpKernel\Attribute\ValueResolver;
227
+ use Symfony\Component\HttpKernel\Controller\ArgumentResolver\SessionValueResolver;
228
+ use Symfony\Component\Routing\Annotation\Route;
229
+ use Symfony\Component\HttpFoundation\Session\SessionInterface;
230
+
231
+ class SessionController
232
+ {
233
+ #[Route('/')]
234
+ public function __invoke(
235
+ #[ValueResolver(SessionValueResolver::class)]
236
+ SessionInterface $session
237
+ ): Response
238
+ {
239
+ // ...
240
+ }
241
+ }
242
+
243
+ .. versionadded :: 6.3
244
+
245
+ The ``ValueResolver `` attribute was introduced in Symfony 6.3.
246
+
247
+ You can target a resolver by passing its name (more on that later) as ``ValueResolver ``'s
248
+ first argument. For convenience, built-in resolvers' name are their FQCN.
249
+
250
+ By default, a targeted resolver is "pinned" to the argument holding the
251
+ ``ValueResolver `` attribute, meaning that only it will be called to provide a value,
252
+ and that it will have to.
253
+
254
+ In the above example the ``DefaultValueResolver `` would never be called, so adding a
255
+ default value to ``$session `` would be useless. If we need one, then it is fine not
256
+ to use ``ValueResolver ``.
257
+ But then, what if we want to prevent an hypothetic ``EagerValueResolver `` to provide a
258
+ value before ``SessionValueResolver ``? Time to use ``ValueResolver ``'s second argument!
259
+ By passing it to ``true ``, you can disable the targeted resolver::
260
+
261
+ // src/Controller/SessionController.php
262
+ namespace App\Controller;
263
+
264
+ use App\ArgumentResolver\EagerValueResolver;
265
+ use Symfony\Component\HttpFoundation\Response;
266
+ use Symfony\Component\HttpKernel\Attribute\ValueResolver;
267
+ use Symfony\Component\Routing\Annotation\Route;
268
+ use Symfony\Component\HttpFoundation\Session\SessionInterface;
269
+
270
+ class SessionController
271
+ {
272
+ #[Route('/')]
273
+ public function __invoke(
274
+ #[ValueResolver(EagerValueResolver::class, disabled: true)]
275
+ SessionInterface $session = null
276
+ ): Response
277
+ {
278
+ // ...
279
+ }
280
+ }
281
+
205
282
Adding a Custom Value Resolver
206
283
------------------------------
207
284
@@ -286,8 +363,13 @@ When those requirements are met, the method creates a new instance of the
286
363
custom value object and returns it as the value for this argument.
287
364
288
365
That's it! Now all you have to do is add the configuration for the service
289
- container. This can be done by tagging the service with ``controller.argument_value_resolver ``
290
- and adding a priority:
366
+ container. This can be done by adding one of the following tags to your value resolver.
367
+
368
+ ``controller.argument_value_resolver ``
369
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
370
+
371
+ This tag is automatically added to every service implementing ``ValueResolverInterface ``,
372
+ but you can set it yourself to change its ``priority `` or ``name `` attributes.
291
373
292
374
.. configuration-block ::
293
375
@@ -302,7 +384,9 @@ and adding a priority:
302
384
303
385
App\ValueResolver\BookingIdValueResolver :
304
386
tags :
305
- - { name: controller.argument_value_resolver, priority: 150 }
387
+ - controller.argument_value_resolver :
388
+ name : booking_id
389
+ priority : 150
306
390
307
391
.. code-block :: xml
308
392
@@ -319,7 +403,7 @@ and adding a priority:
319
403
<!-- ... -->
320
404
321
405
<service id =" App\ValueResolver\BookingIdValueResolver" >
322
- <tag name =" controller.argument_value_resolver " priority =" 150" />
406
+ <tag name =" booking_id " priority =" 150" />controller.argument_value_resolver</ tag >
323
407
</service >
324
408
</services >
325
409
@@ -336,7 +420,7 @@ and adding a priority:
336
420
$services = $containerConfigurator->services();
337
421
338
422
$services->set(BookingIdValueResolver::class)
339
- ->tag('controller.argument_value_resolver', ['priority' => 150])
423
+ ->tag('controller.argument_value_resolver', ['name' => 'booking_id', ' priority' => 150])
340
424
;
341
425
};
342
426
@@ -353,3 +437,34 @@ command to see which argument resolvers are present and in which order they run:
353
437
.. code-block :: terminal
354
438
355
439
$ php bin/console debug:container debug.argument_resolver.inner --show-arguments
440
+
441
+ You can also configure the name passed to the ``ValueResolver `` attribute to target
442
+ your resolver. Otherwise it will default to the service's id.
443
+
444
+ ``controller.targeted_value_resolver ``
445
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
446
+
447
+ Set this tag if you want your resolver to be called only if it is pinned by a
448
+ ``ValueResolver `` attribute. Like ``controller.argument_value_resolver ``, you
449
+ can customize the name by which your resolver can be targeted.
450
+
451
+ As an alternative, you can add the
452
+ :class: `Symfony\\ Component\\ HttpKernel\\ Attribute\\ AsTargetedValueResolver ` attribute
453
+ to your resolver and pass your custom name as its first argument::
454
+
455
+ // src/ValueResolver/IdentifierValueResolver.php
456
+ namespace App\ValueResolver;
457
+
458
+ use Symfony\Component\HttpKernel\Attribute\AsTargetedValueResolver;
459
+ use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
460
+
461
+ #[AsTargetedValueResolver('booking_id')]
462
+ class BookingIdValueResolver implements ValueResolverInterface
463
+ {
464
+ // ...
465
+ }
466
+
467
+ .. versionadded :: 6.3
468
+
469
+ The ``controller.targeted_value_resolver `` tag and ``AsTargetedValueResolver ``
470
+ attribute were introduced in Symfony 6.3.
0 commit comments