From 408bf9534c51cc3ee5b3e1c56376e7cae903bdb2 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 21 Aug 2023 15:04:45 +0200 Subject: [PATCH] [DependencyInjection] Add `#[AutowireLocator]` attribute --- reference/attributes.rst | 1 + .../service_subscribers_locators.rst | 76 +++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/reference/attributes.rst b/reference/attributes.rst index 761099a7356..e8825e6d30e 100644 --- a/reference/attributes.rst +++ b/reference/attributes.rst @@ -38,6 +38,7 @@ Dependency Injection * :ref:`Autowire ` * :ref:`AutowireCallable ` * :doc:`AutowireDecorated ` +* :ref:`AutowireLocator ` * :ref:`AutowireServiceClosure ` * :ref:`Exclude ` * :ref:`TaggedIterator ` diff --git a/service_container/service_subscribers_locators.rst b/service_container/service_subscribers_locators.rst index 4dabc22e0f3..85dc9fdbaeb 100644 --- a/service_container/service_subscribers_locators.rst +++ b/service_container/service_subscribers_locators.rst @@ -297,6 +297,82 @@ This is done by having ``getSubscribedServices()`` return an array of The above example requires using ``3.2`` version or newer of ``symfony/service-contracts``. +.. _service-locator_autowire-locator: + +The AutowireLocator attribute +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Another way to define a service locator is to use the +:class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireLocator` +attribute:: + + // src/CommandBus.php + namespace App; + + use App\CommandHandler\BarHandler; + use App\CommandHandler\FooHandler; + use Psr\Container\ContainerInterface; + use Symfony\Component\DependencyInjection\Attribute\AutowireLocator; + + class CommandBus + { + public function __construct( + #[AutowireLocator(FooHandler::class, BarHandler::class)] + private ContainerInterface $locator, + ) { + } + + public function handle(Command $command): mixed + { + $commandClass = get_class($command); + + if ($this->locator->has($commandClass)) { + $handler = $this->locator->get($commandClass); + + return $handler->handle($command); + } + } + } + +Just like with the ``getSubscribedServices()`` method, it is possible +to define aliased services thanks to named arguments, as well as optional +services:: + + // src/CommandBus.php + namespace App; + + use App\CommandHandler\BarHandler; + use App\CommandHandler\BazHandler; + use App\CommandHandler\FooHandler; + use Psr\Container\ContainerInterface; + use Symfony\Component\DependencyInjection\Attribute\AutowireLocator; + + class CommandBus + { + public function __construct( + #[AutowireLocator( + fooHandlerAlias: FooHandler::class, + barHandlerAlias: BarHandler::class, + optionalBazHandlerAlias: '?'.BazHandler::class + )] + private ContainerInterface $locator, + ) { + } + + public function handle(Command $command): mixed + { + $fooHandler = $this->locator->get('fooHandlerAlias'); + + // ... + } + } + +.. versionadded:: 6.4 + + The + :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireLocator` + attribute was introduced in Symfony 6.4. + .. _service-subscribers-locators_defining-service-locator: Defining a Service Locator