bug #22322 [Console] Fix fatal error when logging console.error without command (chalasr)
This PR was merged into the 3.3-dev branch.
Discussion
----------
[Console] Fix fatal error when logging console.error without command
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | yes
| New feature? | no
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #22449
| License | MIT
| Doc PR | n/a
Happens now that the console.error event is dispatched on command not found, I ran into using `server:run` on 3.3 without `web-server-bundle` enabled:
> PHP Fatal error: Uncaught Symfony\Component\Debug\Exception\FatalThrowableError: Call to a member function getName() on null
In this case, this first tries to cast the event input as string (less good than when the command name is available, there're extra quotes around the command name) and, if can't be casted, uses a generic message.
Commits
-------
97129fc611
Fix fatal error when logging console.error without a command
This commit is contained in:
commit
9c0067b19f
@ -39,7 +39,11 @@ class ExceptionListener implements EventSubscriberInterface
|
|||||||
|
|
||||||
$error = $event->getError();
|
$error = $event->getError();
|
||||||
|
|
||||||
$this->logger->error('Error thrown while running command "{command}". Message: "{message}"', array('error' => $error, 'command' => $this->getInputString($event), 'message' => $error->getMessage()));
|
if (!$inputString = $this->getInputString($event)) {
|
||||||
|
return $this->logger->error('An error occurred while using the console. Message: "{message}"', array('error' => $error, 'message' => $error->getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logger->error('Error thrown while running command "{command}". Message: "{message}"', array('error' => $error, 'command' => $inputString, 'message' => $error->getMessage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onConsoleTerminate(ConsoleTerminateEvent $event)
|
public function onConsoleTerminate(ConsoleTerminateEvent $event)
|
||||||
@ -54,7 +58,11 @@ class ExceptionListener implements EventSubscriberInterface
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger->error('Command "{command}" exited with code "{code}"', array('command' => $this->getInputString($event), 'code' => $exitCode));
|
if (!$inputString = $this->getInputString($event)) {
|
||||||
|
return $this->logger->error('The console exited with code "{code}"', array('code' => $exitCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logger->error('Command "{command}" exited with code "{code}"', array('command' => $inputString, 'code' => $exitCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getSubscribedEvents()
|
public static function getSubscribedEvents()
|
||||||
@ -67,11 +75,15 @@ class ExceptionListener implements EventSubscriberInterface
|
|||||||
|
|
||||||
private static function getInputString(ConsoleEvent $event)
|
private static function getInputString(ConsoleEvent $event)
|
||||||
{
|
{
|
||||||
$commandName = $event->getCommand()->getName();
|
$commandName = $event->getCommand() ? $event->getCommand()->getName() : null;
|
||||||
$input = $event->getInput();
|
$input = $event->getInput();
|
||||||
|
|
||||||
if (method_exists($input, '__toString')) {
|
if (method_exists($input, '__toString')) {
|
||||||
return str_replace(array("'$commandName'", "\"$commandName\""), $commandName, (string) $input);
|
if ($commandName) {
|
||||||
|
return str_replace(array("'$commandName'", "\"$commandName\""), $commandName, (string) $input);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string) $input;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $commandName;
|
return $commandName;
|
||||||
|
@ -19,6 +19,7 @@ use Symfony\Component\Console\Event\ConsoleTerminateEvent;
|
|||||||
use Symfony\Component\Console\EventListener\ExceptionListener;
|
use Symfony\Component\Console\EventListener\ExceptionListener;
|
||||||
use Symfony\Component\Console\Input\ArgvInput;
|
use Symfony\Component\Console\Input\ArgvInput;
|
||||||
use Symfony\Component\Console\Input\ArrayInput;
|
use Symfony\Component\Console\Input\ArrayInput;
|
||||||
|
use Symfony\Component\Console\Input\Input;
|
||||||
use Symfony\Component\Console\Input\StringInput;
|
use Symfony\Component\Console\Input\StringInput;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
@ -37,7 +38,22 @@ class ExceptionListenerTest extends TestCase
|
|||||||
;
|
;
|
||||||
|
|
||||||
$listener = new ExceptionListener($logger);
|
$listener = new ExceptionListener($logger);
|
||||||
$listener->onConsoleError($this->getConsoleErrorEvent($exception, new ArgvInput(array('console.php', 'test:run', '--foo=baz', 'buzz')), 1));
|
$listener->onConsoleError($this->getConsoleErrorEvent($exception, new ArgvInput(array('console.php', 'test:run', '--foo=baz', 'buzz')), 1, new Command('test:run')));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOnConsoleErrorWithNoCommandAndNoInputString()
|
||||||
|
{
|
||||||
|
$exception = new \RuntimeException('An error occurred');
|
||||||
|
|
||||||
|
$logger = $this->getLogger();
|
||||||
|
$logger
|
||||||
|
->expects($this->once())
|
||||||
|
->method('error')
|
||||||
|
->with('An error occurred while using the console. Message: "{message}"', array('error' => $exception, 'message' => 'An error occurred'))
|
||||||
|
;
|
||||||
|
|
||||||
|
$listener = new ExceptionListener($logger);
|
||||||
|
$listener->onConsoleError($this->getConsoleErrorEvent($exception, new NonStringInput(), 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testOnConsoleTerminateForNonZeroExitCodeWritesToLog()
|
public function testOnConsoleTerminateForNonZeroExitCodeWritesToLog()
|
||||||
@ -109,9 +125,9 @@ class ExceptionListenerTest extends TestCase
|
|||||||
return $this->getMockForAbstractClass(LoggerInterface::class);
|
return $this->getMockForAbstractClass(LoggerInterface::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getConsoleErrorEvent(\Exception $exception, InputInterface $input, $exitCode)
|
private function getConsoleErrorEvent(\Exception $exception, InputInterface $input, $exitCode, Command $command = null)
|
||||||
{
|
{
|
||||||
return new ConsoleErrorEvent($input, $this->getOutput(), $exception, $exitCode, new Command('test:run'));
|
return new ConsoleErrorEvent($input, $this->getOutput(), $exception, $exitCode, $command);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getConsoleTerminateEvent(InputInterface $input, $exitCode)
|
private function getConsoleTerminateEvent(InputInterface $input, $exitCode)
|
||||||
@ -124,3 +140,22 @@ class ExceptionListenerTest extends TestCase
|
|||||||
return $this->getMockBuilder(OutputInterface::class)->getMock();
|
return $this->getMockBuilder(OutputInterface::class)->getMock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class NonStringInput extends Input
|
||||||
|
{
|
||||||
|
public function getFirstArgument()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasParameterOption($values, $onlyParams = false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getParameterOption($values, $default = false, $onlyParams = false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parse()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user