@@ -372,6 +372,212 @@ will share identical locators amongst all the services referencing them::
372
372
373
373
.. _`Command pattern` : https://en.wikipedia.org/wiki/Command_pattern
374
374
375
+ Tagged Services Locator Collection with Index
376
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
377
+
378
+ If you want to retrieve a specific service within the injected service collector
379
+ you can use the ``index_by `` and ``default_index_method `` options of the argument
380
+ in combination with ``!tagged_locator `` to define an index.
381
+
382
+ In the following example, all services tagged with ``app.handler `` are passed as
383
+ first constructor argument to ``App\Handler\HandlerCollection ``,
384
+ but we can now access a specific injected service:
385
+
386
+ .. configuration-block ::
387
+
388
+ .. code-block :: yaml
389
+
390
+ # config/services.yaml
391
+ services :
392
+ App\Handler\One :
393
+ tags :
394
+ - { name: 'app.handler', key: 'handler_one' }
395
+
396
+ App\Handler\Two :
397
+ tags :
398
+ - { name: 'app.handler', key: 'handler_two' }
399
+
400
+ App\HandlerCollection :
401
+ # inject all services tagged with app.handler as first argument
402
+ arguments : [!tagged_locator { tag: 'app.handler', index_by: 'key' }]
403
+
404
+ .. code-block :: xml
405
+
406
+ <!-- config/services.xml -->
407
+ <?xml version =" 1.0" encoding =" UTF-8" ?>
408
+ <container xmlns =" http://symfony.com/schema/dic/services"
409
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
410
+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
411
+ http://symfony.com/schema/dic/services/services-1.0.xsd" >
412
+
413
+ <services >
414
+ <service id =" App\Handler\One" >
415
+ <tag name =" app.handler" key =" handler_one" />
416
+ </service >
417
+
418
+ <service id =" App\Handler\Two" >
419
+ <tag name =" app.handler" key =" handler_two" />
420
+ </service >
421
+
422
+ <service id =" App\HandlerCollection" >
423
+ <!-- inject all services tagged with app.handler as first argument -->
424
+ <argument type =" tagged_locator" tag =" app.handler" index-by =" key" />
425
+ </service >
426
+ </services >
427
+ </container >
428
+
429
+ .. code-block :: php
430
+
431
+ // config/services.php
432
+ use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
433
+ use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
434
+
435
+ $container->register(App\Handler\One::class)
436
+ ->addTag('app.handler', ['key' => 'handler_one']);
437
+
438
+ $container->register(App\Handler\Two::class)
439
+ ->addTag('app.handler', ['key' => 'handler_two']);
440
+
441
+ $container->register(App\Handler\HandlerCollection::class)
442
+ // inject all services tagged with app.handler as first argument
443
+ ->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('app.handler', 'key')));
444
+
445
+ After compilation the ``HandlerCollection `` to retrieve a specific service by it's ``key `` attribute
446
+ from the service locator injected, we just have to do ``$serviceLocator->get('handler_two'); `` to
447
+ retrieve the ``handler_two `` handler::
448
+
449
+ // src/Handler/HandlerCollection.php
450
+ namespace App\Handler;
451
+
452
+ use Symfony\Component\DependencyInjection\ServiceLocator;
453
+
454
+ class HandlerCollection
455
+ {
456
+ public function __construct(ServiceLocator $locator)
457
+ {
458
+ $handlerTwo = $locator->get('handler_two'):
459
+ }
460
+ }
461
+
462
+ .. tip ::
463
+
464
+ You can omit the ``index_attribute_name `` attribute, by implementing a static
465
+ method ``getDefaultIndexAttributeName `` to the handler.
466
+
467
+ Based on the previous example ``App\Handler\One `` should look like this::
468
+
469
+ // src/Handler/One.php
470
+ namespace App\Handler;
471
+
472
+ class One
473
+ {
474
+ public static function getDefaultIndexName(): string
475
+ {
476
+ return 'handler_one';
477
+ }
478
+ }
479
+
480
+ And the configuration:
481
+
482
+ .. configuration-block ::
483
+
484
+ .. code-block :: yaml
485
+
486
+ # config/services.yaml
487
+ services :
488
+ App\Handler\One :
489
+ tags :
490
+ - { name: 'app.handler', priority: 20 }
491
+
492
+ # ...
493
+
494
+ .. code-block :: xml
495
+
496
+ <!-- config/services.xml -->
497
+ <?xml version =" 1.0" encoding =" UTF-8" ?>
498
+ <container xmlns =" http://symfony.com/schema/dic/services"
499
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
500
+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
501
+ http://symfony.com/schema/dic/services/services-1.0.xsd" >
502
+
503
+ <services >
504
+ <service id =" App\Handler\One" >
505
+ <tag name =" app.handler" priority =" 20" />
506
+ </service >
507
+
508
+ <!-- ... -->
509
+ </services >
510
+ </container >
511
+
512
+ .. code-block :: php
513
+
514
+ // config/services.php
515
+ $container->register(App\Handler\One::class)
516
+ ->addTag('app.handler', ['priority' => 20]);
517
+
518
+ // ...
519
+
520
+ You also can define the name of the static method to implement on each service
521
+ with the ``default_index_method `` attribute on the argument.
522
+
523
+ Based on the previous example ``App\Handler\One `` should look like::
524
+
525
+ // src/Handler/One.php
526
+ namespace App\Handler;
527
+
528
+ class One
529
+ {
530
+ public static function someFunctionName(): string
531
+ {
532
+ return 'handler_one';
533
+ }
534
+ }
535
+
536
+ And the configuration:
537
+
538
+ .. configuration-block ::
539
+
540
+ .. code-block :: yaml
541
+
542
+ # config/services.yaml
543
+ services :
544
+ # ...
545
+
546
+ App\HandlerCollection :
547
+ # inject all services tagged with app.handler as first argument
548
+ arguments : [!tagged_locator { tag: 'app.handler', index_by: 'key', default_index_method: 'someFunctionName' }]
549
+
550
+ .. code-block :: xml
551
+
552
+ <!-- config/services.xml -->
553
+ <?xml version =" 1.0" encoding =" UTF-8" ?>
554
+ <container xmlns =" http://symfony.com/schema/dic/services"
555
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
556
+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
<
F42D
tr class="diff-line-row">
557
+ http://symfony.com/schema/dic/services/services-1.0.xsd" >
558
+
559
+ <services >
560
+
561
+ <!-- ... --!>
562
+
563
+ <service id="App\HandlerCollection">
564
+ <!-- inject all services tagged with app.handler as first argument -->
565
+ <argument type =" tagged_locator" tag =" app.handler" index-by =" key" default-index-method =" someFunctionName" />
566
+ </service >
567
+ </services >
568
+ </container >
569
+
570
+ .. code-block :: php
571
+
572
+ // config/services.php
573
+ // ...
574
+
575
+ $container->register(App\HandlerCollection::class)
576
+ // inject all services tagged with app.handler as first argument
577
+ ->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('app.handler', 'key', 'someFunctionName')));
578
+
579
+ See also :doc: `tagged services </service_container/tags >`
580
+
375
581
Service Subscriber Trait
376
582
------------------------
377
583