Skip to content

Commit e607796

Browse files
author
Anthony MARTIN
committed
[DependencyInjection] Doc for Allow to choose an index for service locator collection
1 parent 6db79cd commit e607796

File tree

1 file changed

+203
-0
lines changed

1 file changed

+203
-0
lines changed

service_container/service_subscribers_locators.rst

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
375578
Service Subscriber Trait
376579
------------------------
377580

0 commit comments

Comments
 (0)