@@ -562,3 +562,216 @@ 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+ -
10BC0
{ 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+ .. code-block :: php
642+
643+ // src/Handler/HandlerCollection.php
644+ namespace App\Handler;
645+
646+ class HandlerCollection
647+ {
648+ public function __construct(iterable $handlers)
649+ {
650+ $handlers = iterator_to_array($handlers);
651+
652+ $handlerTwo = $handlers['handler_two']:
653+ }
654+ }
655+
656+
657+ .. tip ::
658+
659+ You can omit the ``index_attribute_name `` attribute, by implementing a static
660+ method ``getDefaultIndexAttributeName `` to the handler.
661+
662+ Based on the previous example ``App\Handler\One `` should look like this:
663+
664+ .. code-block :: php
665+
666+ // src/Handler/One.php
667+ namespace App\Handler;
668+
669+ class One
670+ {
671+ public static function getDefaultIndexName(): string
672+ {
673+ return 'handler_one';
674+ }
675+ }
676+
677+ And the configuration:
678+
679+ .. configuration-block ::
680+
681+ .. code-block :: yaml
682+
683+ # config/services.yaml
684+ services :
685+ App\Handler\One :
686+ tags :
687+ - { name: 'app.handler', priority: 20 }
688+
689+ # ...
690+
691+ .. code-block :: xml
692+
693+ <!-- config/services.xml -->
694+ <?xml version =" 1.0" encoding =" UTF-8" ?>
695+ <container xmlns =" http://symfony.com/schema/dic/services"
696+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
697+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
698+ http://symfony.com/schema/dic/services/services-1.0.xsd" >
699+
700+ <services >
701+ <service id =" App\Handler\One" >
702+ <tag name =" app.handler" priority =" 20" />
703+ </service >
704+
705+ <!-- ... -->
706+ </services >
707+ </container >
708+
709+ .. code-block :: php
710+
711+ // config/services.php
712+ $container->register(App\Handler\One::class)
713+ ->addTag('app.handler', ['priority' => 20]);
714+
715+ // ...
716+
717+ You also can define the name of the static method to implement on each service
718+ with the ``default_index_method `` attribute on the argument.
719+
720+ Based on the previous example ``App\Handler\One `` should look like :
721+
722+ .. code-block :: php
723+
724+ // src/Handler/One.php
725+ namespace App\Handler;
726+
727+ class One
728+ {
729+ public static function someFunctionName(): string
730+ {
731+ return 'handler_one';
732+ }
733+ }
734+
735+ And the configuration:
736+
737+ .. configuration-block ::
738+
739+ .. code-block :: yaml
740+
741+ # config/services.yaml
742+ services :
743+ # ...
744+
745+ App\HandlerCollection :
746+ # inject all services tagged with app.handler as first argument
747+ arguments : [!tagged { tag: 'app.handler', index_by: 'key', default_index_method: 'someFunctionName' }]
748+
749+ .. code-block :: xml
750+
751+ <!-- config/services.xml -->
752+ <?xml version =" 1.0" encoding =" UTF-8" ?>
753+ <container xmlns =" http://symfony.com/schema/dic/services"
754+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
755+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
756+ http://symfony.com/schema/dic/services/services-1.0.xsd" >
757+
758+ <services >
759+
760+ <!-- ... --!>
761+
762+ <service id="App\HandlerCollection">
763+ <!-- inject all services tagged with app.handler as first argument -->
764+ <argument type =" tagged" tag =" app.handler" index-by =" key" default-index-method =" someFunctionName" />
765+ </service >
766+ </services >
767+ </container >
768+
769+ .. code-block :: php
770+
771+ // config/services.php
772+ // ...
773+
774+ $container->register(App\HandlerCollection::class)
775+ // inject all services tagged with app.handler as first argument
776+ ->addArgument(new TaggedIteratorArgument('app.handler', 'key', 'someFunctionName'));
777+
0 commit comments