@@ -30,24 +30,22 @@ to handle their respective command when it is asked for::
30
30
class CommandBus
31
31
{
32
32
/**
33
- * @var CommandHandler[]
33
+ * @param CommandHandler[] $handlerMap
34
34
*/
35
- private $handlerMap;
36
-
37
- public function __construct(array $handlerMap)
38
- {
39
- $this->handlerMap = $handlerMap;
35
+ public function __construct(
36
+ private array $handlerMap,
37
+ ) {
40
38
}
41
39
42
40
public function handle(Command $command)
43
41
{
44
42
$commandClass = get_class($command);
45
43
46
- if (!isset($ this->handlerMap[$commandClass]) ) {
44
+ if (!$handler = $ this->handlerMap[$commandClass] ?? null ) {
47
45
return;
48
46
}
49
47
50
- return $this->handlerMap[$commandClass] ->handle($command);
48
+ return $handler ->handle($command);
51
49
}
52
50
}
53
51
@@ -72,8 +70,7 @@ Defining a Service Subscriber
72
70
73
71
First, turn ``CommandBus `` into an implementation of :class: `Symfony\\ Contracts\\ Service\\ ServiceSubscriberInterface `.
74
72
Use its ``getSubscribedServices() `` method to include as many services as needed
75
- in the service subscriber and change the type hint of the container to
76
- a PSR-11 ``ContainerInterface ``::
73
+ in the service subscriber::
77
74
78
75
// src/CommandBus.php
79
76
namespace App;
@@ -85,11 +82,9 @@ a PSR-11 ``ContainerInterface``::
85
82
86
83
class CommandBus implements ServiceSubscriberInterface
87
84
{
88
- private $locator;
89
-
90
- public function __construct(ContainerInterface $locator)
91
- {
92
- $this->locator = $locator;
85
+ public function __construct(
86
+ private ContainerInterface $locator,
87
+ ) {
93
88
}
94
89
95
90
public static function getSubscribedServices(): array
@@ -119,8 +114,12 @@ a PSR-11 ``ContainerInterface``::
119
114
can also manually add the ``container.service_subscriber `` tag.
120
115
121
116
The injected service is an instance of :class: `Symfony\\ Component\\ DependencyInjection\\ ServiceLocator `
122
- which implements the PSR-11 ``ContainerInterface ``, but it is also a callable::
117
+ which implements both the PSR-11 ``ContainerInterface `` and :class: `Symfony\\ Contracts\\ Service\\ ServiceProviderInterface `.
118
+ It is also a callable and a countable::
123
119
120
+ // ...
121
+ $numberOfHandlers = count($this->locator);
122
+ $nameOfHandlers = array_keys($this->locator->getProvidedServices());
124
123
// ...
125
124
$handler = ($this->locator)($commandClass);
126
125
@@ -312,15 +311,16 @@ argument of type ``service_locator``.
312
311
Consider the following ``CommandBus `` class where you want to inject
313
312
some services into it via a service locator::
314
313
315
- // src/HandlerCollection .php
314
+ // src/CommandBus .php
316
315
namespace App;
317
316
318
- use Symfony\Component\DependencyInjection\ServiceLocator ;
317
+ use Psr\Container\ContainerInterface ;
319
318
320
319
class CommandBus
321
320
{
322
- public function __construct(ServiceLocator $locator)
323
- {
321
+ public function __construct(
322
+ private ContainerInterface $locator,
323
+ ) {
324
324
}
325
325
}
326
326
@@ -334,14 +334,15 @@ or directly via PHP attributes:
334
334
// src/CommandBus.php
335
335
namespace App;
336
336
337
+ use Psr\Container\ContainerInterface;
337
338
use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
338
- use Symfony\Component\DependencyInjection\ServiceLocator;
339
339
340
340
class CommandBus
341
341
{
342
342
public function __construct(
343
343
// creates a service locator with all the services tagged with 'app.handler'
344
- #[TaggedLocator('app.handler')] ServiceLocator $locator
344
+ #[TaggedLocator('app.handler')]
345
+ private ContainerInterface $locator,
345
346
) {
346
347
}
347
348
}
@@ -571,14 +572,14 @@ of the ``key`` tag attribute (as defined in the ``index_by`` locator option):
571
572
// src/CommandBus.php
572
573
namespace App;
573
574
575
+ use Psr\Container\ContainerInterface;
574
576
use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
575
- use Symfony\Component\DependencyInjection\ServiceLocator;
576
577
577
578
class CommandBus
578
579
{
579
580
public function __construct(
580
581
#[TaggedLocator('app.handler', indexAttribute: 'key')]
581
- ServiceLocator $locator
582
+ private ContainerInterface $locator,
582
583
) {
583
584
}
584
585
}
@@ -652,13 +653,13 @@ Inside this locator you can retrieve services by index using the value of the
652
653
// src/Handler/HandlerCollection.php
653
654
namespace App\Handler;
654
655
655
- use Symfony\Component\DependencyInjection\ServiceLocator ;
656
+ use Psr\Container\ContainerInterface ;
656
657
657
658
class HandlerCollection
658
659
{
659
- public function __construct(ServiceLocator $locator)
660
+ public function getHandlerTwo(ContainerInterface $locator)
660
661
{
661
- $handlerTwo = $locator->get('handler_two');
662
+ return $locator->get('handler_two');
662
663
}
663
664
664
665
// ...
@@ -691,14 +692,14 @@ attribute to the locator service defining the name of this custom method:
691
692
// src/CommandBus.php
692
693
namespace App;
693
694
695
+ use Psr\Container\ContainerInterface;
694
696
use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
695
- use Symfony\Component\DependencyInjection\ServiceLocator;
696
697
697
698
class CommandBus
698
699
{
699
700
public function __construct(
700
701
#[TaggedLocator('app.handler', 'key', defaultIndexMethod: 'myOwnMethodName')]
701
- ServiceLocator $locator
702
+ private ContainerInterface $locator,
702
703
) {
703
704
}
704
705
}
@@ -758,7 +759,7 @@ The :class:`Symfony\\Contracts\\Service\\ServiceSubscriberTrait` provides an
758
759
implementation for :class: `Symfony\\ Contracts\\ Service\\ ServiceSubscriberInterface `
759
760
that looks through all methods in your class that are marked with the
760
761
:class: `Symfony\\ Contracts\\ Service\\ Attribute\\ SubscribedService ` attribute. It
761
- provides a `` ServiceLocator `` for the services of each method's return type.
762
+ describes the services needed by the class based on each method's return type.
762
763
The service id is ``__METHOD__ ``. This allows you to add dependencies to your
763
764
services based on type-hinted helper methods::
764
765
@@ -916,34 +917,25 @@ Here's an example::
916
917
Testing a Service Subscriber
917
918
----------------------------
918
919
919
- To unit test a service subscriber, you can create a fake `` ServiceLocator `` ::
920
+ To unit test a service subscriber, you can create a fake container ::
920
921
921
- use Symfony\Component\DependencyInjection\ServiceLocator;
922
+ use Symfony\Contracts\Service\ServiceLocatorTrait;
923
+ use Symfony\Contracts\Service\ServiceProviderInterface;
922
924
923
- $container = new class() extends ServiceLocator {
924
- private $services = [];
925
+ // Create the fake services
926
+ $foo = new stdClass();
927
+ $bar = new stdClass();
928
+ $bar->foo = $foo;
925
929
926
- public function __construct()
927
- {
928
- parent::__construct([
929
- 'foo' => function () {
930
- return $this->services['foo'] = $this->services['foo'] ?? new stdClass();
931
- },
932
- 'bar' => function () {
933
- return $this->services['bar'] = $this->services['bar'] ?? $this->createBar();
934
- },
935
- ]);
936
- }
937
-
938
- private function createBar()
939
- {
940
- $bar = new stdClass();
941
- $bar->foo = $this->get('foo');
942
-
943
- return $bar;
944
- }
930
+ // Create the fake container
931
+ $container = new class([
932
+ 'foo' => fn () => $foo,
933
+ 'bar' => fn () => $bar,
934
+ ]) implements ServiceProviderInterface {
935
+ use ServiceLocatorTrait;
945
936
};
946
937
938
+ // Create the service subscriber
947
939
$serviceSubscriber = new MyService($container);
948
940
// ...
949
941
0 commit comments