@@ -372,6 +372,218 @@ will share identical locators amongst all the services referencing them::
372372
373373.. _`Command pattern` : https://en.wikipedia.org/wiki/Command_pattern
374374
375+ Tagged Services Locator Collection with Index
376+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
377+
378+ If you want to retrieve a specific service within the injected service collector
379+ you can use the ``index_by `` and ``default_index_method `` options of the argument
380+ in combination with ``!tagged_locator `` to define an index.
381+
382+ In the following example, all services tagged with ``app.handler `` are passed as
383+ first constructor argument to ``App\Handler\HandlerCollection`,
384+ but we can now access a specific injected service:
385+
386+ .. configuration-block::
387+
388+ .. code-block:: yaml
389+
390+ # config/services.yaml
391+ services:
392+ App\Handler\One:
393+ tags:
394+ - { name: 'app.handler', key: 'handler_one' }
395+
396+ App\Handler\Two:
397+ tags:
398+ - { name: 'app.handler', key: 'handler_two' }
399+
400+ App\HandlerCollection:
401+ # inject all services tagged with app.handler as first argument
402+ arguments: [!tagged_locator { tag: 'app.handler', index_by: 'key' }]
403+
404+ .. code-block:: xml
405+
406+ <!-- config/services.xml -->
407+ <?xml version="1.0" encoding="UTF-8" ?>
408+ <container xmlns="http://symfony.com/schema/dic/services"
409+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
410+ xsi:schemaLocation="http://symfony.com/schema/dic/services
411+ http://symfony.com/schema/dic/services/services-1.0.xsd">
412+
413+ <services>
414+ <service id="App\Handler\One">
415+ <tag name="app.handler" key="handler_one" />
416+ </service>
417+
418+ <service id="App\Handler\Two">
419+ <tag name="app.handler" key="handler_two" />
420+ </service>
421+
422+ <service id="App\HandlerCollection">
423+ <!-- inject all services tagged with app.handler as first argument -->
424+ <argument type="tagged_locator" tag="app.handler" index-by="key" />
425+ </service>
426+ </services>
427+ </container>
428+
429+ .. code-block:: php
430+
431+ // config/services.php
432+ use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
433+ use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
434+
435+ $container->register(App\Handler\One::class)
436+ ->addTag('app.handler', ['key' => 'handler_one']);
437+
438+ $container->register(App\Handler\Two::class)
439+ ->addTag('app.handler', ['key' => 'handler_two']);
440+
441+ $container->register(App\Handler\HandlerCollection::class)
442+ // inject all services tagged with app.handler as first argument
443+ ->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('app.handler', 'key')));
444+
445+ After compilation the ``HandlerCollection `` to retrieve a specific service by it's ``key `` attribute
446+ from the service locator injected, we just have to do ``$serviceLocator->get('handler_two'); `` to
447+ retrieve the ``handler_two `` handler :
448+
449+ .. code-block :: php
450+
451+ // src/Handler/HandlerCollection.php
452+ namespace App\Handler;
453+
454+ use Symfony\Component\DependencyInjection\ServiceLocator;
455+
456+ class HandlerCollection
457+ {
458+ public function __construct(ServiceLocator $serviceLocator)
459+ {
460+ $handler_two = $serviceLocator->get('handler_two'):
461+ }
462+ }
463+
464+
465+ .. tip ::
466+
467+ You can omit the ``index_attribute_name `` attribute, by implementing a static
468+ method ``getDefaultIndexAttributeName `` to the handler.
469+
470+ Based on the previous example ``App\Handler\One `` should look like this:
471+
472+ .. code-block :: php
473+
474+ // src/Handler/One.php
475+ namespace App\Handler;
476+
477+ class One
478+ {
479+ public static function getDefaultIndexName(): string
480+ {
481+ return 'handler_one';
482+ }
483+ }
484+
485+ And the configuration:
486+
487+ .. configuration-block ::
488+
489+ .. code-block :: yaml
490+
491+ # config/services.yaml
492+ services :
493+ App\Handler\One :
494+ tags :
495+ - { name: 'app.handler', priority: 20 }
496+
497+ # ...
498+
499+ .. code-block :: xml
500+
501+ <!-- config/services.xml -->
502+ <?xml version =" 1.0" encoding =" UTF-8" ?>
503+ <container xmlns =" http://symfony.com/schema/dic/services"
504+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
505+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
506+ http://symfony.com/schema/dic/services/services-1.0.xsd" >
507+
508+ <services >
509+ <service id =" App\Handler\One" >
510+ <tag name =" app.handler" priority =" 20" />
511+ </service >
512+
513+ <!-- ... -->
514+ </services >
515+ </container >
516+
517+ .. code-block :: php
518+
519+ // config/services.php
520+ $container->register(App\Handler\One::class)
521+ ->addTag('app.handler', ['priority' => 20]);
522+
523+ // ...
524+
525+ You also can define the name of the static method to implement on each service
526+ with the ``default_index_method `` attribute on the argument.
527+
528+ Based on the previous example ``App\Handler\One `` should look like :
529+
530+ .. code-block :: php
531+
532+ // src/Handler/One.php
533+ namespace App\Handler;
534+
535+ class One
536+ {
537+ public static function someFunctionName(): string
538+ {
539+ return 'handler_one';
540+ }
541+ }
542+
543+ And the configuration:
544+
545+ .. configuration-block ::
546+
547+ .. code-block :: yaml
548+
549+ # config/services.yaml
550+ services :
551+ # ...
552+
553+ App\HandlerCollection :
554+ # inject all services tagged with app.handler as first argument
555+ arguments : [!tagged_locator { tag: 'app.handler', index_by: 'key', default_index_method: 'someFunctionName' }]
556+
557+ .. code-block :: xml
558+
559+ <!-- config/services.xml -->
560+ <?xml version =" 1.0" encoding =" UTF-8" ?>
561+ <container xmlns =" http://symfony.com/schema/dic/services"
562+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
563+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
564+ http://symfony.com/schema/dic/services/services-1.0.xsd" >
565+
566+ <services >
567+
568+ <!-- ... --!>
569+
570+ <service id="App\HandlerCollection">
571+ <!-- inject all services tagged with app.handler as first argument -->
572+ <argument type =" tagged_locator" tag =" app.handler" index-by =" key" default-index-method =" someFunctionName" />
573+ </service >
574+ </services >
575+ </container >
576+
577+ .. code-block :: php
578+
579+ // config/services.php
580+ // ...
581+
582+ $container->register(App\HandlerCollection::class)
583+ // inject all services tagged with app.handler as first argument
584+ ->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('app.handler', 'key', 'someFunctionName')));
585+ See also :doc: `tagged services </service_container/tags >`
586+
375587Service Subscriber Trait
376588------------------------
377589
0 commit comments