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