Skip to content

Commit 338058f

Browse files
author
Anthony MARTIN
committed
[DependencyInjection] Doc for #30257 Allow to choose an index for tagged collection
1 parent f034d99 commit 338058f

File tree

1 file changed

+207
-0
lines changed

1 file changed

+207
-0
lines changed

service_container/tags.rst

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

0 commit comments

Comments
 (0)