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