[Console] Fix dispatching throwables from ConsoleEvents::COMMAND
This commit is contained in:
parent
5742958a49
commit
6d6b04ae97
@ -117,10 +117,17 @@ class Application
|
|||||||
$this->configureIO($input, $output);
|
$this->configureIO($input, $output);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
$e = null;
|
||||||
$exitCode = $this->doRun($input, $output);
|
$exitCode = $this->doRun($input, $output);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $x) {
|
||||||
|
$e = $x;
|
||||||
|
} catch (\Throwable $x) {
|
||||||
|
$e = new FatalThrowableError($x);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $e) {
|
||||||
if (!$this->catchExceptions) {
|
if (!$this->catchExceptions) {
|
||||||
throw $e;
|
throw $x;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($output instanceof ConsoleOutputInterface) {
|
if ($output instanceof ConsoleOutputInterface) {
|
||||||
@ -182,6 +189,7 @@ class Application
|
|||||||
$input = new ArrayInput(array('command' => $this->defaultCommand));
|
$input = new ArrayInput(array('command' => $this->defaultCommand));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->runningCommand = null;
|
||||||
// the command name MUST be the first element of the input
|
// the command name MUST be the first element of the input
|
||||||
$command = $this->find($name);
|
$command = $this->find($name);
|
||||||
|
|
||||||
@ -839,47 +847,41 @@ class Application
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (null === $this->dispatcher) {
|
if (null === $this->dispatcher) {
|
||||||
try {
|
|
||||||
return $command->run($input, $output);
|
return $command->run($input, $output);
|
||||||
} catch (\Exception $e) {
|
|
||||||
throw $e;
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
throw new FatalThrowableError($e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$event = new ConsoleCommandEvent($command, $input, $output);
|
$event = new ConsoleCommandEvent($command, $input, $output);
|
||||||
|
$e = null;
|
||||||
|
|
||||||
|
try {
|
||||||
$this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event);
|
$this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event);
|
||||||
|
|
||||||
if ($event->commandShouldRun()) {
|
if ($event->commandShouldRun()) {
|
||||||
try {
|
|
||||||
$e = null;
|
|
||||||
$exitCode = $command->run($input, $output);
|
$exitCode = $command->run($input, $output);
|
||||||
} catch (\Exception $x) {
|
|
||||||
$e = $x;
|
|
||||||
} catch (\Throwable $x) {
|
|
||||||
$e = new FatalThrowableError($x);
|
|
||||||
}
|
|
||||||
if (null !== $e) {
|
|
||||||
$event = new ConsoleExceptionEvent($command, $input, $output, $e, $e->getCode());
|
|
||||||
$this->dispatcher->dispatch(ConsoleEvents::EXCEPTION, $event);
|
|
||||||
|
|
||||||
if ($e !== $event->getException()) {
|
|
||||||
$x = $e = $event->getException();
|
|
||||||
}
|
|
||||||
|
|
||||||
$event = new ConsoleTerminateEvent($command, $input, $output, $e->getCode());
|
|
||||||
$this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);
|
|
||||||
|
|
||||||
throw $x;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
$exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED;
|
$exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED;
|
||||||
}
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
}
|
||||||
|
if (null !== $e) {
|
||||||
|
$x = $e instanceof \Exception ? $e : new FatalThrowableError($e);
|
||||||
|
$event = new ConsoleExceptionEvent($command, $input, $output, $x, $x->getCode());
|
||||||
|
$this->dispatcher->dispatch(ConsoleEvents::EXCEPTION, $event);
|
||||||
|
|
||||||
|
if ($x !== $event->getException()) {
|
||||||
|
$e = $event->getException();
|
||||||
|
}
|
||||||
|
$exitCode = $e->getCode();
|
||||||
|
}
|
||||||
|
|
||||||
$event = new ConsoleTerminateEvent($command, $input, $output, $exitCode);
|
$event = new ConsoleTerminateEvent($command, $input, $output, $exitCode);
|
||||||
$this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);
|
$this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);
|
||||||
|
|
||||||
|
if (null !== $e) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
|
||||||
return $event->getExitCode();
|
return $event->getExitCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -977,15 +977,28 @@ class ApplicationTest extends TestCase
|
|||||||
$this->assertContains('before.foo.caught.after.', $tester->getDisplay());
|
$this->assertContains('before.foo.caught.after.', $tester->getDisplay());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRunWithError()
|
public function testRunDispatchesAllEventsWithExceptionInListener()
|
||||||
{
|
{
|
||||||
if (method_exists($this, 'expectException')) {
|
$dispatcher = $this->getDispatcher();
|
||||||
$this->expectException('Exception');
|
$dispatcher->addListener('console.command', function () {
|
||||||
$this->expectExceptionMessage('dymerr');
|
throw new \RuntimeException('foo');
|
||||||
} else {
|
});
|
||||||
$this->setExpectedException('Exception', 'dymerr');
|
|
||||||
|
$application = new Application();
|
||||||
|
$application->setDispatcher($dispatcher);
|
||||||
|
$application->setAutoExit(false);
|
||||||
|
|
||||||
|
$application->register('foo')->setCode(function (InputInterface $input, OutputInterface $output) {
|
||||||
|
$output->write('foo.');
|
||||||
|
});
|
||||||
|
|
||||||
|
$tester = new ApplicationTester($application);
|
||||||
|
$tester->run(array('command' => 'foo'));
|
||||||
|
$this->assertContains('before.caught.after.', $tester->getDisplay());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testRunWithError()
|
||||||
|
{
|
||||||
$application = new Application();
|
$application = new Application();
|
||||||
$application->setAutoExit(false);
|
$application->setAutoExit(false);
|
||||||
$application->setCatchExceptions(false);
|
$application->setCatchExceptions(false);
|
||||||
@ -997,7 +1010,13 @@ class ApplicationTest extends TestCase
|
|||||||
});
|
});
|
||||||
|
|
||||||
$tester = new ApplicationTester($application);
|
$tester = new ApplicationTester($application);
|
||||||
|
|
||||||
|
try {
|
||||||
$tester->run(array('command' => 'dym'));
|
$tester->run(array('command' => 'dym'));
|
||||||
|
$this->fail('Error expected.');
|
||||||
|
} catch (\Error $e) {
|
||||||
|
$this->assertSame('dymerr', $e->getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1087,32 +1106,6 @@ class ApplicationTest extends TestCase
|
|||||||
$this->assertSame(array($width, 80), $application->getTerminalDimensions());
|
$this->assertSame(array($width, 80), $application->getTerminalDimensions());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getDispatcher($skipCommand = false)
|
|
||||||
{
|
|
||||||
$dispatcher = new EventDispatcher();
|
|
||||||
$dispatcher->addListener('console.command', function (ConsoleCommandEvent $event) use ($skipCommand) {
|
|
||||||
$event->getOutput()->write('before.');
|
|
||||||
|
|
||||||
if ($skipCommand) {
|
|
||||||
$event->disableCommand();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$dispatcher->addListener('console.terminate', function (ConsoleTerminateEvent $event) use ($skipCommand) {
|
|
||||||
$event->getOutput()->writeln('after.');
|
|
||||||
|
|
||||||
if (!$skipCommand) {
|
|
||||||
$event->setExitCode(113);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$dispatcher->addListener('console.exception', function (ConsoleExceptionEvent $event) {
|
|
||||||
$event->getOutput()->write('caught.');
|
|
||||||
|
|
||||||
$event->setException(new \LogicException('caught.', $event->getExitCode(), $event->getException()));
|
|
||||||
});
|
|
||||||
|
|
||||||
return $dispatcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSetRunCustomDefaultCommand()
|
public function testSetRunCustomDefaultCommand()
|
||||||
{
|
{
|
||||||
$command = new \FooCommand();
|
$command = new \FooCommand();
|
||||||
@ -1151,6 +1144,32 @@ class ApplicationTest extends TestCase
|
|||||||
$inputStream = $application->getHelperSet()->get('question')->getInputStream();
|
$inputStream = $application->getHelperSet()->get('question')->getInputStream();
|
||||||
$this->assertEquals($tester->getInput()->isInteractive(), @posix_isatty($inputStream));
|
$this->assertEquals($tester->getInput()->isInteractive(), @posix_isatty($inputStream));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getDispatcher($skipCommand = false)
|
||||||
|
{
|
||||||
|
$dispatcher = new EventDispatcher();
|
||||||
|
$dispatcher->addListener('console.command', function (ConsoleCommandEvent $event) use ($skipCommand) {
|
||||||
|
$event->getOutput()->write('before.');
|
||||||
|
|
||||||
|
if ($skipCommand) {
|
||||||
|
$event->disableCommand();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$dispatcher->addListener('console.terminate', function (ConsoleTerminateEvent $event) use ($skipCommand) {
|
||||||
|
$event->getOutput()->writeln('after.');
|
||||||
|
|
||||||
|
if (!$skipCommand) {
|
||||||
|
$event->setExitCode(ConsoleCommandEvent::RETURN_CODE_DISABLED);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$dispatcher->addListener('console.exception', function (ConsoleExceptionEvent $event) {
|
||||||
|
$event->getOutput()->write('caught.');
|
||||||
|
|
||||||
|
$event->setException(new \LogicException('caught.', $event->getExitCode(), $event->getException()));
|
||||||
|
});
|
||||||
|
|
||||||
|
return $dispatcher;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CustomApplication extends Application
|
class CustomApplication extends Application
|
||||||
|
Reference in New Issue
Block a user