[Console] Skip commands from ConsoleCommandEvent

Use case: We have different variations of the same application, for which
only certain commands are allowed. Right now this is done in a custom
Application class, but it would be much easier to just be able to skip
commands from a listener, where you can disable commands via the Event
object.

This patch provides this feature and corresponding test cases.

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes - for Console tests
| Fixed tickets | None
| License       | MIT
| Doc PR        | None
This commit is contained in:
Thomas Ploch 2013-10-07 16:20:10 +02:00
parent bf140a8487
commit acb1ae6616
3 changed files with 80 additions and 13 deletions

View File

@ -892,6 +892,7 @@ class Application
$event = new ConsoleCommandEvent($command, $input, $output); $event = new ConsoleCommandEvent($command, $input, $output);
$this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event); $this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event);
if ($event->commandShouldRun()) {
try { try {
$exitCode = $command->run($input, $output); $exitCode = $command->run($input, $output);
} catch (\Exception $e) { } catch (\Exception $e) {
@ -903,6 +904,9 @@ class Application
throw $event->getException(); throw $event->getException();
} }
} else {
$exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED;
}
$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);

View File

@ -12,10 +12,51 @@
namespace Symfony\Component\Console\Event; namespace Symfony\Component\Console\Event;
/** /**
* Allows to do things before the command is executed. * Allows to do things before the command is executed, like skipping the command or changing the input.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*/ */
class ConsoleCommandEvent extends ConsoleEvent class ConsoleCommandEvent extends ConsoleEvent
{ {
/**
* The return code for skipped commands, this will also be passed into the terminate event
*/
const RETURN_CODE_DISABLED = 113;
/**
* Indicates if the command should be run or skipped
*
* @var bool
*/
private $commandShouldRun = true;
/**
* Disables the command, so it won't be run
*
* @return bool
*/
public function disableCommand()
{
return $this->commandShouldRun = false;
}
/**
* Enables the command
*
* @return bool
*/
public function enableCommand()
{
return $this->commandShouldRun = true;
}
/**
* Returns true if the command is runnable, false otherwise
*
* @return bool
*/
public function commandShouldRun()
{
return $this->commandShouldRun;
}
} }

View File

@ -891,6 +891,22 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase
$this->assertContains('before.foo.after.caught.', $tester->getDisplay()); $this->assertContains('before.foo.after.caught.', $tester->getDisplay());
} }
public function testRunWithDispatcherSkippingCommand()
{
$application = new Application();
$application->setDispatcher($this->getDispatcher(true));
$application->setAutoExit(false);
$application->register('foo')->setCode(function (InputInterface $input, OutputInterface $output) {
$output->write('foo.');
});
$tester = new ApplicationTester($application);
$exitCode = $tester->run(array('command' => 'foo'));
$this->assertContains('before.after.', $tester->getDisplay());
$this->assertEquals(ConsoleCommandEvent::RETURN_CODE_DISABLED, $exitCode);
}
public function testTerminalDimensions() public function testTerminalDimensions()
{ {
$application = new Application(); $application = new Application();
@ -906,16 +922,22 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase
$this->assertSame(array($width, 80), $application->getTerminalDimensions()); $this->assertSame(array($width, 80), $application->getTerminalDimensions());
} }
protected function getDispatcher() protected function getDispatcher($skipCommand = false)
{ {
$dispatcher = new EventDispatcher(); $dispatcher = new EventDispatcher();
$dispatcher->addListener('console.command', function (ConsoleCommandEvent $event) { $dispatcher->addListener('console.command', function (ConsoleCommandEvent $event) use ($skipCommand) {
$event->getOutput()->write('before.'); $event->getOutput()->write('before.');
if ($skipCommand) {
$event->disableCommand();
}
}); });
$dispatcher->addListener('console.terminate', function (ConsoleTerminateEvent $event) { $dispatcher->addListener('console.terminate', function (ConsoleTerminateEvent $event) use ($skipCommand) {
$event->getOutput()->write('after.'); $event->getOutput()->write('after.');
$event->setExitCode(128); if (!$skipCommand) {
$event->setExitCode(113);
}
}); });
$dispatcher->addListener('console.exception', function (ConsoleExceptionEvent $event) { $dispatcher->addListener('console.exception', function (ConsoleExceptionEvent $event) {
$event->getOutput()->writeln('caught.'); $event->getOutput()->writeln('caught.');