diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 73bea791a960f..8b061c1fbcc8c 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -128,8 +128,8 @@ public function run(InputInterface $input = null, OutputInterface $output = null $exception = new FatalThrowableError($e); } - if (null !== $this->runningCommand && null !== $e && null !== $this->dispatcher) { - $event = new ConsoleErrorEvent($this->runningCommand, $input, $output, $e, $e->getCode()); + if (null !== $e && null !== $this->dispatcher) { + $event = new ConsoleErrorEvent($input, $output, $e, $e->getCode(), $this->runningCommand); $this->dispatcher->dispatch(ConsoleEvents::ERROR, $event); $e = $event->getError(); diff --git a/src/Symfony/Component/Console/CHANGELOG.md b/src/Symfony/Component/Console/CHANGELOG.md index d1695aa00e779..f8539491d264b 100644 --- a/src/Symfony/Component/Console/CHANGELOG.md +++ b/src/Symfony/Component/Console/CHANGELOG.md @@ -10,6 +10,8 @@ CHANGELOG with value optional explicitly passed empty * added console.error event to catch exceptions thrown by other listeners * deprecated console.exception event in favor of console.error +* added ability to handle `CommandNotFoundException` through the + `console.error` event 3.2.0 ------ diff --git a/src/Symfony/Component/Console/Event/ConsoleErrorEvent.php b/src/Symfony/Component/Console/Event/ConsoleErrorEvent.php index d48c577d4e738..1e5bffae7a380 100644 --- a/src/Symfony/Component/Console/Event/ConsoleErrorEvent.php +++ b/src/Symfony/Component/Console/Event/ConsoleErrorEvent.php @@ -27,7 +27,7 @@ class ConsoleErrorEvent extends ConsoleExceptionEvent private $error; private $handled = false; - public function __construct(Command $command, InputInterface $input, OutputInterface $output, $error, $exitCode) + public function __construct(InputInterface $input, OutputInterface $output, $error, $exitCode, Command $command = null) { if (!$error instanceof \Throwable && !$error instanceof \Exception) { throw new InvalidArgumentException(sprintf('The error passed to ConsoleErrorEvent must be an instance of \Throwable or \Exception, "%s" was passed instead.', is_object($error) ? get_class($error) : gettype($error))); diff --git a/src/Symfony/Component/Console/Event/ConsoleExceptionEvent.php b/src/Symfony/Component/Console/Event/ConsoleExceptionEvent.php index 7430f840b5e57..09571cd318dc2 100644 --- a/src/Symfony/Component/Console/Event/ConsoleExceptionEvent.php +++ b/src/Symfony/Component/Console/Event/ConsoleExceptionEvent.php @@ -27,7 +27,7 @@ class ConsoleExceptionEvent extends ConsoleEvent private $exception; private $exitCode; - public function __construct(Command $command, InputInterface $input, OutputInterface $output, \Exception $exception, $exitCode, $deprecation = true) + public function __construct(Command $command = null, InputInterface $input, OutputInterface $output, \Exception $exception, $exitCode, $deprecation = true) { if ($deprecation) { @trigger_error(sprintf('The %s class is deprecated since version 3.3 and will be removed in 4.0. Use the ConsoleErrorEvent instead.', __CLASS__), E_USER_DEPRECATED); diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index fa583d99af88b..fb633cf3b11d6 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -1051,6 +1051,26 @@ public function testRunAllowsErrorListenersToSilenceTheException() $this->assertEquals(0, $tester->getStatusCode()); } + public function testConsoleErrorEventIsTriggeredOnCommandNotFound() + { + $dispatcher = new EventDispatcher(); + $dispatcher->addListener('console.error', function (ConsoleErrorEvent $event) { + $this->assertNull($event->getCommand()); + $this->assertInstanceOf(CommandNotFoundException::class, $event->getError()); + $event->getOutput()->write('silenced command not found'); + $event->markErrorAsHandled(); + }); + + $application = new Application(); + $application->setDispatcher($dispatcher); + $application->setAutoExit(false); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'unknown')); + $this->assertContains('silenced command not found', $tester->getDisplay()); + $this->assertEquals(0, $tester->getStatusCode()); + } + /** * @group legacy * @expectedDeprecation The "console.exception" event is deprecated since version 3.3 and will be removed in 4.0. Use the "console.error" event instead. diff --git a/src/Symfony/Component/Console/Tests/EventListener/ExceptionListenerTest.php b/src/Symfony/Component/Console/Tests/EventListener/ExceptionListenerTest.php index cbd44e50537a8..a57235a867f5f 100644 --- a/src/Symfony/Component/Console/Tests/EventListener/ExceptionListenerTest.php +++ b/src/Symfony/Component/Console/Tests/EventListener/ExceptionListenerTest.php @@ -111,7 +111,7 @@ private function getLogger() private function getConsoleErrorEvent(\Exception $exception, InputInterface $input, $exitCode) { - return new ConsoleErrorEvent(new Command('test:run'), $input, $this->getOutput(), $exception, $exitCode); + return new ConsoleErrorEvent($input, $this->getOutput(), $exception, $exitCode, new Command('test:run')); } private function getConsoleTerminateEvent(InputInterface $input, $exitCode)