@@ -562,3 +562,208 @@ application handlers::
562562 ->addTag('app.handler', ['priority' => 20]);
563563
564564 Note that any other custom attributes will be ignored by this feature.
565+
566+
567+ Tagged Services Collection with Index
568+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
569+
570+ If you want to retrieve a specific service within the injected collection
571+ you can use the ``index_by `` and ``default_index_method `` options of the argument
572+ in combination with ``!tagged ``.
573+
574+ In the following example, all services tagged with ``app.handler `` are passed as
575+ first constructor argument to ``App\Handler\HandlerCollection`,
576+ but we can now access a specific injected service:
577+
578+ .. configuration-block::
579+
580+ .. code-block:: yaml
581+
582+ # config/services.yaml
583+ services:
584+ App\Handler\One:
585+ tags:
586+ - { name: 'app.handler', key: 'handler_one' }
587+
588+ App\Handler\Two:
589+ tags:
590+ - { name: 'app.handler', key: 'handler_two' }
591+
592+ App\HandlerCollection:
593+ # inject all services tagged with app.handler as first argument
594+ arguments: [!tagged { tag: 'app.handler', index_by: 'key' }]
595+
596+ .. code-block:: xml
597+
598+ <!-- config/services.xml -->
599+ <?xml version="1.0" encoding="UTF-8" ?>
600+ <container xmlns="http://symfony.com/schema/dic/services"
601+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
602+ xsi:schemaLocation="http://symfony.com/schema/dic/services
603+ http://symfony.com/schema/dic/services/services-1.0.xsd">
604+
605+ <services>
606+ <service id="App\Handler\One">
607+ <tag name="app.handler" key="handler_one" />
608+ </service>
609+
610+ <service id="App\Handler\Two">
611+ <tag name="app.handler" key="handler_two" />
612+ </service>
613+
614+ <service id="App\HandlerCollection">
615+ <!-- inject all services tagged with app.handler as first argument -->
616+ <argument type="tagged" tag="app.handler" index-by="key" />
617+ </service>
618+ </services>
619+ </container>
620+
621+ .. code-block:: php
622+
623+ // config/services.php
624+ use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
625+
626+ $container->register(App\Handler\One::class)
627+ ->addTag('app.handler', ['key' => 'handler_one']);
628+
629+ $container->register(App\Handler\Two::class)
630+ ->addTag('app.handler', ['key' => 'handler_two']);
631+
632+ $container->register(App\Handler\HandlerCollection::class)
633+ // inject all services tagged with app.handler as first argument
634+ ->addArgument(new TaggedIteratorArgument('app.handler', 'key'));
635+
636+ After compilation the ``HandlerCollection `` is able to iterate over your
637+ application handlers. To retrieve a specific service by it's ``key `` attribute
638+ from the iterator, we can use ``iterator_to_array `` and retrieve the ``handler_two ``:
639+ to get an array and then retrieve the ``handler_two `` handler::
640+
641+ // src/Handler/HandlerCollection.php
642+ namespace App\Handler;
643+
644+ class HandlerCollection
645+ {
646+ public function __construct(iterable $handlers)
647+ {
648+ $handlers = iterator_to_array($handlers);
649+
650+ $handlerTwo = $handlers['handler_two']:
651+ }
652+ }
653+
654+ .. tip ::
655+
656+ You can omit the ``index_attribute_name `` attribute, by implementing a static
657+ method ``getDefaultIndexAttributeName `` to the handler.
658+
659+ Based on the previous example ``App\Handler\One `` should look like this::
660+
661+ // src/Handler/One.php
662+ namespace App\Handler;
663+
664+ class One
665+ {
666+ public static function getDefaultIndexName(): string
667+ {
668+ return 'handler_one';
669+ }
670+ }
671+ And the configuration:
672+
673+ .. configuration-block ::
674+
675+ .. code-block :: yaml
676+
677+ # config/services.yaml
678+ services :
679+ App\Handler\One :
680+ tags :
681+ - { name: 'app.handler', priority: 20 }
682+
683+ # ...
684+
685+ .. code-block :: xml
686+
687+ <!-- config/services.xml -->
688+ <?xml version =" 1.0" encoding =" UTF-8" ?>
689+ <container xmlns =" http://symfony.com/schema/dic/services"
690+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
691+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
692+ http://symfony.com/schema/dic/services/services-1.0.xsd" >
693+
694+ <services >
695+ <service id =" App\Handler\One" >
696+ <tag name =" app.handler" priority =" 20" />
697+ </service >
698+
699+ <!-- ... -->
700+ </services >
701+ </container >
702+
703+ .. code-block :: php
704+
705+ // config/services.php
706+ $container->register(App\Handler\One::class)
707+ ->addTag('app.handler', ['priority' => 20]);
708+
709+ // ...
710+
711+ You also can define the name of the static method to implement on each service
712+ with the ``default_index_method `` attribute on the argument.
713+
714+ Based on the previous example ``App\Handler\One `` should look like::
715+
716+ // src/Handler/One.php
717+ namespace App\Handler;
718+
719+ class One
720+ {
721+ public static function someFunctionName(): string
722+ {
723+ return 'handler_one';
724+ }
725+ }
726+ And the configuration:
727+
728+ .. configuration-block ::
729+
730+ .. code-block :: yaml
731+
732+ # config/services.yaml
733+ services :
734+ # ...
735+
736+ App\HandlerCollection :
737+ # inject all services tagged with app.handler as first argument
738+ arguments : [!tagged { tag: 'app.handler', index_by: 'key', default_index_method: 'someFunctionName' }]
739+
740+ .. code-block :: xml
741+
742+ <!-- config/services.xml -->
743+ <?xml version =" 1.0" encoding =" UTF-8" ?>
744+ <container xmlns =" http://symfony.com/schema/dic/services"
745+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
746+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
747+ http://symfony.com/schema/dic/services/services-1.0.xsd" >
748+
749+ <services >
750+
751+ <!-- ... --!>
752+
753+ <service id="App\HandlerCollection">
754+ <!-- inject all services tagged with app.handler as first argument -->
755+ <argument type =" tagged" tag =" app.handler" index-by =" key" default-index-method =" someFunctionName" />
756+ </service >
757+ </services >
758+ </container >
759+
760+ .. code-block :: php
761+
762+ // config/services.php
763+ // ...
764+
765+ $container->register(App\HandlerCollection::class)
766+ // inject all services tagged with app.handler as first argument
767+ ->addArgument(new TaggedIteratorArgument('app.handler', 'key', 'someFunctionName'));
768+
769+ See also :doc: `tagged locator services </service_container/service_subscribers_locators >`
0 commit comments