diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/message.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/message.xml index 731fd96b255cb..3884ef97dd388 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/message.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/message.xml @@ -7,7 +7,7 @@ - + @@ -15,12 +15,12 @@ - - + + - + diff --git a/src/Symfony/Component/Message/ContainerHandlerLocator.php b/src/Symfony/Component/Message/ContainerHandlerLocator.php new file mode 100644 index 0000000000000..c4b358af6f820 --- /dev/null +++ b/src/Symfony/Component/Message/ContainerHandlerLocator.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Message; + +use Psr\Container\ContainerInterface; +use Symfony\Component\Message\Exception\NoHandlerForMessageException; + +/** + * @author Miha Vrhovnik + */ +class ContainerHandlerLocator implements HandlerLocatorInterface +{ + /** + * @var ContainerInterface + */ + private $serviceLocator; + + public function __construct(ContainerInterface $serviceLocator) + { + $this->serviceLocator = $serviceLocator; + } + + public function resolve($message): callable + { + $messageKey = get_class($message); + + if (!$this->serviceLocator->has($messageKey)) { + throw new NoHandlerForMessageException(sprintf('No handler for message "%s"', $messageKey)); + } + + return $this->serviceLocator->get($messageKey); + } + +} diff --git a/src/Symfony/Component/Message/DependencyInjection/MessagePass.php b/src/Symfony/Component/Message/DependencyInjection/MessagePass.php index 3426357a371e9..8e30fcba48739 100644 --- a/src/Symfony/Component/Message/DependencyInjection/MessagePass.php +++ b/src/Symfony/Component/Message/DependencyInjection/MessagePass.php @@ -13,9 +13,12 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait; +use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\Message\Handler\MessageHandlerCollection; /** * @author Samuel Roze @@ -29,7 +32,7 @@ class MessagePass implements CompilerPassInterface private $messageHandlerResolverService; private $handlerTag; - public function __construct(string $messageBusService = 'message_bus', string $middlewareTag = 'message_middleware', string $messageHandlerResolverService = 'message.handler_resolver', string $handlerTag = 'message_handler') + public function __construct(string $messageBusService = 'message_bus', string $middlewareTag = 'message_middleware', string $messageHandlerResolverService = 'message.container_message_handler_resolver', string $handlerTag = 'message_handler') { $this->messageBusService = $messageBusService; $this->middlewareTag = $middlewareTag; @@ -53,11 +56,10 @@ public function process(ContainerBuilder $container) $busDefinition = $container->getDefinition($this->messageBusService); $busDefinition->replaceArgument(0, $middlewares); - $handlerResolver = $container->getDefinition($this->messageHandlerResolverService); - $handlerResolver->replaceArgument(0, $this->findHandlers($container)); + $this->registerHandlers($container); } - private function findHandlers(ContainerBuilder $container): array + private function registerHandlers(ContainerBuilder $container) { $handlersByMessage = array(); @@ -79,7 +81,23 @@ private function findHandlers(ContainerBuilder $container): array $handlersByMessage[$message] = call_user_func_array('array_merge', $handlersByMessage[$message]); } - return $handlersByMessage; + + $definitions = array(); + foreach ($handlersByMessage as $message => $handlers) { + if (1 === count($handlers)) { + $handlersByMessage[$message] = current($handlers); + } else { + $d = new Definition(MessageHandlerCollection::class, array($handlers)); + $d->setPrivate(true); + $serviceId = hash('sha1', $message); + $definitions[$serviceId] = $d; + $handlersByMessage[$message] = new Reference($serviceId); + } + } + $container->addDefinitions($definitions); + + $handlerResolver = $container->getDefinition($this->messageHandlerResolverService); + $handlerResolver->replaceArgument(0, ServiceLocatorTagPass::register($container, $handlersByMessage)); } private function guessHandledClass(ContainerBuilder $container, string $serviceId): string