Skip to content

Commit 860cf3e

Browse files
committed
minor #11042 [DependencyInjection] Doc for Allow to choose an index for service locators (Anthony MARTIN)
This PR was submitted for the master branch but it was merged into the 4.3 branch instead (closes #11042). Discussion ---------- [DependencyInjection] Doc for Allow to choose an index for service locators Here is the doc for the new feature implemented in : [symfony/symfony#30348](symfony/symfony#30348) that follow the feature [symfony/symfony#30257](symfony/symfony#30257) Commits ------- d63c298 [DependencyInjection] Doc for Allow to choose an index for service locator collection
2 parents b64269e + d63c298 commit 860cf3e

File tree

1 file changed

+206
-0
lines changed

1 file changed

+206
-0
lines changed

service_container/service_subscribers_locators.rst

+206
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,212 @@ will share identical locators amongst all the services referencing them::
394394

395395
.. _`Command pattern`: https://en.wikipedia.org/wiki/Command_pattern
396396

397+
Tagged Services Locator Collection with Index
398+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
399+
400+
If you want to retrieve a specific service within the injected service collector
401+
you can use the ``index_by`` and ``default_index_method`` options of the argument
402+
in combination with ``!tagged_locator`` to define an index.
403+
404+
In the following example, all services tagged with ``app.handler`` are passed as
405+
first constructor argument to ``App\Handler\HandlerCollection``,
406+
but we can now access a specific injected service:
407+
408+
.. configuration-block::
409+
410+
.. code-block:: yaml
411+
412+
# config/services.yaml
413+
services:
414+
App\Handler\One:
415+
tags:
416+
- { name: 'app.handler', key: 'handler_one' }
417+
418+
App\Handler\Two:
419+
tags:
420+
- { name: 'app.handler', key: 'handler_two' }
421+
422+
App\HandlerCollection:
423+
# inject all services tagged with app.handler as first argument
424+
arguments: [!tagged_locator { tag: 'app.handler', index_by: 'key' }]
425+
426+
.. code-block:: xml
427+
428+
<!-- config/services.xml -->
429+
<?xml version="1.0" encoding="UTF-8" ?>
430+
<container xmlns="http://symfony.com/schema/dic/services"
431+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
432+
xsi:schemaLocation="http://symfony.com/schema/dic/services
433+
http://symfony.com/schema/dic/services/services-1.0.xsd">
434+
435+
<services>
436+
<service id="App\Handler\One">
437+
<tag name="app.handler" key="handler_one" />
438+
</service>
439+
440+
<service id="App\Handler\Two">
441+
<tag name="app.handler" key="handler_two" />
442+
</service>
443+
444+
<service id="App\HandlerCollection">
445+
<!-- inject all services tagged with app.handler as first argument -->
446+
<argument type="tagged_locator" tag="app.handler" index-by="key" />
447+
</service>
448+
</services>
449+
</container>
450+
451+
.. code-block:: php
452+
453+
// config/services.php
454+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
455+
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
456+
457+
$container->register(App\Handler\One::class)
458+
->addTag('app.handler', ['key' => 'handler_one']);
459+
460+
$container->register(App\Handler\Two::class)
461+
->addTag('app.handler', ['key' => 'handler_two']);
462+
463+
$container->register(App\Handler\HandlerCollection::class)
464+
// inject all services tagged with app.handler as first argument
465+
->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('app.handler', 'key')));
466+
467+
After compilation the ``HandlerCollection`` to retrieve a specific service by it's ``key`` attribute
468+
from the service locator injected, we just have to do ``$serviceLocator->get('handler_two');`` to
469+
retrieve the ``handler_two`` handler::
470+
471+
// src/Handler/HandlerCollection.php
472+
namespace App\Handler;
473+
474+
use Symfony\Component\DependencyInjection\ServiceLocator;
475+
476+
class HandlerCollection
477+
{
478+
public function __construct(ServiceLocator $locator)
479+
{
480+
$handlerTwo = $locator->get('handler_two'):
481+
}
482+
}
483+
484+
.. tip::
485+
486+
You can omit the ``index_attribute_name`` attribute, by implementing a static
487+
method ``getDefaultIndexAttributeName`` to the handler.
488+
489+
Based on the previous example ``App\Handler\One`` should look like this::
490+
491+
// src/Handler/One.php
492+
namespace App\Handler;
493+
494+
class One
495+
{
496+
public static function getDefaultIndexName(): string
497+
{
498+
return 'handler_one';
499+
}
500+
}
501+
502+
And the configuration:
503+
504+
.. configuration-block::
505+
506+
.. code-block:: yaml
507+
508+
# config/services.yaml
509+
services:
510+
App\Handler\One:
511+
tags:
512+
- { name: 'app.handler', priority: 20 }
513+
514+
# ...
515+
516+
.. code-block:: xml
517+
518+
<!-- config/services.xml -->
519+
<?xml version="1.0" encoding="UTF-8" ?>
520+
<container xmlns="http://symfony.com/schema/dic/services"
521+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
522+
xsi:schemaLocation="http://symfony.com/schema/dic/services
523+
http://symfony.com/schema/dic/services/services-1.0.xsd">
524+
525+
<services>
526+
<service id="App\Handler\One">
527+
<tag name="app.handler" priority="20" />
528+
</service>
529+
530+
<!-- ... -->
531+
</services>
532+
</container>
533+
534+
.. code-block:: php
535+
536+
// config/services.php
537+
$container->register(App\Handler\One::class)
538+
->addTag('app.handler', ['priority' => 20]);
539+
540+
// ...
541+
542+
You also can define the name of the static method to implement on each service
543+
with the ``default_index_method`` attribute on the argument.
544+
545+
Based on the previous example ``App\Handler\One`` should look like::
546+
547+
// src/Handler/One.php
548+
namespace App\Handler;
549+
550+
class One
551+
{
552+
public static function someFunctionName(): string
553+
{
554+
return 'handler_one';
555+
}
556+
}
557+
558+
And the configuration:
559+
560+
.. configuration-block::
561+
562+
.. code-block:: yaml
563+
564+
# config/services.yaml
565+
services:
566+
# ...
567+
568+
App\HandlerCollection:
569+
# inject all services tagged with app.handler as first argument
570+
arguments: [!tagged_locator { tag: 'app.handler', index_by: 'key', default_index_method: 'someFunctionName' }]
571+
572+
.. code-block:: xml
573+
574+
<!-- config/services.xml -->
575+
<?xml version="1.0" encoding="UTF-8" ?>
576+
<container xmlns="http://symfony.com/schema/dic/services"
577+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
578+
xsi:schemaLocation="http://symfony.com/schema/dic/services
579+
http://symfony.com/schema/dic/services/services-1.0.xsd">
580+
581+
<services>
582+
583+
<!-- ... --!>
584+
585+
<service id="App\HandlerCollection">
586+
<!-- inject all services tagged with app.handler as first argument -->
587+
<argument type="tagged_locator" tag="app.handler" index-by="key" default-index-method="someFunctionName" />
588+
</service>
589+
</services>
590+
</container>
591+
592+
.. code-block:: php
593+
594+
// config/services.php
595+
// ...
596+
597+
$container->register(App\HandlerCollection::class)
598+
// inject all services tagged with app.handler as first argument
599+
->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('app.handler', 'key', 'someFunctionName')));
600+
601+
See also :doc:`tagged services </service_container/tags>`
602+
397603
Service Subscriber Trait
398604
------------------------
399605

0 commit comments

Comments
 (0)