@@ -30,24 +30,22 @@ to handle their respective command when it is asked for::
3030 class CommandBus
3131 {
3232 /**
33- * @var CommandHandler[]
33+ * @param CommandHandler[] $handlerMap
3434 */
35- private $handlerMap;
36-
37- public function __construct(array $handlerMap)
38- {
39- $this->handlerMap = $handlerMap;
35+ public function __construct(
36+ private array $handlerMap,
37+ ) {
4038 }
4139
4240 public function handle(Command $command)
4341 {
4442 $commandClass = get_class($command);
4543
46- if (!isset($ this->handlerMap[$commandClass]) ) {
44+ if (!$handler = $ this->handlerMap[$commandClass] ?? null ) {
4745 return;
4846 }
4947
50- return $this->handlerMap[$commandClass] ->handle($command);
48+ return $handler ->handle($command);
5149 }
5250 }
5351
@@ -72,8 +70,7 @@ Defining a Service Subscriber
7270
7371First, turn ``CommandBus `` into an implementation of :class: `Symfony\\ Contracts\\ Service\\ ServiceSubscriberInterface `.
7472Use 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::
7774
7875 // src/CommandBus.php
7976 namespace App;
@@ -85,11 +82,9 @@ a PSR-11 ``ContainerInterface``::
8582
8683 class CommandBus implements ServiceSubscriberInterface
8784 {
88- private $locator;
89-
90- public function __construct(ContainerInterface $locator)
91- {
92- $this->locator = $locator;
85+ public function __construct(
86+ private ContainerInterface $locator,
87+ ) {
9388 }
9489
9590 public static function getSubscribedServices(): array
@@ -119,8 +114,12 @@ a PSR-11 ``ContainerInterface``::
119114 can also manually add the ``container.service_subscriber `` tag.
120115
121116The 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::
123119
120+ // ...
121+ $numberOfHandlers = count($this->locator);
122+ $nameOfHandlers = array_keys($this->locator->getProvidedServices());
124123 // ...
125124 $handler = ($this->locator)($commandClass);
126125
@@ -312,15 +311,16 @@ argument of type ``service_locator``.
312311Consider the following ``CommandBus `` class where you want to inject
313312some services into it via a service locator::
314313
315- // src/HandlerCollection .php
314+ // src/CommandBus .php
316315 namespace App;
317316
318- use Symfony\Component\DependencyInjection\ServiceLocator ;
317+ use Psr\Container\ContainerInterface ;
319318
320319 class CommandBus
321320 {
322- public function __construct(ServiceLocator $locator)
323- {
321+ public function __construct(
322+ private ContainerInterface $locator,
323+ ) {
324324 }
325325 }
326326
@@ -334,14 +334,15 @@ or directly via PHP attributes:
334334 // src/CommandBus.php
335335 namespace App;
336336
337+ use Psr\Container\ContainerInterface;
337338 use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
338- use Symfony\Component\DependencyInjection\ServiceLocator;
339339
340340 class CommandBus
341341 {
342342 public function __construct(
343343 // 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,
345346 ) {
346347 }
347348 }
@@ -571,14 +572,14 @@ of the ``key`` tag attribute (as defined in the ``index_by`` locator option):
571572 // src/CommandBus.php
572573 namespace App;
573574
575+ use Psr\Container\ContainerInterface;
574576 use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
575- use Symfony\Component\DependencyInjection\ServiceLocator;
576577
577578 class CommandBus
578579 {
579580 public function __construct(
580581 #[TaggedLocator('app.handler', indexAttribute: 'key')]
581- ServiceLocator $locator
582+ private ContainerInterface $locator,
582583 ) {
583584 }
584585 }
@@ -652,13 +653,13 @@ Inside this locator you can retrieve services by index using the value of the
652653 // src/Handler/HandlerCollection.php
653654 namespace App\Handler;
654655
655- use Symfony\Component\DependencyInjection\ServiceLocator ;
656+ use Psr\Container\ContainerInterface ;
656657
657658 class HandlerCollection
658659 {
659- public function __construct(ServiceLocator $locator)
660+ public function getHandlerTwo(ContainerInterface $locator)
660661 {
661- $handlerTwo = $locator->get('handler_two');
662+ return $locator->get('handler_two');
662663 }
663664
664665 // ...
@@ -691,14 +692,14 @@ attribute to the locator service defining the name of this custom method:
691692 // src/CommandBus.php
692693 namespace App;
693694
695+ use Psr\Container\ContainerInterface;
694696 use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
695- use Symfony\Component\DependencyInjection\ServiceLocator;
696697
697698 class CommandBus
698699 {
699700 public function __construct(
700701 #[TaggedLocator('app.handler', 'key', defaultIndexMethod: 'myOwnMethodName')]
701- ServiceLocator $locator
702+ private ContainerInterface $locator,
702703 ) {
703704 }
704705 }
@@ -758,7 +759,7 @@ The :class:`Symfony\\Contracts\\Service\\ServiceSubscriberTrait` provides an
758759implementation for :class: `Symfony\\ Contracts\\ Service\\ ServiceSubscriberInterface `
759760that looks through all methods in your class that are marked with the
760761: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.
762763The service id is ``__METHOD__ ``. This allows you to add dependencies to your
763764services based on type-hinted helper methods::
764765
@@ -916,34 +917,25 @@ Here's an example::
916917Testing a Service Subscriber
917918----------------------------
918919
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 ::
920921
921- use Symfony\Component\DependencyInjection\ServiceLocator;
922+ use Symfony\Contracts\Service\ServiceLocatorTrait;
923+ use Symfony\Contracts\Service\ServiceProviderInterface;
922924
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;
925929
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;
945936 };
946937
938+ // Create the service subscriber
947939 $serviceSubscriber = new MyService($container);
948940 // ...
949941
0 commit comments