diff --git a/src/Symfony/Bridge/Doctrine/Messenger/DoctrineTransactionMiddleware.php b/src/Symfony/Bridge/Doctrine/Messenger/DoctrineTransactionMiddleware.php index b6de4132d045a..0e7444a291271 100644 --- a/src/Symfony/Bridge/Doctrine/Messenger/DoctrineTransactionMiddleware.php +++ b/src/Symfony/Bridge/Doctrine/Messenger/DoctrineTransactionMiddleware.php @@ -15,6 +15,7 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Middleware\MiddlewareInterface; +use Symfony\Component\Messenger\Middleware\StackInterface; /** * Wraps all handlers in a single doctrine transaction. @@ -35,7 +36,7 @@ public function __construct(ManagerRegistry $managerRegistry, ?string $entityMan /** * {@inheritdoc} */ - public function handle(Envelope $envelope, callable $next): void + public function handle(Envelope $envelope, StackInterface $stack): void { $entityManager = $this->managerRegistry->getManager($this->entityManagerName); @@ -45,7 +46,7 @@ public function handle(Envelope $envelope, callable $next): void $entityManager->getConnection()->beginTransaction(); try { - $next($envelope); + $stack->next()->handle($envelope, $stack); $entityManager->flush(); $entityManager->getConnection()->commit(); } catch (\Throwable $exception) { diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 84acedf33baa4..ac74e4309e3dd 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -7,7 +7,7 @@ CHANGELOG * The component is not experimental anymore * All the changes below are BC BREAKS * `MessageBusInterface::dispatch()` and `MiddlewareInterface::handle()` now return `void` - * `MiddlewareInterface::handle()` now require an `Envelope` as first argument + * `MiddlewareInterface::handle()` now require an `Envelope` as first argument and a `StackInterface` as second * `EnvelopeAwareInterface` has been removed * The signature of `Amqp*` classes changed to take a `Connection` as a first argument and an optional `Serializer` as a second argument. @@ -16,7 +16,6 @@ CHANGELOG Instead, it accepts the sender instance itself instead of its identifier in the container. * `MessageSubscriberInterface::getHandledMessages()` return value has changed. The value of an array item needs to be an associative array or the method name. - * `ValidationMiddleware::handle()` and `SendMessageMiddleware::handle()` now require an `Envelope` object * `StampInterface` replaces `EnvelopeItemInterface` and doesn't extend `Serializable` anymore * The `ConsumeMessagesCommand` class now takes an instance of `Psr\Container\ContainerInterface` as first constructor argument diff --git a/src/Symfony/Component/Messenger/MessageBus.php b/src/Symfony/Component/Messenger/MessageBus.php index 96fa689968543..8cbcf2bf0e05f 100644 --- a/src/Symfony/Component/Messenger/MessageBus.php +++ b/src/Symfony/Component/Messenger/MessageBus.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Messenger; use Symfony\Component\Messenger\Middleware\MiddlewareInterface; +use Symfony\Component\Messenger\Middleware\StackMiddleware; /** * @author Samuel Roze @@ -64,14 +65,8 @@ public function dispatch($message): void if (!$middlewareIterator->valid()) { return; } - $next = static function (Envelope $envelope) use ($middlewareIterator, &$next) { - $middlewareIterator->next(); + $stack = new StackMiddleware($middlewareIterator); - if ($middlewareIterator->valid()) { - $middlewareIterator->current()->handle($envelope, $next); - } - }; - - $middlewareIterator->current()->handle($message instanceof Envelope ? $message : new Envelope($message), $next); + $middlewareIterator->current()->handle($message instanceof Envelope ? $message : new Envelope($message), $stack); } } diff --git a/src/Symfony/Component/Messenger/Middleware/ActivationMiddleware.php b/src/Symfony/Component/Messenger/Middleware/ActivationMiddleware.php index 1f983541828e5..1c86b8a94a599 100644 --- a/src/Symfony/Component/Messenger/Middleware/ActivationMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/ActivationMiddleware.php @@ -35,12 +35,12 @@ public function __construct(MiddlewareInterface $inner, $activated) /** * {@inheritdoc} */ - public function handle(Envelope $envelope, callable $next): void + public function handle(Envelope $envelope, StackInterface $stack): void { if (\is_callable($this->activated) ? ($this->activated)($envelope) : $this->activated) { - $this->inner->handle($envelope, $next); + $this->inner->handle($envelope, $stack); } else { - $next($envelope); + $stack->next()->handle($envelope, $stack); } } } diff --git a/src/Symfony/Component/Messenger/Middleware/HandleMessageMiddleware.php b/src/Symfony/Component/Messenger/Middleware/HandleMessageMiddleware.php index 12b74987082a8..820f6f1f27378 100644 --- a/src/Symfony/Component/Messenger/Middleware/HandleMessageMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/HandleMessageMiddleware.php @@ -34,11 +34,11 @@ public function __construct(HandlerLocatorInterface $messageHandlerLocator, bool * * @throws NoHandlerForMessageException When no handler is found and $allowNoHandlers is false */ - public function handle(Envelope $envelope, callable $next): void + public function handle(Envelope $envelope, StackInterface $stack): void { if (null !== $handler = $this->messageHandlerLocator->getHandler($envelope)) { $handler($envelope->getMessage()); - $next($envelope); + $stack->next()->handle($envelope, $stack); } elseif (!$this->allowNoHandlers) { throw new NoHandlerForMessageException(sprintf('No handler for message "%s".', \get_class($envelope->getMessage()))); } diff --git a/src/Symfony/Component/Messenger/Middleware/LoggingMiddleware.php b/src/Symfony/Component/Messenger/Middleware/LoggingMiddleware.php index 758e160a2b6f8..0ba046c2708aa 100644 --- a/src/Symfony/Component/Messenger/Middleware/LoggingMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/LoggingMiddleware.php @@ -29,7 +29,7 @@ public function __construct(LoggerInterface $logger) /** * {@inheritdoc} */ - public function handle(Envelope $envelope, callable $next): void + public function handle(Envelope $envelope, StackInterface $stack): void { $message = $envelope->getMessage(); $context = array( @@ -39,7 +39,7 @@ public function handle(Envelope $envelope, callable $next): void $this->logger->debug('Starting handling message {name}', $context); try { - $next($envelope); + $stack->next()->handle($envelope, $stack); } catch (\Throwable $e) { $context['exception'] = $e; $this->logger->warning('An exception occurred while handling message {name}', $context); diff --git a/src/Symfony/Component/Messenger/Middleware/MiddlewareInterface.php b/src/Symfony/Component/Messenger/Middleware/MiddlewareInterface.php index def80def13792..b42d795f5fb24 100644 --- a/src/Symfony/Component/Messenger/Middleware/MiddlewareInterface.php +++ b/src/Symfony/Component/Messenger/Middleware/MiddlewareInterface.php @@ -18,16 +18,5 @@ */ interface MiddlewareInterface { - /** - * @param callable|NextInterface $next - */ - public function handle(Envelope $envelope, callable $next): void; -} - -/** - * @internal - */ -interface NextInterface -{ - public function __invoke(Envelope $envelope): void; + public function handle(Envelope $envelope, StackInterface $stack): void; } diff --git a/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php b/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php index c12622396b940..2e323a8e69ffd 100644 --- a/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php @@ -34,11 +34,11 @@ public function __construct(SenderLocatorInterface $senderLocator, array $messag /** * {@inheritdoc} */ - public function handle(Envelope $envelope, callable $next): void + public function handle(Envelope $envelope, StackInterface $stack): void { if ($envelope->get(ReceivedStamp::class)) { // It's a received message. Do not send it back: - $next($envelope); + $stack->next()->handle($envelope, $stack); return; } @@ -54,6 +54,6 @@ public function handle(Envelope $envelope, callable $next): void } } - $next($envelope); + $stack->next()->handle($envelope, $stack); } } diff --git a/src/Symfony/Component/Messenger/Middleware/StackInterface.php b/src/Symfony/Component/Messenger/Middleware/StackInterface.php new file mode 100644 index 0000000000000..2c9eeeba121ba --- /dev/null +++ b/src/Symfony/Component/Messenger/Middleware/StackInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Middleware; + +/** + * @author Nicolas Grekas + */ +interface StackInterface +{ + /** + * Returns the next middleware to process a message. + */ + public function next(): MiddlewareInterface; +} diff --git a/src/Symfony/Component/Messenger/Middleware/StackMiddleware.php b/src/Symfony/Component/Messenger/Middleware/StackMiddleware.php new file mode 100644 index 0000000000000..51da5d4d1a3e4 --- /dev/null +++ b/src/Symfony/Component/Messenger/Middleware/StackMiddleware.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Middleware; + +use Symfony\Component\Messenger\Envelope; + +/** + * @author Nicolas Grekas + */ +class StackMiddleware implements MiddlewareInterface, StackInterface +{ + private $middlewareIterator; + + public function __construct(\Iterator $middlewareIterator = null) + { + $this->middlewareIterator = $middlewareIterator; + } + + public function next(): MiddlewareInterface + { + if (null === $iterator = $this->middlewareIterator) { + return $this; + } + $iterator->next(); + + if (!$iterator->valid()) { + $this->middlewareIterator = null; + + return $this; + } + + return $iterator->current(); + } + + public function handle(Envelope $envelope, StackInterface $stack): void + { + // no-op: this is the last null middleware + } +} diff --git a/src/Symfony/Component/Messenger/Middleware/TraceableMiddleware.php b/src/Symfony/Component/Messenger/Middleware/TraceableMiddleware.php index 43de86a56d713..65eb8d539ef12 100644 --- a/src/Symfony/Component/Messenger/Middleware/TraceableMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/TraceableMiddleware.php @@ -37,7 +37,7 @@ public function __construct(MiddlewareInterface $inner, Stopwatch $stopwatch, st /** * {@inheritdoc} */ - public function handle(Envelope $envelope, callable $next): void + public function handle(Envelope $envelope, StackInterface $stack): void { $class = \get_class($this->inner); $eventName = 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class; @@ -49,11 +49,7 @@ public function handle(Envelope $envelope, callable $next): void $this->stopwatch->start($eventName, $this->eventCategory); try { - $this->inner->handle($envelope, function (Envelope $envelope) use ($next, $eventName) { - $this->stopwatch->stop($eventName); - $next($envelope); - $this->stopwatch->start($eventName, $this->eventCategory); - }); + $this->inner->handle($envelope, new TraceableInnerMiddleware($stack, $this->stopwatch, $eventName, $this->eventCategory)); } finally { if ($this->stopwatch->isStarted($eventName)) { $this->stopwatch->stop($eventName); @@ -61,3 +57,44 @@ public function handle(Envelope $envelope, callable $next): void } } } + +/** + * @internal + */ +class TraceableInnerMiddleware implements MiddlewareInterface, StackInterface +{ + private $stack; + private $stopwatch; + private $eventName; + private $eventCategory; + + public function __construct(StackInterface $stack, Stopwatch $stopwatch, string $eventName, string $eventCategory) + { + $this->stack = $stack; + $this->stopwatch = $stopwatch; + $this->eventName = $eventName; + $this->eventCategory = $eventCategory; + } + + /** + * {@inheritdoc} + */ + public function handle(Envelope $envelope, StackInterface $stack): void + { + $this->stopwatch->stop($this->eventName); + if ($this === $stack) { + $this->stack->next()->handle($envelope, $this->stack); + } else { + $stack->next()->handle($envelope, $stack); + } + $this->stopwatch->start($this->eventName, $this->eventCategory); + } + + /** + * {@inheritdoc} + */ + public function next(): MiddlewareInterface + { + return $this; + } +} diff --git a/src/Symfony/Component/Messenger/Middleware/ValidationMiddleware.php b/src/Symfony/Component/Messenger/Middleware/ValidationMiddleware.php index cfc70c9216478..e70415a1ac82c 100644 --- a/src/Symfony/Component/Messenger/Middleware/ValidationMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/ValidationMiddleware.php @@ -31,7 +31,7 @@ public function __construct(ValidatorInterface $validator) /** * {@inheritdoc} */ - public function handle(Envelope $envelope, callable $next): void + public function handle(Envelope $envelope, StackInterface $stack): void { $message = $envelope->getMessage(); $groups = null; @@ -45,6 +45,6 @@ public function handle(Envelope $envelope, callable $next): void throw new ValidationFailedException($message, $violations); } - $next($envelope); + $stack->next()->handle($envelope, $stack); } } diff --git a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php index 1ca439cbcc90e..415329ea0d4d3 100644 --- a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php +++ b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php @@ -29,6 +29,7 @@ use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware; use Symfony\Component\Messenger\Middleware\MiddlewareInterface; +use Symfony\Component\Messenger\Middleware\StackInterface; use Symfony\Component\Messenger\Tests\Fixtures\DummyCommand; use Symfony\Component\Messenger\Tests\Fixtures\DummyCommandHandler; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; @@ -846,8 +847,8 @@ public function dummyMethodForSomeBus() class UselessMiddleware implements MiddlewareInterface { - public function handle(Envelope $message, callable $next): void + public function handle(Envelope $message, StackInterface $stack): void { - $next($message); + $stack->next()->handle($message, $stack); } } diff --git a/src/Symfony/Component/Messenger/Tests/MessageBusTest.php b/src/Symfony/Component/Messenger/Tests/MessageBusTest.php index c89eab3586300..59480711ef97a 100644 --- a/src/Symfony/Component/Messenger/Tests/MessageBusTest.php +++ b/src/Symfony/Component/Messenger/Tests/MessageBusTest.php @@ -48,8 +48,8 @@ public function testItCallsMiddleware() $firstMiddleware->expects($this->once()) ->method('handle') ->with($envelope, $this->anything()) - ->will($this->returnCallback(function ($envelope, $next) { - $next($envelope); + ->will($this->returnCallback(function ($envelope, $stack) { + $stack->next()->handle($envelope, $stack); })); $secondMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock(); @@ -76,16 +76,16 @@ public function testThatAMiddlewareCanAddSomeStampsToTheEnvelope() $firstMiddleware->expects($this->once()) ->method('handle') ->with($envelope, $this->anything()) - ->will($this->returnCallback(function ($envelope, $next) { - $next($envelope->with(new AnEnvelopeStamp())); + ->will($this->returnCallback(function ($envelope, $stack) { + $stack->next()->handle($envelope->with(new AnEnvelopeStamp()), $stack); })); $secondMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock(); $secondMiddleware->expects($this->once()) ->method('handle') ->with($envelopeWithAnotherStamp, $this->anything()) - ->will($this->returnCallback(function ($envelope, $next) { - $next($envelope); + ->will($this->returnCallback(function ($envelope, $stack) { + $stack->next()->handle($envelope, $stack); })); $thirdMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock(); @@ -115,8 +115,8 @@ public function testThatAMiddlewareCanUpdateTheMessageWhileKeepingTheEnvelopeSta $firstMiddleware->expects($this->once()) ->method('handle') ->with($envelope, $this->anything()) - ->will($this->returnCallback(function ($message, $next) use ($expectedEnvelope) { - $next($expectedEnvelope); + ->will($this->returnCallback(function ($envelope, $stack) use ($expectedEnvelope) { + $stack->next()->handle($expectedEnvelope, $stack); })); $secondMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock(); diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/ActivationMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/ActivationMiddlewareTest.php index 8fc98c015286a..c020a05548f48 100644 --- a/src/Symfony/Component/Messenger/Tests/Middleware/ActivationMiddlewareTest.php +++ b/src/Symfony/Component/Messenger/Tests/Middleware/ActivationMiddlewareTest.php @@ -11,31 +11,31 @@ namespace Symfony\Component\Messenger\Tests\Middleware; -use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Middleware\ActivationMiddleware; use Symfony\Component\Messenger\Middleware\MiddlewareInterface; +use Symfony\Component\Messenger\Middleware\StackInterface; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; /** * @author Maxime Steinhausser */ -class ActivationMiddlewareTest extends TestCase +class ActivationMiddlewareTest extends MiddlewareTestCase { public function testExecuteMiddlewareOnActivated() { $message = new DummyMessage('Hello'); $envelope = new Envelope($message); - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); - $next->expects($this->never())->method('__invoke'); + $stack = $this->createMock(StackInterface::class); + $stack->expects($this->never())->method('next'); $middleware = $this->createMock(MiddlewareInterface::class); - $middleware->expects($this->once())->method('handle')->with($envelope, $next); + $middleware->expects($this->once())->method('handle')->with($envelope, $stack); $decorator = new ActivationMiddleware($middleware, true); - $decorator->handle($envelope, $next); + $decorator->handle($envelope, $stack); } public function testExecuteMiddlewareOnActivatedWithCallable() @@ -46,15 +46,15 @@ public function testExecuteMiddlewareOnActivatedWithCallable() $activated = $this->createPartialMock(\stdClass::class, array('__invoke')); $activated->expects($this->once())->method('__invoke')->with($envelope)->willReturn(true); - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); - $next->expects($this->never())->method('__invoke'); + $stack = $this->createMock(StackInterface::class); + $stack->expects($this->never())->method('next'); $middleware = $this->createMock(MiddlewareInterface::class); - $middleware->expects($this->once())->method('handle')->with($envelope, $next); + $middleware->expects($this->once())->method('handle')->with($envelope, $stack); $decorator = new ActivationMiddleware($middleware, $activated); - $decorator->handle($envelope, $next); + $decorator->handle($envelope, $stack); } public function testExecuteMiddlewareOnDeactivated() @@ -62,14 +62,11 @@ public function testExecuteMiddlewareOnDeactivated() $message = new DummyMessage('Hello'); $envelope = new Envelope($message); - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); - $next->expects($this->once())->method('__invoke')->with($envelope); - $middleware = $this->createMock(MiddlewareInterface::class); $middleware->expects($this->never())->method('handle'); $decorator = new ActivationMiddleware($middleware, false); - $decorator->handle($envelope, $next); + $decorator->handle($envelope, $this->getStackMock()); } } diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/HandleMessageMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/HandleMessageMiddlewareTest.php index 59d827b041cdb..f038784b08a60 100644 --- a/src/Symfony/Component/Messenger/Tests/Middleware/HandleMessageMiddlewareTest.php +++ b/src/Symfony/Component/Messenger/Tests/Middleware/HandleMessageMiddlewareTest.php @@ -11,13 +11,13 @@ namespace Symfony\Component\Messenger\Tests\Middleware; -use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Handler\Locator\HandlerLocator; use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware; +use Symfony\Component\Messenger\Middleware\StackMiddleware; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; -class HandleMessageMiddlewareTest extends TestCase +class HandleMessageMiddlewareTest extends MiddlewareTestCase { public function testItCallsTheHandlerAndNextMiddleware() { @@ -26,16 +26,13 @@ public function testItCallsTheHandlerAndNextMiddleware() $handler = $this->createPartialMock(\stdClass::class, array('__invoke')); - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); - $middleware = new HandleMessageMiddleware(new HandlerLocator(array( DummyMessage::class => $handler, ))); $handler->expects($this->once())->method('__invoke')->with($message); - $next->expects($this->once())->method('__invoke')->with($envelope); - $middleware->handle($envelope, $next); + $middleware->handle($envelope, $this->getStackMock()); } /** @@ -46,13 +43,13 @@ public function testThrowsNoHandlerException() { $middleware = new HandleMessageMiddleware(new HandlerLocator(array())); - $middleware->handle(new Envelope(new DummyMessage('Hey')), function () {}); + $middleware->handle(new Envelope(new DummyMessage('Hey')), new StackMiddleware()); } public function testAllowNoHandlers() { $middleware = new HandleMessageMiddleware(new HandlerLocator(array()), true); - $this->assertNull($middleware->handle(new Envelope(new DummyMessage('Hey')), function () {})); + $this->assertNull($middleware->handle(new Envelope(new DummyMessage('Hey')), new StackMiddleware())); } } diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/LoggingMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/LoggingMiddlewareTest.php index 5c3439e747891..452854e13f7d9 100644 --- a/src/Symfony/Component/Messenger/Tests/Middleware/LoggingMiddlewareTest.php +++ b/src/Symfony/Component/Messenger/Tests/Middleware/LoggingMiddlewareTest.php @@ -11,13 +11,13 @@ namespace Symfony\Component\Messenger\Tests\Middleware; -use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Middleware\LoggingMiddleware; +use Symfony\Component\Messenger\Middleware\StackInterface; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; -class LoggingMiddlewareTest extends TestCase +class LoggingMiddlewareTest extends MiddlewareTestCase { public function testDebugLogAndNextMiddleware() { @@ -29,14 +29,8 @@ public function testDebugLogAndNextMiddleware() ->expects($this->exactly(2)) ->method('debug') ; - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); - $next - ->expects($this->once()) - ->method('__invoke') - ->with($envelope) - ; - (new LoggingMiddleware($logger))->handle($envelope, $next); + (new LoggingMiddleware($logger))->handle($envelope, $this->getStackMock()); } /** @@ -56,14 +50,13 @@ public function testWarningLogOnException() ->expects($this->once()) ->method('warning') ; - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); - $next + $stack = $this->createMock(StackInterface::class); + $stack ->expects($this->once()) - ->method('__invoke') - ->with($envelope) + ->method('next') ->willThrowException(new \Exception()) ; - (new LoggingMiddleware($logger))->handle($envelope, $next); + (new LoggingMiddleware($logger))->handle($envelope, $stack); } } diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/MiddlewareTestCase.php b/src/Symfony/Component/Messenger/Tests/Middleware/MiddlewareTestCase.php new file mode 100644 index 0000000000000..f6934adb6a91b --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Middleware/MiddlewareTestCase.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Middleware; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Middleware\MiddlewareInterface; +use Symfony\Component\Messenger\Middleware\StackInterface; + +abstract class MiddlewareTestCase extends TestCase +{ + protected function getStackMock(bool $nextIsCalled = true) + { + $nextMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock(); + $nextMiddleware + ->expects($nextIsCalled ? $this->once() : $this->never()) + ->method('handle') + ; + + $stack = $this->createMock(StackInterface::class); + $stack + ->expects($nextIsCalled ? $this->once() : $this->never()) + ->method('next') + ->willReturn($nextMiddleware) + ; + + return $stack; + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php index 9553d4735e479..2c13d32feca03 100644 --- a/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php +++ b/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php @@ -11,8 +11,8 @@ namespace Symfony\Component\Messenger\Tests\Middleware; -use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Middleware\MiddlewareInterface; use Symfony\Component\Messenger\Middleware\SendMessageMiddleware; use Symfony\Component\Messenger\Stamp\ReceivedStamp; use Symfony\Component\Messenger\Tests\Fixtures\ChildDummyMessage; @@ -21,35 +21,31 @@ use Symfony\Component\Messenger\Transport\Sender\Locator\SenderLocatorInterface; use Symfony\Component\Messenger\Transport\Sender\SenderInterface; -class SendMessageMiddlewareTest extends TestCase +class SendMessageMiddlewareTest extends MiddlewareTestCase { public function testItSendsTheMessageToAssignedSender() { $message = new DummyMessage('Hey'); $envelope = new Envelope($message); $sender = $this->getMockBuilder(SenderInterface::class)->getMock(); - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); $middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender)); $sender->expects($this->once())->method('send')->with($envelope); - $next->expects($this->never())->method($this->anything()); - $middleware->handle($envelope, $next); + $middleware->handle($envelope, $this->getStackMock(false)); } public function testItSendsTheMessageToAssignedSenderWithPreWrappedMessage() { $envelope = new Envelope(new DummyMessage('Hey')); $sender = $this->getMockBuilder(SenderInterface::class)->getMock(); - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); $middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender)); $sender->expects($this->once())->method('send')->with($envelope); - $next->expects($this->never())->method($this->anything()); - $middleware->handle($envelope, $next); + $middleware->handle($envelope, $this->getStackMock(false)); } public function testItAlsoCallsTheNextMiddlewareBasedOnTheMessageClass() @@ -57,16 +53,14 @@ public function testItAlsoCallsTheNextMiddlewareBasedOnTheMessageClass() $message = new DummyMessage('Hey'); $envelope = new Envelope($message); $sender = $this->getMockBuilder(SenderInterface::class)->getMock(); - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); $middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender), array( DummyMessage::class => true, )); $sender->expects($this->once())->method('send')->with($envelope); - $next->expects($this->once())->method($this->anything()); - $middleware->handle($envelope, $next); + $middleware->handle($envelope, $this->getStackMock()); } public function testItAlsoCallsTheNextMiddlewareBasedOnTheMessageParentClass() @@ -74,16 +68,14 @@ public function testItAlsoCallsTheNextMiddlewareBasedOnTheMessageParentClass() $message = new ChildDummyMessage('Hey'); $envelope = new Envelope($message); $sender = $this->getMockBuilder(SenderInterface::class)->getMock(); - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); $middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender), array( DummyMessage::class => true, )); $sender->expects($this->once())->method('send')->with($envelope); - $next->expects($this->once())->method($this->anything()); - $middleware->handle($envelope, $next); + $middleware->handle($envelope, $this->getStackMock()); } public function testItAlsoCallsTheNextMiddlewareBasedOnTheMessageInterface() @@ -91,16 +83,14 @@ public function testItAlsoCallsTheNextMiddlewareBasedOnTheMessageInterface() $message = new DummyMessage('Hey'); $envelope = new Envelope($message); $sender = $this->getMockBuilder(SenderInterface::class)->getMock(); - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); $middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender), array( DummyMessageInterface::class => true, )); $sender->expects($this->once())->method('send')->with($envelope); - $next->expects($this->once())->method($this->anything()); - $middleware->handle($envelope, $next); + $middleware->handle($envelope, $this->getStackMock()); } public function testItAlsoCallsTheNextMiddlewareBasedOnWildcard() @@ -108,29 +98,25 @@ public function testItAlsoCallsTheNextMiddlewareBasedOnWildcard() $message = new DummyMessage('Hey'); $envelope = new Envelope($message); $sender = $this->getMockBuilder(SenderInterface::class)->getMock(); - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); $middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender), array( '*' => true, )); $sender->expects($this->once())->method('send')->with($envelope); - $next->expects($this->once())->method($this->anything()); - $middleware->handle($envelope, $next); + $middleware->handle($envelope, $this->getStackMock()); } public function testItCallsTheNextMiddlewareWhenNoSenderForThisMessage() { $message = new DummyMessage('Hey'); $envelope = new Envelope($message); - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); $middleware = new SendMessageMiddleware(new InMemorySenderLocator(null)); + $handler = $this->getMockBuilder(MiddlewareInterface::class)->getMock(); - $next->expects($this->once())->method($this->anything()); - - $middleware->handle($envelope, $next); + $middleware->handle($envelope, $this->getStackMock()); } public function testItSkipsReceivedMessages() @@ -138,14 +124,12 @@ public function testItSkipsReceivedMessages() $envelope = (new Envelope(new DummyMessage('Hey')))->with(new ReceivedStamp()); $sender = $this->getMockBuilder(SenderInterface::class)->getMock(); - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); $middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender)); $sender->expects($this->never())->method('send'); - $next->expects($this->once())->method('__invoke')->with($envelope); - $middleware->handle($envelope, $next); + $middleware->handle($envelope, $this->getStackMock()); } } diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/TraceableMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/TraceableMiddlewareTest.php index 513cc538e8f66..12b5ade2222c0 100644 --- a/src/Symfony/Component/Messenger/Tests/Middleware/TraceableMiddlewareTest.php +++ b/src/Symfony/Component/Messenger/Tests/Middleware/TraceableMiddlewareTest.php @@ -11,9 +11,9 @@ namespace Symfony\Component\Messenger\Tests\Middleware; -use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Middleware\MiddlewareInterface; +use Symfony\Component\Messenger\Middleware\StackInterface; use Symfony\Component\Messenger\Middleware\TraceableMiddleware; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; use Symfony\Component\Stopwatch\Stopwatch; @@ -21,7 +21,7 @@ /** * @author Maxime Steinhausser */ -class TraceableMiddlewareTest extends TestCase +class TraceableMiddlewareTest extends MiddlewareTestCase { public function testHandle() { @@ -32,18 +32,11 @@ public function testHandle() $middleware->expects($this->once()) ->method('handle') ->with($envelope, $this->anything()) - ->will($this->returnCallback(function ($envelope, callable $next) { - $next($envelope); + ->will($this->returnCallback(function ($envelope, StackInterface $stack) { + $stack->next()->handle($envelope, $stack); })) ; - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); - $next - ->expects($this->once()) - ->method('__invoke') - ->with($envelope) - ; - $stopwatch = $this->createMock(Stopwatch::class); $stopwatch->expects($this->once())->method('isStarted')->willReturn(true); $stopwatch->expects($this->exactly(2)) @@ -57,7 +50,7 @@ public function testHandle() $traced = new TraceableMiddleware($middleware, $stopwatch, $busId); - $traced->handle($envelope, $next); + $traced->handle($envelope, $this->getStackMock()); } /** @@ -73,15 +66,15 @@ public function testHandleWithException() $middleware->expects($this->once()) ->method('handle') ->with($envelope, $this->anything()) - ->will($this->returnCallback(function ($envelope, callable $next) { - $next($envelope); + ->will($this->returnCallback(function ($envelope, StackInterface $stack) { + $stack->next()->handle($envelope, $stack); })) ; - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); - $next + $stack = $this->createMock(StackInterface::class); + $stack ->expects($this->once()) - ->method('__invoke') + ->method('next') ->willThrowException(new \RuntimeException('Foo exception from next callable')) ; @@ -98,6 +91,6 @@ public function testHandleWithException() ; $traced = new TraceableMiddleware($middleware, $stopwatch, $busId); - $traced->handle($envelope, $next); + $traced->handle($envelope, $stack); } } diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/ValidationMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/ValidationMiddlewareTest.php index e3d73986a3a47..9d77778f3b97b 100644 --- a/src/Symfony/Component/Messenger/Tests/Middleware/ValidationMiddlewareTest.php +++ b/src/Symfony/Component/Messenger/Tests/Middleware/ValidationMiddlewareTest.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Messenger\Tests\Middleware; -use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Middleware\ValidationMiddleware; use Symfony\Component\Messenger\Stamp\ValidationStamp; @@ -19,7 +18,7 @@ use Symfony\Component\Validator\ConstraintViolationListInterface; use Symfony\Component\Validator\Validator\ValidatorInterface; -class ValidationMiddlewareTest extends TestCase +class ValidationMiddlewareTest extends MiddlewareTestCase { public function testValidateAndNextMiddleware() { @@ -33,14 +32,8 @@ public function testValidateAndNextMiddleware() ->with($message) ->willReturn($this->createMock(ConstraintViolationListInterface::class)) ; - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); - $next - ->expects($this->once()) - ->method('__invoke') - ->with($envelope) - ; - (new ValidationMiddleware($validator))->handle($envelope, $next); + (new ValidationMiddleware($validator))->handle($envelope, $this->getStackMock()); } public function testValidateWithStampAndNextMiddleware() @@ -54,14 +47,8 @@ public function testValidateWithStampAndNextMiddleware() ->with($message, null, $groups) ->willReturn($this->createMock(ConstraintViolationListInterface::class)) ; - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); - $next - ->expects($this->once()) - ->method('__invoke') - ->with($envelope) - ; - (new ValidationMiddleware($validator))->handle($envelope, $next); + (new ValidationMiddleware($validator))->handle($envelope, $this->getStackMock()); } /** @@ -86,12 +73,7 @@ public function testValidationFailedException() ->with($message) ->willReturn($violationList) ; - $next = $this->createPartialMock(\stdClass::class, array('__invoke')); - $next - ->expects($this->never()) - ->method('__invoke') - ; - (new ValidationMiddleware($validator))->handle($envelope, $next); + (new ValidationMiddleware($validator))->handle($envelope, $this->getStackMock(false)); } }