From 2dbbfbda4e93712b70fd4de53142a7606cd01df6 Mon Sep 17 00:00:00 2001 From: Samuel ROZE Date: Sun, 26 Aug 2018 15:06:12 +0100 Subject: [PATCH] Allow interfaces to be type-hinted as well --- .../DependencyInjection/MessengerPass.php | 2 +- .../Locator/ContainerHandlerLocator.php | 33 +++++++++- .../Middleware/SendMessageMiddlewareTest.php | 2 +- .../Routing/SenderLocatorTest.php | 5 +- .../Tests/Fixtures/ChildDummyMessage.php | 16 +++++ .../Locator/ContainerHandlerLocatorTest.php | 62 +++++++++++++++++++ 6 files changed, 111 insertions(+), 9 deletions(-) create mode 100644 src/Symfony/Component/Messenger/Tests/Fixtures/ChildDummyMessage.php create mode 100644 src/Symfony/Component/Messenger/Tests/Handler/Locator/ContainerHandlerLocatorTest.php diff --git a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php index 2de3289a51695..6d25a535b1de2 100644 --- a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php +++ b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php @@ -114,7 +114,7 @@ private function registerHandlers(ContainerBuilder $container, array $busIds) $method = $method[0]; } - if (!\class_exists($messageClass)) { + if (!\class_exists($messageClass) && !\interface_exists($messageClass)) { $messageClassLocation = isset($tag['handles']) ? 'declared in your tag attribute "handles"' : $r->implementsInterface(MessageSubscriberInterface::class) ? sprintf('returned by method "%s::getHandledMessages()"', $r->getName()) : sprintf('used as argument type in method "%s::%s()"', $r->getName(), $method); throw new RuntimeException(sprintf('Invalid handler service "%s": message class "%s" %s does not exist.', $serviceId, $messageClass, $messageClassLocation)); diff --git a/src/Symfony/Component/Messenger/Handler/Locator/ContainerHandlerLocator.php b/src/Symfony/Component/Messenger/Handler/Locator/ContainerHandlerLocator.php index 7b45b4eac4ac9..5b02991d0078d 100644 --- a/src/Symfony/Component/Messenger/Handler/Locator/ContainerHandlerLocator.php +++ b/src/Symfony/Component/Messenger/Handler/Locator/ContainerHandlerLocator.php @@ -30,12 +30,39 @@ public function __construct(ContainerInterface $container) public function resolve($message): callable { $messageClass = \get_class($message); - $handlerKey = 'handler.'.$messageClass; - if (!$this->container->has($handlerKey)) { + if (null === $handler = $this->resolveFromClass($messageClass)) { throw new NoHandlerForMessageException(sprintf('No handler for message "%s".', $messageClass)); } - return $this->container->get($handlerKey); + return $handler; + } + + private function resolveFromClass($class): ?callable + { + if ($handler = $this->getHandler($class)) { + return $handler; + } + + foreach (class_implements($class, false) as $interface) { + if ($handler = $this->getHandler($interface)) { + return $handler; + } + } + + foreach (class_parents($class, false) as $parent) { + if ($handler = $this->getHandler($parent)) { + return $handler; + } + } + + return null; + } + + private function getHandler($class) + { + $handlerKey = 'handler.'.$class; + + return $this->container->has($handlerKey) ? $this->container->get($handlerKey) : null; } } diff --git a/src/Symfony/Component/Messenger/Tests/Asynchronous/Middleware/SendMessageMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Asynchronous/Middleware/SendMessageMiddlewareTest.php index 5a4dc5f204b9d..91d4bbeea15bd 100644 --- a/src/Symfony/Component/Messenger/Tests/Asynchronous/Middleware/SendMessageMiddlewareTest.php +++ b/src/Symfony/Component/Messenger/Tests/Asynchronous/Middleware/SendMessageMiddlewareTest.php @@ -16,7 +16,7 @@ use Symfony\Component\Messenger\Asynchronous\Routing\SenderLocatorInterface; use Symfony\Component\Messenger\Asynchronous\Transport\ReceivedMessage; use Symfony\Component\Messenger\Envelope; -use Symfony\Component\Messenger\Tests\Asynchronous\Routing\ChildDummyMessage; +use Symfony\Component\Messenger\Tests\Fixtures\ChildDummyMessage; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessageInterface; use Symfony\Component\Messenger\Transport\SenderInterface; diff --git a/src/Symfony/Component/Messenger/Tests/Asynchronous/Routing/SenderLocatorTest.php b/src/Symfony/Component/Messenger/Tests/Asynchronous/Routing/SenderLocatorTest.php index 22cf6bac81e67..370ffd3cddeeb 100644 --- a/src/Symfony/Component/Messenger/Tests/Asynchronous/Routing/SenderLocatorTest.php +++ b/src/Symfony/Component/Messenger/Tests/Asynchronous/Routing/SenderLocatorTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\Messenger\Asynchronous\Routing\SenderLocator; +use Symfony\Component\Messenger\Tests\Fixtures\ChildDummyMessage; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessageInterface; use Symfony\Component\Messenger\Tests\Fixtures\SecondMessage; @@ -88,7 +89,3 @@ public function testItSupportsAWildcardInsteadOfTheMessageClass() $this->assertSame($apiSender, $locator->getSenderForMessage(new SecondMessage())); } } - -class ChildDummyMessage extends DummyMessage -{ -} diff --git a/src/Symfony/Component/Messenger/Tests/Fixtures/ChildDummyMessage.php b/src/Symfony/Component/Messenger/Tests/Fixtures/ChildDummyMessage.php new file mode 100644 index 0000000000000..474ae1449cd13 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Fixtures/ChildDummyMessage.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Fixtures; + +class ChildDummyMessage extends DummyMessage +{ +} diff --git a/src/Symfony/Component/Messenger/Tests/Handler/Locator/ContainerHandlerLocatorTest.php b/src/Symfony/Component/Messenger/Tests/Handler/Locator/ContainerHandlerLocatorTest.php new file mode 100644 index 0000000000000..56d6ac7360347 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Handler/Locator/ContainerHandlerLocatorTest.php @@ -0,0 +1,62 @@ +set('handler.'.DummyMessage::class, $handler); + + $locator = new ContainerHandlerLocator($container); + $resolvedHandler = $locator->resolve(new DummyMessage('Hey')); + + $this->assertSame($handler, $resolvedHandler); + } + + /** + * @expectedException \Symfony\Component\Messenger\Exception\NoHandlerForMessageException + * @expectedExceptionMessage No handler for message "Symfony\Component\Messenger\Tests\Fixtures\DummyMessage" + */ + public function testThrowsNoHandlerException() + { + $locator = new ContainerHandlerLocator(new Container()); + $locator->resolve(new DummyMessage('Hey')); + } + + public function testResolveMessageViaTheirInterface() + { + $handler = function () {}; + + $container = new Container(); + $container->set('handler.'.DummyMessageInterface::class, $handler); + + $locator = new ContainerHandlerLocator($container); + $resolvedHandler = $locator->resolve(new DummyMessage('Hey')); + + $this->assertSame($handler, $resolvedHandler); + } + + public function testResolveMessageViaTheirParentClass() + { + $handler = function () {}; + + $container = new Container(); + $container->set('handler.'.DummyMessage::class, $handler); + + $locator = new ContainerHandlerLocator($container); + $resolvedHandler = $locator->resolve(new ChildDummyMessage('Hey')); + + $this->assertSame($handler, $resolvedHandler); + } +}