@@ -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+ If you want to retrieve a specific service within the injected collection
573+ you can 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 ``App\Handler\HandlerCollection`,
578+ but we can now access 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 `` is able to iterate over your
639+ application handlers. To retrieve a specific service by it's ``key `` attribute
640+ from the iterator, we can use ``iterator_to_array `` and retrieve the ``handler_two ``:
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+ }
656+ }
657+
658+
659+ .. tip ::
660+
661+ You can omit the ``index_attribute_name `` attribute, by implementing a static
662+ method ``getDefaultIndexAttributeName `` to the handler.
663+
664+ Based on the previous example ``App\Handler\One `` should look like this:
665+
666+ .. code-block :: php
667+
668+ // src/Handler/One.php
669+ namespace App\Handler;
670+
671+ class One
672+ {
673+ public static function getDefaultIndexName(): string
674+ {
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(): string
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+
0 commit comments