@@ -372,6 +372,209 @@ 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+ // src/Handler/HandlerCollection.php
450+ namespace App\Handler;
451+
452+ use Symfony\Component\DependencyInjection\ServiceLocator;
453+
454+ class HandlerCollection
455+ {
456+ public function __construct(ServiceLocator $locator)
457+ {
458+ $handlerTwo = $locator->get('handler_two'):
459+ }
460+ }
461+ .. tip ::
462+
463+ You can omit the ``index_attribute_name `` attribute, by implementing a static
464+ method ``getDefaultIndexAttributeName `` to the handler.
465+
466+ Based on the previous example ``App\Handler\One `` should look like this::
467+
468+ // src/Handler/One.php
469+ namespace App\Handler;
470+
471+ class One
472+ {
473+ public static function getDefaultIndexName(): string
474+ {
475+ return 'handler_one';
476+ }
477+ }
478+ And the configuration:
479+
480+ .. configuration-block ::
481+
482+ .. code-block :: yaml
483+
484+ # config/services.yaml
485+ services :
486+ App\Handler\One :
487+ tags :
488+ - { name: 'app.handler', priority: 20 }
489+
490+ # ...
491+
492+ .. code-block :: xml
493+
494+ <!-- config/services.xml -->
495+ <?xml version =" 1.0" encoding =" UTF-8" ?>
496+ <container xmlns =" http://symfony.com/schema/dic/services"
497+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
498+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
499+ http://symfony.com/schema/dic/services/services-1.0.xsd" >
500+
501+ <services >
502+ <service id =" App\Handler\One" >
503+ <tag name =" app.handler" priority =" 20" />
504+ </service >
505+
506+ <!-- ... -->
507+ </services >
508+ </container >
509+
510+ .. code-block :: php
511+
512+ // config/services.php
513+ $container->register(App\Handler\One::class)
514+ ->addTag('app.handler', ['priority' => 20]);
515+
516+ // ...
517+
518+ You also can define the name of the static method to implement on each service
519+ with the ``default_index_method `` attribute on the argument.
520+
521+ Based on the previous example ``App\Handler\One `` should look like::
522+
523+ // src/Handler/One.php
524+ namespace App\Handler;
525+
526+ class One
527+ {
528+ public static function someFunctionName(): string
529+ {
530+ return 'handler_one';
531+ }
532+ }
533+ And the configuration:
534+
535+ .. configuration-block ::
536+
537+ .. code-block :: yaml
538+
539+ # config/services.yaml
540+ services :
541+ # ...
542+
543+ App\HandlerCollection :
544+ # inject all services tagged with app.handler as first argument
545+ arguments : [!tagged_locator { tag: 'app.handler', index_by: 'key', default_index_method: 'someFunctionName' }]
546+
547+ .. code-block :: xml
548+
549+ <!-- config/services.xml -->
550+ <?xml version =" 1.0" encoding =" UTF-8" ?>
551+ <container xmlns =" http://symfony.com/schema/dic/services"
552+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
553+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
554+ http://symfony.com/schema/dic/services/services-1.0.xsd" >
555+
556+ <services >
557+
558+ <!-- ... --!>
559+
560+ <service id="App\HandlerCollection">
561+ <!-- inject all services tagged with app.handler as first argument -->
562+ <argument type =" tagged_locator" tag =" app.handler" index-by =" key" default-index-method =" someFunctionName" />
563+ </service >
564+ </services >
565+ </container >
566+
567+ .. code-block :: php
568+
569+ // config/services.php
570+ // ...
571+
572+ $container->register(App\HandlerCollection::class)
573+ // inject all services tagged with app.handler as first argument
574+ ->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('app.handler', 'key', 'someFunctionName')));
575+
576+ See also :doc: `tagged services </service_container/tags >`
577+
375578Service Subscriber Trait
376579------------------------
377580
0 commit comments