diff --git a/src/Symfony/Component/Messenger/Command/AbstractFailedMessagesCommand.php b/src/Symfony/Component/Messenger/Command/AbstractFailedMessagesCommand.php index 1c480ecdf1..77a6700500 100644 --- a/src/Symfony/Component/Messenger/Command/AbstractFailedMessagesCommand.php +++ b/src/Symfony/Component/Messenger/Command/AbstractFailedMessagesCommand.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Messenger\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\Dumper; use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Stamp\ErrorDetailsStamp; use Symfony\Component\Messenger\Stamp\RedeliveryStamp; @@ -21,6 +22,11 @@ use Symfony\Component\Messenger\Stamp\SentToFailureTransportStamp; use Symfony\Component\Messenger\Stamp\TransportMessageIdStamp; use Symfony\Component\Messenger\Transport\Receiver\MessageCountAwareInterface; use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; +use Symfony\Component\VarDumper\Caster\Caster; +use Symfony\Component\VarDumper\Caster\TraceStub; +use Symfony\Component\VarDumper\Cloner\ClonerInterface; +use Symfony\Component\VarDumper\Cloner\Stub; +use Symfony\Component\VarDumper\Cloner\VarCloner; /** * @author Ryan Weaver @@ -121,7 +127,7 @@ abstract class AbstractFailedMessagesCommand extends Command if ($io->isVeryVerbose()) { $io->title('Message:'); - $dump = new Dumper($io); + $dump = new Dumper($io, null, $this->createCloner()); $io->writeln($dump($envelope->getMessage())); $io->title('Exception:'); $flattenException = null; @@ -130,7 +136,7 @@ abstract class AbstractFailedMessagesCommand extends Command } elseif (null !== $lastRedeliveryStampWithException) { $flattenException = $lastRedeliveryStampWithException->getFlattenException(); } - $io->writeln(null === $flattenException ? '(no data)' : $flattenException->getTraceAsString()); + $io->writeln(null === $flattenException ? '(no data)' : $dump($flattenException)); } else { $io->writeln(' Re-run command with -vv to see more message & error details.'); } @@ -172,4 +178,26 @@ abstract class AbstractFailedMessagesCommand extends Command return null; } + + private function createCloner(): ?ClonerInterface + { + if (!class_exists(VarCloner::class)) { + return null; + } + + $cloner = new VarCloner(); + $cloner->addCasters([FlattenException::class => function (FlattenException $flattenException, array $a, Stub $stub): array { + $stub->class = $flattenException->getClass(); + + return [ + Caster::PREFIX_VIRTUAL.'message' => $flattenException->getMessage(), + Caster::PREFIX_VIRTUAL.'code' => $flattenException->getCode(), + Caster::PREFIX_VIRTUAL.'file' => $flattenException->getFile(), + Caster::PREFIX_VIRTUAL.'line' => $flattenException->getLine(), + Caster::PREFIX_VIRTUAL.'trace' => new TraceStub($flattenException->getTrace()), + ]; + }]); + + return $cloner; + } } diff --git a/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php b/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php index 884d432abd..0cbae9d551 100644 --- a/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php +++ b/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Messenger\Tests\Command; use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Tester\CommandTester; use Symfony\Component\Messenger\Command\FailedMessagesShowCommand; use Symfony\Component\Messenger\Envelope; @@ -234,4 +235,44 @@ EOF $tester = new CommandTester($command); $tester->execute(['id' => 15]); } + + public function testVeryVerboseOutputForSingleMessageContainsExceptionWithTrace() + { + $exception = new \RuntimeException('Things are bad!'); + $exceptionLine = __LINE__ - 1; + $envelope = new Envelope(new \stdClass(), [ + new TransportMessageIdStamp(15), + new SentToFailureTransportStamp('async'), + new RedeliveryStamp(0), + new ErrorDetailsStamp($exception), + ]); + $receiver = $this->createMock(ListableReceiverInterface::class); + $receiver->expects($this->once())->method('find')->with(42)->willReturn($envelope); + + $command = new FailedMessagesShowCommand('failure_receiver', $receiver); + $tester = new CommandTester($command); + $tester->execute(['id' => 42], ['verbosity' => OutputInterface::VERBOSITY_VERY_VERBOSE]); + $this->assertStringMatchesFormat(sprintf(<<<'EOF' +%%A +Exception: +========== + +RuntimeException { + message: "Things are bad!" + code: 0 + file: "%s" + line: %d + trace: { + %%s%%eTests%%eCommand%%eFailedMessagesShowCommandTest.php:%d { + Symfony\Component\Messenger\Tests\Command\FailedMessagesShowCommandTest->testVeryVerboseOutputForSingleMessageContainsExceptionWithTrace() + › { + › $exception = new \RuntimeException('Things are bad!'); + › $exceptionLine = __LINE__ - 1; + } +%%A +EOF + , + __FILE__, $exceptionLine, $exceptionLine), + $tester->getDisplay(true)); + } }