@@ -25,24 +25,22 @@ to handle their respective command when it is asked for::
2525 class CommandBus
2626 {
2727 /**
28- * @var CommandHandler[]
28+ * @param CommandHandler[] $handlerMap
2929 */
30- private $handlerMap;
31-
32- public function __construct(array $handlerMap)
33- {
34- $this->handlerMap = $handlerMap;
30+ public function __construct(
31+ private array $handlerMap,
32+ ) {
3533 }
3634
3735 public function handle(Command $command)
3836 {
3937 $commandClass = get_class($command);
4038
41- if (!isset($ this->handlerMap[$commandClass]) ) {
39+ if (!$handler = $ this->handlerMap[$commandClass] ?? null ) {
4240 return;
4341 }
4442
45- return $this->handlerMap[$commandClass] ->handle($command);
43+ return $handler ->handle($command);
4644 }
4745 }
4846
@@ -67,8 +65,7 @@ Defining a Service Subscriber
6765
6866First, turn ``CommandBus `` into an implementation of :class: `Symfony\\ Contracts\\ Service\\ ServiceSubscriberInterface `.
6967Use 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::
7269
7370 // src/CommandBus.php
7471 namespace App;
@@ -80,11 +77,9 @@ a PSR-11 ``ContainerInterface``::
8077
8178 class CommandBus implements ServiceSubscriberInterface
8279 {
83- private $locator;
84-
85- public function __construct(ContainerInterface $locator)
86- {
87- $this->locator = $locator;
80+ public function __construct(
81+ private ContainerInterface $locator,
82+ ) {
8883 }
8984
9085 public static function getSubscribedServices(): array
@@ -114,8 +109,12 @@ a PSR-11 ``ContainerInterface``::
114109 can also manually add the ``container.service_subscriber `` tag.
115110
116111The 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::
118114
115+ // ...
116+ $numberOfHandlers = count($this->locator);
117+ $nameOfHandlers = array_keys($this->locator->getProvidedServices());
119118 // ...
120119 $handler = ($this->locator)($commandClass);
121120
@@ -305,15 +304,16 @@ argument of type ``service_locator``.
305304Consider the following ``CommandBus `` class where you want to inject
306305some services into it via a service locator::
307306
308- // src/HandlerCollection .php
307+ // src/CommandBus .php
309308 namespace App;
310309
311- use Symfony\Component\DependencyInjection\ServiceLocator ;
310+ use Psr\Container\ContainerInterface ;
312311
313312 class CommandBus
314313 {
315- public function __construct(ServiceLocator $locator)
316- {
314+ public function __construct(
315+ private ContainerInterface $locator,
316+ ) {
317317 }
318318 }
319319
@@ -327,14 +327,15 @@ or directly via PHP attributes:
327327 // src/CommandBus.php
328328 namespace App;
329329
330+ use Psr\Container\ContainerInterface;
330331 use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
331- use Symfony\Component\DependencyInjection\ServiceLocator;
332332
333333 class CommandBus
334334 {
335335 public function __construct(
336336 // 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,
338339 ) {
339340 }
340341 }
@@ -564,14 +565,14 @@ of the ``key`` tag attribute (as defined in the ``index_by`` locator option):
564565 // src/CommandBus.php
565566 namespace App;
566567
568+ use Psr\Container\ContainerInterface;
567569 use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
568- use Symfony\Component\DependencyInjection\ServiceLocator;
569570
570571 class CommandBus
571572 {
572573 public function __construct(
573574 #[TaggedLocator('app.handler', indexAttribute: 'key')]
574- ServiceLocator $locator
575+ private ContainerInterface $locator,
575576 ) {
576577 }
577578 }
@@ -645,13 +646,13 @@ Inside this locator you can retrieve services by index using the value of the
645646 // src/Handler/HandlerCollection.php
646647 namespace App\Handler;
647648
648- use Symfony\Component\DependencyInjection\ServiceLocator ;
649+ use Psr\Container\ContainerInterface ;
649650
650651 class HandlerCollection
651652 {
652- public function __construct(ServiceLocator $locator)
653+ public function getHandlerTwo(ContainerInterface $locator)
653654 {
654- $handlerTwo = $locator->get('handler_two');
655+ return $locator->get('handler_two');
655656 }
656657
657658 // ...
@@ -684,14 +685,14 @@ attribute to the locator service defining the name of this custom method:
684685 // src/CommandBus.php
685686 namespace App;
686687
688+ use Psr\Container\ContainerInterface;
687689 use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
688- use Symfony\Component\DependencyInjection\ServiceLocator;
689690
690691 class CommandBus
691692 {
692693 public function __construct(
693694 #[TaggedLocator('app.handler', 'key', defaultIndexMethod: 'myOwnMethodName')]
694- ServiceLocator $locator
695+ private ContainerInterface $locator,
695696 ) {
696697 }
697698 }
@@ -749,7 +750,7 @@ The :class:`Symfony\\Contracts\\Service\\ServiceSubscriberTrait` provides an
749750implementation for :class: `Symfony\\ Contracts\\ Service\\ ServiceSubscriberInterface `
750751that looks through all methods in your class that are marked with the
751752: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.
753754The service id is ``__METHOD__ ``. This allows you to add dependencies to your
754755services based on type-hinted helper methods::
755756
@@ -907,34 +908,25 @@ Here's an example::
907908Testing a Service Subscriber
908909----------------------------
909910
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 ::
911912
912- use Symfony\Component\DependencyInjection\ServiceLocator;
913+ use Symfony\Contracts\Service\ServiceLocatorTrait;
914+ use Symfony\Contracts\Service\ServiceProviderInterface;
913915
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;
916920
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;
936927 };
937928
929+ // Create the service subscriber
938930 $serviceSubscriber = new MyService($container);
939931 // ...
940932
0 commit comments