From 980b3d365d9576ee14815b338c58ca4b0944ec4b Mon Sep 17 00:00:00 2001 From: Anthony MARTIN Date: Mon, 18 Feb 2019 11:09:29 +0100 Subject: [PATCH] [DependencyInjection] Doc for #30257 Allow to choose an index for tagged collection --- service_container/tags.rst | 206 +++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) diff --git a/service_container/tags.rst b/service_container/tags.rst index 8793048211b..601e8f6d136 100644 --- a/service_container/tags.rst +++ b/service_container/tags.rst @@ -699,3 +699,209 @@ in the configuration of the collecting service: ) ; }; + +Tagged Services Collection with Index +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you want to retrieve a specific service within the injected collection +you can use the ``index_by`` and ``default_index_method`` options of the argument +in combination with ``!tagged``. + +In the following example, all services tagged with ``app.handler`` are passed as +first constructor argument to ``App\Handler\HandlerCollection``, +but we can now access a specific injected service: + +.. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + services: + App\Handler\One: + tags: + - { name: 'app.handler', key: 'handler_one' } + + App\Handler\Two: + tags: + - { name: 'app.handler', key: 'handler_two' } + + App\HandlerCollection: + # inject all services tagged with app.handler as first argument + arguments: [!tagged { tag: 'app.handler', index_by: 'key' }] + + .. code-block:: xml + + + + + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/services.php + use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; + + $container->register(App\Handler\One::class) + ->addTag('app.handler', ['key' => 'handler_one']); + + $container->register(App\Handler\Two::class) + ->addTag('app.handler', ['key' => 'handler_two']); + + $container->register(App\Handler\HandlerCollection::class) + // inject all services tagged with app.handler as first argument + ->addArgument(new TaggedIteratorArgument('app.handler', 'key')); + +After compilation the ``HandlerCollection`` is able to iterate over your +application handlers. To retrieve a specific service by it's ``key`` attribute +from the iterator, we can use ``iterator_to_array`` and retrieve the ``handler_two``: +to get an array and then retrieve the ``handler_two`` handler:: + + // src/Handler/HandlerCollection.php + namespace App\Handler; + + class HandlerCollection + { + public function __construct(iterable $handlers) + { + $handlers = iterator_to_array($handlers); + + $handlerTwo = $handlers['handler_two']: + } + } + +.. tip:: + + You can omit the ``index_attribute_name`` attribute, by implementing a static + method ``getDefaultIndexAttributeName`` to the handler. + + Based on the previous example ``App\Handler\One`` should look like this:: + + // src/Handler/One.php + namespace App\Handler; + + class One + { + public static function getDefaultIndexName(): string + { + return 'handler_one'; + } + } + + And the configuration: + + .. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + services: + App\Handler\One: + tags: + - { name: 'app.handler', priority: 20 } + + # ... + + .. code-block:: xml + + + + + + + + + + + + + + + .. code-block:: php + + // config/services.php + $container->register(App\Handler\One::class) + ->addTag('app.handler', ['priority' => 20]); + + // ... + + You also can define the name of the static method to implement on each service + with the ``default_index_method`` attribute on the argument. + + Based on the previous example ``App\Handler\One`` should look like:: + + // src/Handler/One.php + namespace App\Handler; + + class One + { + public static function someFunctionName(): string + { + return 'handler_one'; + } + } + + And the configuration: + + .. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + services: + # ... + + App\HandlerCollection: + # inject all services tagged with app.handler as first argument + arguments: [!tagged { tag: 'app.handler', index_by: 'key', default_index_method: 'someFunctionName' }] + + .. code-block:: xml + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/services.php + // ... + + $container->register(App\HandlerCollection::class) + // inject all services tagged with app.handler as first argument + ->addArgument(new TaggedIteratorArgument('app.handler', 'key', 'someFunctionName')); + +See also :doc:`tagged locator services `