Skip to content

Commit dce0204

Browse files
committed
Merge branch '4.3' into 4.4
* 4.3: [DependencyInjection] Doc for Allow to choose an index for service locator collection
2 parents 423f694 + bdf0855 commit dce0204

File tree

1 file changed

+146
-1
lines changed

1 file changed

+146
-1
lines changed

service_container/service_subscribers_locators.rst

Lines changed: 146 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,150 @@ will share identical locators amongst all the services referencing them::
392392
$myService->addArgument(ServiceLocatorTagPass::register($container, $locateableServices));
393393
}
394394

395-
.. _`Command pattern`: https://en.wikipedia.org/wiki/Command_pattern
395+
Indexing the Collection of Services
396+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
397+
398+
Services passed to the service locator can define their own index using an
399+
arbitrary attribute whose name is defined as ``index_by`` in the service locator.
400+
401+
In the following example, the ``App\Handler\HandlerCollection`` locator receives
402+
all services tagged with ``app.handler`` and they are indexed using the value
403+
of the ``key`` tag attribute (as defined in the ``index_by`` locator option):
404+
405+
.. configuration-block::
406+
407+
.. code-block:: yaml
408+
409+
# config/services.yaml
410+
services:
411+
App\Handler\One:
412+
tags:
413+
- { name: 'app.handler', key: 'handler_one' }
414+
415+
App\Handler\Two:
416+
tags:
417+
- { name: 'app.handler', key: 'handler_two' }
418+
419+
App\HandlerCollection:
420+
# inject all services tagged with app.handler as first argument
421+
arguments: [!tagged_locator { tag: 'app.handler', index_by: 'key' }]
422+
423+
.. code-block:: xml
424+
425+
<!-- config/services.xml -->
426+
<?xml version="1.0" encoding="UTF-8" ?>
427+
<container xmlns="http://symfony.com/schema/dic/services"
428+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
429+
xsi:schemaLocation="http://symfony.com/schema/dic/services
430+
http://symfony.com/schema/dic/services/services-1.0.xsd">
431+
432+
<services>
433+
<service id="App\Handler\One">
434+
<tag name="app.handler" key="handler_one" />
435+
</service>
436+
437+
<service id="App\Handler\Two">
438+
<tag name="app.handler" key="handler_two" />
439+
</service>
440+
441+
<service id="App\HandlerCollection">
442+
<!-- inject all services tagged with app.handler as first argument -->
443+
<argument type="tagged_locator" tag="app.handler" index-by="key" />
444+
</service>
445+
</services>
446+
</container>
447+
448+
.. code-block:: php
449+
450+
// config/services.php
451+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
452+
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
453+
454+
$container->register(App\Handler\One::class)
455+
->addTag('app.handler', ['key' => 'handler_one']);
456+
457+
$container->register(App\Handler\Two::class)
458+
->addTag('app.handler', ['key' => 'handler_two']);
459+
460+
$container->register(App\Handler\HandlerCollection::class)
461+
// inject all services tagged with app.handler as first argument
462+
->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('app.handler', 'key')));
463+
464+
Inside this locator you can retrieve services by index using the value of the
465+
``key`` attribute. For example, to get the ``App\Handler\Two`` service::
466+
467+
// src/Handler/HandlerCollection.php
468+
namespace App\Handler;
469+
470+
use Symfony\Component\DependencyInjection\ServiceLocator;
471+
472+
class HandlerCollection
473+
{
474+
public function __construct(ServiceLocator $locator)
475+
{
476+
$handlerTwo = $locator->get('handler_two'):
477+
}
478+
479+
// ...
480+
}
481+
482+
Instead of defining the index in the service definition, you can return its
483+
value in a method called ``getDefaultIndexName()`` inside the class associated
484+
to the service::
485+
486+
// src/Handler/One.php
487+
namespace App\Handler;
488+
489+
class One
490+
{
491+
public static function getDefaultIndexName(): string
492+
{
493+
return 'handler_one';
494+
}
495+
496+
// ...
497+
}
498+
499+
If you prefer to use another method name, add a ``default_index_method``
500+
attribute to the locator service defining the name of this custom method:
501+
502+
.. configuration-block::
503+
504+
.. code-block:: yaml
505+
506+
# config/services.yaml
507+
services:
508+
# ...
509+
510+
App\HandlerCollection:
511+
arguments: [!tagged_locator { tag: 'app.handler', default_index_method: 'myOwnMethodName' }]
512+
513+
.. code-block:: xml
514+
515+
<!-- config/services.xml -->
516+
<?xml version="1.0" encoding="UTF-8" ?>
517+
<container xmlns="http://symfony.com/schema/dic/services"
518+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
519+
xsi:schemaLocation="http://symfony.com/schema/dic/services
520+
http://symfony.com/schema/dic/services/services-1.0.xsd">
521+
522+
<services>
523+
524+
<!-- ... -->
525+
526+
<service id="App\HandlerCollection">
527+
<argument type="tagged_locator" tag="app.handler" default-index-method="myOwnMethodName" />
528+
</service>
529+
</services>
530+
</container>
531+
532+
.. code-block:: php
533+
534+
// config/services.php
535+
// ...
536+
537+
$container->register(App\HandlerCollection::class)
538+
->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('app.handler', null, 'myOwnMethodName')));
396539
397540
Service Subscriber Trait
398541
------------------------
@@ -484,3 +627,5 @@ and compose your services with them::
484627
When creating these helper traits, the service id cannot be ``__METHOD__``
485628
as this will include the trait name, not the class name. Instead, use
486629
``__CLASS__.'::'.__FUNCTION__`` as the service id.
630+
631+
.. _`Command pattern`: https://en.wikipedia.org/wiki/Command_pattern

0 commit comments

Comments
 (0)