From 0b1fbb16f7b4e7f77c919cdfa9797422bbca0713 Mon Sep 17 00:00:00 2001 From: Nicolo Singer Date: Wed, 15 Jul 2026 13:07:38 +0200 Subject: [PATCH 1/2] Fix wrapped exception access when keys are not sequential getWrappedExceptions() may return a non-sequentially keyed array, so accessing [0] could miss the exception; normalize with array_values() first. Signed-off-by: Nicolo Singer --- src/CommandBus/SymfonyCommandBus.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/CommandBus/SymfonyCommandBus.php b/src/CommandBus/SymfonyCommandBus.php index 958d0f7c..47cc2fe8 100644 --- a/src/CommandBus/SymfonyCommandBus.php +++ b/src/CommandBus/SymfonyCommandBus.php @@ -8,6 +8,8 @@ use Symfony\Component\Messenger\Exception\HandlerFailedException; use Symfony\Component\Messenger\MessageBusInterface; +use function array_values; + final class SymfonyCommandBus implements CommandBus { public function __construct( @@ -20,7 +22,7 @@ public function dispatch(object $command): void try { $this->messageBus->dispatch($command); } catch (HandlerFailedException $e) { - throw $e->getWrappedExceptions(null, true)[0] ?? $e; + throw array_values($e->getWrappedExceptions(null, true))[0] ?? $e; } } } From 831504917b77e7f1475f484fcebe04ad47d33350 Mon Sep 17 00:00:00 2001 From: Daniel Badura Date: Wed, 15 Jul 2026 20:38:00 +0200 Subject: [PATCH 2/2] Adjust test case --- .../Unit/CommandBus/SymfonyCommandBusTest.php | 125 ++++++++++++++++++ .../CommandBus/SymfonyCommandtBusTest.php | 84 ------------ 2 files changed, 125 insertions(+), 84 deletions(-) create mode 100644 tests/Unit/CommandBus/SymfonyCommandBusTest.php delete mode 100644 tests/Unit/CommandBus/SymfonyCommandtBusTest.php diff --git a/tests/Unit/CommandBus/SymfonyCommandBusTest.php b/tests/Unit/CommandBus/SymfonyCommandBusTest.php new file mode 100644 index 00000000..f93b8b0f --- /dev/null +++ b/tests/Unit/CommandBus/SymfonyCommandBusTest.php @@ -0,0 +1,125 @@ +command = $envelope->getMessage(); + + return $envelope; + } + }; + $messageBus = new MessageBus([$middleware]); + + $commandBus = new SymfonyCommandBus($messageBus); + $commandBus->dispatch($command); + + self::assertNotNull($middleware->command); + self::assertSame($command, $middleware->command); + } + + public function testException(): void + { + $command = new CreateProfile(CustomId::fromString('1')); + + $middleware = new class implements MiddlewareInterface + { + public object|null $command = null; + + public function handle(Envelope $envelope, StackInterface $stack): Envelope + { + $this->command = $envelope->getMessage(); + + throw new RuntimeException('test'); + } + }; + $messageBus = new MessageBus([$middleware]); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessageMatches('/^test$/'); + + $commandBus = new SymfonyCommandBus($messageBus); + $commandBus->dispatch($command); + + self::assertNotNull($middleware->command); + self::assertSame($command, $middleware->command); + } + + public function testRecursiveException(): void + { + $command = new CreateProfile(CustomId::fromString('1')); + + $middleware = new class implements MiddlewareInterface + { + public object|null $command = null; + + public function handle(Envelope $envelope, StackInterface $stack): Envelope + { + $this->command = $envelope->getMessage(); + + throw new HandlerFailedException($envelope, [new RuntimeException('test')]); + } + }; + $messageBus = new MessageBus([$middleware]); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessageMatches('/^test$/'); + + $commandBus = new SymfonyCommandBus($messageBus); + $commandBus->dispatch($command); + + self::assertNotNull($middleware->command); + self::assertSame($command, $middleware->command); + } + + public function testRecursiveExceptionStringKey(): void + { + $command = new CreateProfile(CustomId::fromString('1')); + + $middleware = new class implements MiddlewareInterface + { + public object|null $command = null; + + public function handle(Envelope $envelope, StackInterface $stack): Envelope + { + $this->command = $envelope->getMessage(); + + throw new HandlerFailedException($envelope, ['controller-class' => new RuntimeException('test')]); + } + }; + $messageBus = new MessageBus([$middleware]); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessageMatches('/^test$/'); + + $commandBus = new SymfonyCommandBus($messageBus); + $commandBus->dispatch($command); + + self::assertNotNull($middleware->command); + self::assertSame($command, $middleware->command); + } +} diff --git a/tests/Unit/CommandBus/SymfonyCommandtBusTest.php b/tests/Unit/CommandBus/SymfonyCommandtBusTest.php deleted file mode 100644 index af671703..00000000 --- a/tests/Unit/CommandBus/SymfonyCommandtBusTest.php +++ /dev/null @@ -1,84 +0,0 @@ -createMock(MessageBusInterface::class); - $messageBus - ->expects($this->once()) - ->method('dispatch') - ->with($command) - ->willReturn($envelope); - - $commandBus = new SymfonyCommandBus($messageBus); - $commandBus->dispatch($command); - } - - public function testException(): void - { - $command = new CreateProfile( - CustomId::fromString('1'), - ); - $internalException = new class extends RuntimeException { - }; - $envelope = new Envelope($command); - - $messageBus = $this->createMock(MessageBusInterface::class); - $messageBus - ->expects($this->once()) - ->method('dispatch') - ->with($command) - ->willThrowException(new HandlerFailedException($envelope, [$internalException])); - - $commandBus = new SymfonyCommandBus($messageBus); - - $this->expectException($internalException::class); - - $commandBus->dispatch($command); - } - - public function testRecursiveException(): void - { - $command = new CreateProfile( - CustomId::fromString('1'), - ); - $internalException = new class extends RuntimeException { - }; - $envelope = new Envelope($command); - - $messageBus = $this->createMock(MessageBusInterface::class); - $messageBus - ->expects($this->once()) - ->method('dispatch') - ->with($command) - ->willThrowException(new HandlerFailedException( - $envelope, - [new HandlerFailedException($envelope, [$internalException])], - )); - - $commandBus = new SymfonyCommandBus($messageBus); - $this->expectException($internalException::class); - - $commandBus->dispatch($command); - } -}