Skip to content

Commit b504690

Browse files
author
Anthony MARTIN
committed
[DependencyInjection] Doc for #30257 Allow to choose an index for tagged collection
1 parent 8bce8a2 commit b504690

File tree

1 file changed

+213
-0
lines changed

1 file changed

+213
-0
lines changed

service_container/tags.rst

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)