Skip to content

Commit 3ebefaa

Browse files
author
Anthony MARTIN
committed
[DependencyInjection] Doc for Allow to choose an index for service locator collection
1 parent 8bce8a2 commit 3ebefaa

File tree

1 file changed

+212
-0
lines changed

1 file changed

+212
-0
lines changed

service_container/service_subscribers_locators.rst

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,218 @@ 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+
.. code-block:: php
450+
451+
// src/Handler/HandlerCollection.php
452+
namespace App\Handler;
453+
454+
use Symfony\Component\DependencyInjection\ServiceLocator;
455+
456+
class HandlerCollection
457+
{
458+
public function __construct(ServiceLocator $serviceLocator)
459+
{
460+
$handler_two = $serviceLocator->get('handler_two'):
461+
}
462+
}
463+
464+
465+
.. tip::
466+
467+
You can omit the ``index_attribute_name`` attribute, by implementing a static
468+
method ``getDefaultIndexAttributeName`` to the handler.
469+
470+
Based on the previous example ``App\Handler\One`` should look like this:
471+
472+
.. code-block:: php
473+
474+
// src/Handler/One.php
475+
namespace App\Handler;
476+
477+
class One
478+
{
479+
public static function getDefaultIndexName(): string
480+
{
481+
return 'handler_one';
482+
}
483+
}
484+
485+
And the configuration:
486+
487+
.. configuration-block::
488+
489+
.. code-block:: yaml
490+
491+
# config/services.yaml
492+
services:
493+
App\Handler\One:
494+
tags:
495+
- { name: 'app.handler', priority: 20 }
496+
497+
# ...
498+
499+
.. code-block:: xml
500+
501+
<!-- config/services.xml -->
502+
<?xml version="1.0" encoding="UTF-8" ?>
503+
<container xmlns="http://symfony.com/schema/dic/services"
504+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
505+
xsi:schemaLocation="http://symfony.com/schema/dic/services
506+
http://symfony.com/schema/dic/services/services-1.0.xsd">
507+
508+
<services>
509+
<service id="App\Handler\One">
510+
<tag name="app.handler" priority="20" />
511+
</service>
512+
513+
<!-- ... -->
514+
</services>
515+
</container>
516+
517+
.. code-block:: php
518+
519+
// config/services.php
520+
$container->register(App\Handler\One::class)
521+
->addTag('app.handler', ['priority' => 20]);
522+
523+
// ...
524+
525+
You also can define the name of the static method to implement on each service
526+
with the ``default_index_method`` attribute on the argument.
527+
528+
Based on the previous example ``App\Handler\One`` should look like :
529+
530+
.. code-block:: php
531+
532+
// src/Handler/One.php
533+
namespace App\Handler;
534+
535+
class One
536+
{
537+
public static function someFunctionName(): string
538+
{
539+
return 'handler_one';
540+
}
541+
}
542+
543+
And the configuration:
544+
545+
.. configuration-block::
546+
547+
.. code-block:: yaml
548+
549+
# config/services.yaml
550+
services:
551+
# ...
552+
553+
App\HandlerCollection:
554+
# inject all services tagged with app.handler as first argument
555+
arguments: [!tagged_locator { tag: 'app.handler', index_by: 'key', default_index_method: 'someFunctionName' }]
556+
557+
.. code-block:: xml
558+
559+
<!-- config/services.xml -->
560+
<?xml version="1.0" encoding="UTF-8" ?>
561+
<container xmlns="http://symfony.com/schema/dic/services"
562+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
563+
xsi:schemaLocation="http://symfony.com/schema/dic/services
564+
http://symfony.com/schema/dic/services/services-1.0.xsd">
565+
566+
<services>
567+
568+
<!-- ... --!>
569+
570+
<service id="App\HandlerCollection">
571+
<!-- inject all services tagged with app.handler as first argument -->
572+
<argument type="tagged_locator" tag="app.handler" index-by="key" default-index-method="someFunctionName" />
573+
</service>
574+
</services>
575+
</container>
576+
577+
.. code-block:: php
578+
579+
// config/services.php
580+
// ...
581+
582+
$container->register(App\HandlerCollection::class)
583+
// inject all services tagged with app.handler as first argument
584+
->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('app.handler', 'key', 'someFunctionName')));
585+
See also :doc:`tagged services </service_container/tags>`
586+
375587
Service Subscriber Trait
376588
------------------------
377589

0 commit comments

Comments
 (0)