@@ -392,7 +392,150 @@ will share identical locators amongst all the services referencing them::
392
392
$myService->addArgument(ServiceLocatorTagPass::register($container, $locateableServices));
393
393
}
394
394
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')));
396
539
397
540
Service Subscriber Trait
398
541
------------------------
@@ -484,3 +627,5 @@ and compose your services with them::
484
627
When creating these helper traits, the service id cannot be ``__METHOD__ ``
485
628
as this will include the trait name, not the class name. Instead, use
486
629
``__CLASS__.'::'.__FUNCTION__ `` as the service id.
630
+
631
+ .. _`Command pattern` : https://en.wikipedia.org/wiki/Command_pattern
0 commit comments