@@ -562,3 +562,210 @@ 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+
672+ And the configuration:
673+
674+ .. configuration-block ::
675+
676+ .. code-block :: yaml
677+
678+ # config/services.yaml
679+ services :
680+ App\Handler\One :
681+ tags :
682+ - { name: 'app.handler', priority: 20 }
683+
684+ # ...
685+
686+ .. code-block :: xml
687+
688+ <!-- config/services.xml -->
689+ <?xml version =" 1.0" encoding =" UTF-8" ?>
690+ <container xmlns =" http://symfony.com/schema/dic/services"
691+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
692+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
693+ http://symfony.com/schema/dic/services/services-1.0.xsd" >
694+
695+ <services >
696+ <service id =" App\Handler\One" >
697+ <tag name =" app.handler" priority =" 20" />
698+ </service >
699+
700+ <!-- ... -->
701+ </services >
702+ </container >
703+
704+ .. code-block :: php
705+
706+ // config/services.php
707+ $container->register(App\Handler\One::class)
708+ ->addTag('app.handler', ['priority' => 20]);
709+
710+ // ...
711+
712+ You also can define the name of the static method to implement on each service
713+ with the ``default_index_method `` attribute on the argument.
714+
715+ Based on the previous example ``App\Handler\One `` should look like::
716+
717+ // src/Handler/One.php
718+ namespace App\Handler;
719+
720+ class One
721+ {
722+ public static function someFunctionName(): string
723+ {
724+ return 'handler_one';
725+ }
726+ }
727+
728+ And the configuration:
729+
730+ .. configuration-block ::
731+
732+ .. code-block :: yaml
733+
734+ # config/services.yaml
735+ services :
736+ # ...
737+
738+ App\HandlerCollection :
739+ # inject all services tagged with app.handler as first argument
740+ arguments : [!tagged { tag: 'app.handler', index_by: 'key', default_index_method: 'someFunctionName' }]
741+
742+ .. code-block :: xml
743+
744+ <!-- config/services.xml -->
745+ <?xml version =" 1.0" encoding =" UTF-8" ?>
746+ <container xmlns =" http://symfony.com/schema/dic/services"
747+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
748+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
749+ http://symfony.com/schema/dic/services/services-1.0.xsd" >
750+
751+ <services >
752+
753+ <!-- ... --!>
754+
755+ <service id="App\HandlerCollection">
756+ <!-- inject all services tagged with app.handler as first argument -->
757+ <argument type =" tagged" tag =" app.handler" index-by =" key" default-index-method =" someFunctionName" />
758+ </service >
759+ </services >
760+ </container >
761+
762+ .. code-block :: php
763+
764+ // config/services.php
765+ // ...
766+
767+ $container->register(App\HandlerCollection::class)
768+ // inject all services tagged with app.handler as first argument
769+ ->addArgument(new TaggedIteratorArgument('app.handler', 'key', 'someFunctionName'));
770+
771+ See also :doc: `tagged locator services </service_container/service_subscribers_locators >`
0 commit comments