From 6a5d7a1aace0b898affde1cab4ea51ad8c5ec29d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 17 Oct 2018 15:58:28 +0200 Subject: [PATCH] [Messenger] make middlewares truly lazy on a bus --- .../Component/Messenger/MessageBus.php | 53 ++++++++++++------- .../DependencyInjection/MessengerPassTest.php | 12 ++--- .../Messenger/Tests/MessageBusTest.php | 4 +- 3 files changed, 41 insertions(+), 28 deletions(-) diff --git a/src/Symfony/Component/Messenger/MessageBus.php b/src/Symfony/Component/Messenger/MessageBus.php index ecaa0623fe0b7..96fa689968543 100644 --- a/src/Symfony/Component/Messenger/MessageBus.php +++ b/src/Symfony/Component/Messenger/MessageBus.php @@ -11,28 +11,39 @@ namespace Symfony\Component\Messenger; -use Symfony\Component\Messenger\Exception\InvalidArgumentException; use Symfony\Component\Messenger\Middleware\MiddlewareInterface; /** * @author Samuel Roze * @author Matthias Noback + * @author Nicolas Grekas */ class MessageBus implements MessageBusInterface { - private $middlewareHandlers; - - /** - * @var MiddlewareInterface[]|null - */ - private $indexedMiddlewareHandlers; + private $middlewareAggregate; /** * @param MiddlewareInterface[]|iterable $middlewareHandlers */ public function __construct(iterable $middlewareHandlers = array()) { - $this->middlewareHandlers = $middlewareHandlers; + if ($middlewareHandlers instanceof \IteratorAggregate) { + $this->middlewareAggregate = $middlewareHandlers; + } elseif (\is_array($middlewareHandlers)) { + $this->middlewareAggregate = new \ArrayObject($middlewareHandlers); + } else { + $this->middlewareAggregate = new class() { + public $aggregate; + public $iterator; + + public function getIterator() + { + return $this->aggregate = new \ArrayObject(iterator_to_array($this->iterator, false)); + } + }; + $this->middlewareAggregate->aggregate = &$this->middlewareAggregate; + $this->middlewareAggregate->iterator = $middlewareHandlers; + } } /** @@ -41,24 +52,26 @@ public function __construct(iterable $middlewareHandlers = array()) public function dispatch($message): void { if (!\is_object($message)) { - throw new InvalidArgumentException(sprintf('Invalid type for message argument. Expected object, but got "%s".', \gettype($message))); + throw new \TypeError(sprintf('Invalid argument provided to "%s()": expected object, but got %s.', __METHOD__, \gettype($message))); } + $middlewareIterator = $this->middlewareAggregate->getIterator(); - $this->callableForNextMiddleware(0)($message instanceof Envelope ? $message : new Envelope($message)); - } - - private function callableForNextMiddleware(int $index): callable - { - if (null === $this->indexedMiddlewareHandlers) { - $this->indexedMiddlewareHandlers = \is_array($this->middlewareHandlers) ? array_values($this->middlewareHandlers) : iterator_to_array($this->middlewareHandlers, false); + while ($middlewareIterator instanceof \IteratorAggregate) { + $middlewareIterator = $middlewareIterator->getIterator(); } + $middlewareIterator->rewind(); - if (!isset($this->indexedMiddlewareHandlers[$index])) { - return static function () {}; + if (!$middlewareIterator->valid()) { + return; } + $next = static function (Envelope $envelope) use ($middlewareIterator, &$next) { + $middlewareIterator->next(); - return function (Envelope $envelope) use ($index) { - $this->indexedMiddlewareHandlers[$index]->handle($envelope, $this->callableForNextMiddleware($index + 1)); + if ($middlewareIterator->valid()) { + $middlewareIterator->current()->handle($envelope, $next); + } }; + + $middlewareIterator->current()->handle($message instanceof Envelope ? $message : new Envelope($message), $next); } } diff --git a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php index 85db4cb195206..28530d7ea0daa 100644 --- a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php +++ b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php @@ -90,10 +90,10 @@ public function testProcessHandlersByBus() ->setAbstract(true) ; - $middlewares = array(array('id' => 'call_message_handler')); + $middlewareHandlers = array(array('id' => 'call_message_handler')); - $container->setParameter($commandBusId.'.middleware', $middlewares); - $container->setParameter($queryBusId.'.middleware', $middlewares); + $container->setParameter($commandBusId.'.middleware', $middlewareHandlers); + $container->setParameter($queryBusId.'.middleware', $middlewareHandlers); $container->register(DummyCommandHandler::class)->addTag('messenger.message_handler', array('bus' => $commandBusId)); $container->register(DummyQueryHandler::class)->addTag('messenger.message_handler', array('bus' => $queryBusId)); @@ -607,10 +607,10 @@ public function testItRegistersTheDebugCommand() $container->register('console.command.messenger_debug', DebugCommand::class)->addArgument(array()); - $middlewares = array(array('id' => 'call_message_handler')); + $middlewareHandlers = array(array('id' => 'call_message_handler')); - $container->setParameter($commandBusId.'.middleware', $middlewares); - $container->setParameter($queryBusId.'.middleware', $middlewares); + $container->setParameter($commandBusId.'.middleware', $middlewareHandlers); + $container->setParameter($queryBusId.'.middleware', $middlewareHandlers); $container->register(DummyCommandHandler::class)->addTag('messenger.message_handler', array('bus' => $commandBusId)); $container->register(DummyQueryHandler::class)->addTag('messenger.message_handler', array('bus' => $queryBusId)); diff --git a/src/Symfony/Component/Messenger/Tests/MessageBusTest.php b/src/Symfony/Component/Messenger/Tests/MessageBusTest.php index 0ea4c644ce66d..c89eab3586300 100644 --- a/src/Symfony/Component/Messenger/Tests/MessageBusTest.php +++ b/src/Symfony/Component/Messenger/Tests/MessageBusTest.php @@ -30,8 +30,8 @@ public function testItHasTheRightInterface() } /** - * @expectedException \Symfony\Component\Messenger\Exception\InvalidArgumentException - * @expectedExceptionMessage Invalid type for message argument. Expected object, but got "string". + * @expectedException \TypeError + * @expectedExceptionMessage Invalid argument provided to "Symfony\Component\Messenger\MessageBus::dispatch()": expected object, but got string. */ public function testItDispatchInvalidMessageType() {