@@ -394,6 +394,212 @@ will share identical locators amongst all the services referencing them::
394
394
395
395
.. _`Command pattern` : https://en.wikipedia.org/wiki/Command_pattern
396
396
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
+
397
603
Service Subscriber Trait
398
604
------------------------
399
605
0 commit comments