@@ -25,24 +25,22 @@ to handle their respective command when it is asked for::
25
25
class CommandBus
26
26
{
27
27
/**
28
- * @var CommandHandler[]
28
+ * @param CommandHandler[] $handlerMap
29
29
*/
30
- private $handlerMap;
31
-
32
- public function __construct(array $handlerMap)
33
- {
34
- $this->handlerMap = $handlerMap;
30
+ public function __construct(
31
+ private array $handlerMap,
32
+ ) {
35
33
}
36
34
37
35
public function handle(Command $command)
38
36
{
39
37
$commandClass = get_class($command);
40
38
41
- if (!isset($ this->handlerMap[$commandClass]) ) {
39
+ if (!$handler = $ this->handlerMap[$commandClass] ?? null ) {
42
40
return;
43
41
}
44
42
45
- return $this->handlerMap[$commandClass] ->handle($command);
43
+ return $handler ->handle($command);
46
44
}
47
45
}
48
46
@@ -67,8 +65,7 @@ Defining a Service Subscriber
67
65
68
66
First, turn ``CommandBus `` into an implementation of :class: `Symfony\\ Contracts\\ Service\\ ServiceSubscriberInterface `.
69
67
Use its ``getSubscribedServices() `` method to include as many services as needed
70
- in the service subscriber and change the type hint of the container to
71
- a PSR-11 ``ContainerInterface ``::
68
+ in the service subscriber::
72
69
73
70
// src/CommandBus.php
74
71
namespace App;
@@ -80,11 +77,9 @@ a PSR-11 ``ContainerInterface``::
80
77
81
78
class CommandBus implements ServiceSubscriberInterface
82
79
{
83
- private $locator;
84
-
85
- public function __construct(ContainerInterface $locator)
86
- {
87
- $this->locator = $locator;
80
+ public function __construct(
81
+ private ContainerInterface $locator,
82
+ ) {
88
83
}
89
84
90
85
public static function getSubscribedServices(): array
@@ -114,8 +109,12 @@ a PSR-11 ``ContainerInterface``::
114
109
can also manually add the ``container.service_subscriber `` tag.
115
110
116
111
The injected service is an instance of :class: `Symfony\\ Component\\ DependencyInjection\\ ServiceLocator `
117
- which implements the PSR-11 ``ContainerInterface ``, but it is also a callable::
112
+ which implements both the PSR-11 ``ContainerInterface `` and :class: `Symfony\\ Contracts\\ Service\\ ServiceProviderInterface `.
113
+ It is also a callable and a countable::
118
114
115
+ // ...
116
+ $numberOfHandlers = count($this->locator);
117
+ $nameOfHandlers = array_keys($this->locator->getProvidedServices());
119
118
// ...
120
119
$handler = ($this->locator)($commandClass);
121
120
@@ -305,15 +304,16 @@ argument of type ``service_locator``.
305
304
Consider the following ``CommandBus `` class where you want to inject
306
305
some services into it via a service locator::
307
306
308
- // src/HandlerCollection .php
307
+ // src/CommandBus .php
309
308
namespace App;
310
309
311
- use Symfony\Component\DependencyInjection\ServiceLocator ;
310
+ use Psr\Container\ContainerInterface ;
312
311
313
312
class CommandBus
314
313
{
315
- public function __construct(ServiceLocator $locator)
316
- {
314
+ public function __construct(
315
+ private ContainerInterface $locator,
316
+ ) {
317
317
}
318
318
}
319
319
@@ -327,14 +327,15 @@ or directly via PHP attributes:
327
327
// src/CommandBus.php
328
328
namespace App;
329
329
330
+ use Psr\Container\ContainerInterface;
330
331
use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
331
- use Symfony\Component\DependencyInjection\ServiceLocator;
332
332
333
333
class CommandBus
334
334
{
335
335
public function __construct(
336
336
// creates a service locator with all the services tagged with 'app.handler'
337
- #[TaggedLocator('app.handler')] ServiceLocator $locator
337
+ #[TaggedLocator('app.handler')]
338
+ private ContainerInterface $locator,
338
339
) {
339
340
}
340
341
}
@@ -564,14 +565,14 @@ of the ``key`` tag attribute (as defined in the ``index_by`` locator option):
564
565
// src/CommandBus.php
565
566
namespace App;
566
567
568
+ use Psr\Container\ContainerInterface;
567
569
use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
568
- use Symfony\Component\DependencyInjection\ServiceLocator;
569
570
570
571
class CommandBus
571
572
{
572
573
public function __construct(
573
574
#[TaggedLocator('app.handler', indexAttribute: 'key')]
574
- ServiceLocator $locator
575
+ private ContainerInterface $locator,
575
576
) {
576
577
}
577
578
}
@@ -645,13 +646,13 @@ Inside this locator you can retrieve services by index using the value of the
645
646
// src/Handler/HandlerCollection.php
646
647
namespace App\Handler;
647
648
648
- use Symfony\Component\DependencyInjection\ServiceLocator ;
649
+ use Psr\Container\ContainerInterface ;
649
650
650
651
class HandlerCollection
651
652
{
652
- public function __construct(ServiceLocator $locator)
653
+ public function getHandlerTwo(ContainerInterface $locator)
653
654
{
654
- $handlerTwo = $locator->get('handler_two');
655
+ return $locator->get('handler_two');
655
656
}
656
657
657
658
// ...
@@ -684,14 +685,14 @@ attribute to the locator service defining the name of this custom method:
684
685
// src/CommandBus.php
685
686
namespace App;
686
687
688
+ use Psr\Container\ContainerInterface;
687
689
use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
688
- use Symfony\Component\DependencyInjection\ServiceLocator;
689
690
690
691
class CommandBus
691
692
{
692
693
public function __construct(
693
694
#[TaggedLocator('app.handler', 'key', defaultIndexMethod: 'myOwnMethodName')]
694
- ServiceLocator $locator
695
+ private ContainerInterface $locator,
695
696
) {
696
697
}
697
698
}
@@ -749,7 +750,7 @@ The :class:`Symfony\\Contracts\\Service\\ServiceSubscriberTrait` provides an
749
750
implementation for :class: `Symfony\\ Contracts\\ Service\\ ServiceSubscriberInterface `
750
751
that looks through all methods in your class that are marked with the
751
752
:class: `Symfony\\ Contracts\\ Service\\ Attribute\\ SubscribedService ` attribute. It
752
- provides a `` ServiceLocator `` for the services of each method's return type.
753
+ describes the services needed by the class based on each method's return type.
753
754
The service id is ``__METHOD__ ``. This allows you to add dependencies to your
754
755
services based on type-hinted helper methods::
755
756
@@ -907,34 +908,25 @@ Here's an example::
907
908
Testing a Service Subscriber
908
909
----------------------------
909
910
910
- To unit test a service subscriber, you can create a fake `` ServiceLocator `` ::
911
+ To unit test a service subscriber, you can create a fake container ::
911
912
912
- use Symfony\Component\DependencyInjection\ServiceLocator;
913
+ use Symfony\Contracts\Service\ServiceLocatorTrait;
914
+ use Symfony\Contracts\Service\ServiceProviderInterface;
913
915
914
- $container = new class() extends ServiceLocator {
915
- private $services = [];
916
+ // Create the fake services
917
+ $foo = new stdClass();
918
+ $bar = new stdClass();
919
+ $bar->foo = $foo;
916
920
917
- public function __construct()
918
- {
919
- parent::__construct([
920
- 'foo' => function () {
921
- return $this->services['foo'] = $this->services['foo'] ?? new stdClass();
922
- },
923
- 'bar' => function () {
924
- return $this->services['bar'] = $this->services['bar'] ?? $this->createBar();
925
- },
926
- ]);
927
- }
928
-
929
- private function createBar()
930
- {
931
- $bar = new stdClass();
932
- $bar->foo = $this->get('foo');
933
-
934
- return $bar;
935
- }
921
+ // Create the fake container
922
+ $container = new class([
923
+ 'foo' => fn () => $foo,
924
+ 'bar' => fn () => $bar,
925
+ ]) implements ServiceProviderInterface {
926
+ use ServiceLocatorTrait;
936
927
};
937
928
929
+ // Create the service subscriber
938
930
$serviceSubscriber = new MyService($container);
939
931
// ...
940
932
0 commit comments