@@ -213,6 +213,61 @@ PSR-7 Objects Resolver:
213
213
:class: `Psr\\ Http\\ Message\\ RequestInterface ` or :class: `Psr\\ Http\\ Message\\ MessageInterface `.
214
214
It requires installing :doc: `the PSR-7 Bridge </components/psr7 >` component.
215
215
216
+ Managing Value Resolvers
217
+ ------------------------
218
+
219
+ For each argument, every resolver tagged with ``controller.argument_value_resolver ``
220
+ will be called until one provides a value. The order in which they are called depends
221
+ on their priority. For example, the ``SessionValueResolver `` will be called before the
222
+ ``DefaultValueResolver `` because its priority is higher. This allows to write e.g.
223
+ ``SessionInterface $session = null `` to get the session if there is one, or ``null ``
224
+ if there is none.
225
+
226
+ In that specific case, you don't need any resolver running before
227
+ ``SessionValueResolver ``, so skipping them would not only improve performance,
228
+ but also prevent one of them providing a value before ``SessionValueResolver ``
229
+ has a chance to.
230
+
231
+ The :class: `Symfony\\ Component\\ HttpKernel\\ Attribute\\ ValueResolver ` attribute
232
+ lets you do this by "targeting" the resolver you want::
233
+
234
+ // src/Controller/SessionController.php
235
+ namespace App\Controller;
236
+
237
+ use Symfony\Component\HttpFoundation\Response;
238
+ use Symfony\Component\HttpFoundation\Session\SessionInterface;
239
+ use Symfony\Component\HttpKernel\Attribute\ValueResolver;
240
+ use Symfony\Component\HttpKernel\Controller\ArgumentResolver\SessionValueResolver;
241
+ use Symfony\Component\Routing\Annotation\Route;
242
+
243
+ class SessionController
244
+ {
245
+ #[Route('/')]
246
+ public function __invoke(
247
+ #[ValueResolver(SessionValueResolver::class)]
248
+ SessionInterface $session = null
249
+ ): Response
250
+ {
251
+ // ...
252
+ }
253
+ }
254
+
255
+ .. versionadded :: 6.3
256
+
257
+ The ``ValueResolver `` attribute was introduced in Symfony 6.3.
258
+
259
+ In the example above, the ``SessionValueResolver `` will be called first because
260
+ it is targeted. The ``DefaultValueResolver `` will be called next if no value has
261
+ been provided; that's why you can assign ``null `` as ``$session ``'s default value.
262
+
263
+ You can target a resolver by passing its name as ``ValueResolver ``'s first argument.
264
+ For convenience, built-in resolvers' name are their FQCN.
265
+
266
+ A targeted resolver can also be disabled by passing ``ValueResolver ``'s ``$disabled ``
267
+ argument to ``true ``; this is how :ref: `MapEntity allows to disable the
268
+ EntityValueResolver for a specific controller <doctrine-entity-value-resolver>`.
269
+ Yes, ``MapEntity `` extends ``ValueResolver ``!
270
+
216
271
Adding a Custom Value Resolver
217
272
------------------------------
218
273
@@ -297,8 +352,13 @@ When those requirements are met, the method creates a new instance of the
297
352
custom value object and returns it as the value for this argument.
298
353
299
354
That's it! Now all you have to do is add the configuration for the service
300
- container. This can be done by tagging the service with ``controller.argument_value_resolver ``
301
- and adding a priority:
355
+ container. This can be done by adding one of the following tags to your value resolver.
356
+
357
+ ``controller.argument_value_resolver ``
358
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
359
+
360
+ This tag is automatically added to every service implementing ``ValueResolverInterface ``,
361
+ but you can set it yourself to change its ``priority `` or ``name `` attributes.
302
362
303
363
.. configuration-block ::
304
364
@@ -313,7 +373,9 @@ and adding a priority:
313
373
314
374
App\ValueResolver\BookingIdValueResolver :
315
375
tags :
316
- - { name: controller.argument_value_resolver, priority: 150 }
376
+ - controller.argument_value_resolver :
377
+ name : booking_id
378
+ priority : 150
317
379
318
380
.. code-block :: xml
319
381
@@ -330,7 +392,7 @@ and adding a priority:
330
392
<!-- ... -->
331
393
332
394
<service id =" App\ValueResolver\BookingIdValueResolver" >
333
- <tag name =" controller.argument_value_resolver " priority =" 150" / >
395
+ <tag name =" booking_id " priority =" 150" >controller.argument_value_resolver</ tag >
334
396
</service >
335
397
</services >
336
398
@@ -347,7 +409,7 @@ and adding a priority:
347
409
$services = $containerConfigurator->services();
348
410
349
411
$services->set(BookingIdValueResolver::class)
350
- ->tag('controller.argument_value_resolver', ['priority' => 150])
412
+ ->tag('controller.argument_value_resolver', ['name' => 'booking_id', ' priority' => 150])
351
413
;
352
414
};
353
415
@@ -364,3 +426,51 @@ command to see which argument resolvers are present and in which order they run:
364
426
.. code-block :: terminal
365
427
366
428
$ php bin/console debug:container debug.argument_resolver.inner --show-arguments
429
+
430
+ You can also configure the name passed to the ``ValueResolver `` attribute to target
431
+ your resolver. Otherwise it will default to the service's id.
432
+
433
+ ``controller.targeted_value_resolver ``
434
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
435
+
436
+ Set this tag if you want your resolver to be called only if it is targeted by a
437
+ ``ValueResolver `` attribute. Like ``controller.argument_value_resolver ``, you
438
+ can customize the name by which your resolver can be targeted.
439
+
440
+ As an alternative, you can add the
441
+ :class: `Symfony\\ Component\\ HttpKernel\\ Attribute\\ AsTargetedValueResolver ` attribute
442
+ to your resolver and pass your custom name as its first argument::
443
+
444
+ // src/ValueResolver/IdentifierValueResolver.php
445
+ namespace App\ValueResolver;
446
+
447
+ use Symfony\Component\HttpKernel\Attribute\AsTargetedValueResolver;
448
+ use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
449
+
450
+ #[AsTargetedValueResolver('booking_id')]
451
+ class BookingIdValueResolver implements ValueResolverInterface
452
+ {
453
+ // ...
454
+ }
455
+
456
+ You can then pass this name as ``ValueResolver ``'s first argument to target your resolver::
457
+
458
+ // src/Controller/BookingController.php
459
+ namespace App\Controller;
460
+
461
+ use App\Reservation\BookingId;
462
+ use Symfony\Component\HttpFoundation\Response;
463
+ use Symfony\Component\HttpKernel\Attribute\ValueResolver;
464
+
465
+ class BookingController
466
+ {
467
+ public function index(#[ValueResolver('booking_id')] BookingId $id): Response
468
+ {
469
+ // ... do something with $id
470
+ }
471
+ }
472
+
473
+ .. versionadded :: 6.3
474
+
475
+ The ``controller.targeted_value_resolver `` tag and ``AsTargetedValueResolver ``
476
+ attribute were introduced in Symfony 6.3.
0 commit comments