Added events for CLI commands

This adds an init and terminate event for commands. They are
dispatched from ContainerAwareCommand.

The cache:clear command can't implement this (cf. #3889 on Github).
This commit is contained in:
Francesco Levorato 2012-04-11 23:35:46 +02:00 committed by Fabien Potencier
parent ddd30d0b8e
commit f224102c72
9 changed files with 282 additions and 4 deletions

View File

@ -4,6 +4,7 @@ CHANGELOG
2.3.0
-----
* added an init and terminate event dispatched by CLI commands
* added `--clean` option the the `translation:update` command
* added `http_method_override` option

View File

@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@ -23,8 +24,10 @@ use Symfony\Component\Finder\Finder;
* @author Francis Besset <francis.besset@gmail.com>
* @author Fabien Potencier <fabien@symfony.com>
*/
class CacheClearCommand extends ContainerAwareCommand
class CacheClearCommand extends Command
{
private $container;
/**
* {@inheritdoc}
*/
@ -197,4 +200,16 @@ EOF;
return new $class($parent->getEnvironment(), $parent->isDebug());
}
/**
* @return ContainerInterface
*/
protected function getContainer()
{
if (null === $this->container) {
$this->container = $this->getApplication()->getKernel()->getContainer();
}
return $this->container;
}
}

View File

@ -11,7 +11,12 @@
namespace Symfony\Bundle\FrameworkBundle\Command;
use Symfony\Bundle\FrameworkBundle\Console\ConsoleEvents;
use Symfony\Bundle\FrameworkBundle\Event\ConsoleEvent;
use Symfony\Bundle\FrameworkBundle\Event\ConsoleTerminateEvent;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
@ -27,6 +32,24 @@ abstract class ContainerAwareCommand extends Command implements ContainerAwareIn
*/
private $container;
/**
* {@inheritdoc}
*/
public function run(InputInterface $input, OutputInterface $output)
{
$dispatcher = $this->getContainer()->get('event_dispatcher');
$initEvent = new ConsoleEvent($input, $output);
$dispatcher->dispatch(ConsoleEvents::INIT, $initEvent);
$exitCode = parent::run($input, $output);
$terminateEvent = new ConsoleTerminateEvent($input, $output, $exitCode);
$dispatcher->dispatch(ConsoleEvents::TERMINATE, $terminateEvent);
return $exitCode;
}
/**
* @return ContainerInterface
*/

View File

@ -0,0 +1,43 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\FrameworkBundle\Console;
/**
* Contains all events thrown during Console commands execution
*
* @author Francesco Levorato <git@flevour.net>
*/
final class ConsoleEvents
{
/**
* The INIT event allows you to attach listeners before any command is
* executed by the console. It also allows you to modify the input and output
* before they are handled to the command.
*
* The event listener method receives a \Symfony\Bundle\FrameworkBundle\Event\ConsoleEvent
* instance.
*
* @var string
*/
const INIT = 'console.init';
/**
* The TERMINATE event allows you to attach listeners after a command is
* executed by the console.
*
* The event listener method receives a \Symfony\Bundle\FrameworkBundle\Event\ConsoleTerminateEvent
* instance.
*
* @var string
*/
const TERMINATE = 'console.terminate';
}

View File

@ -0,0 +1,54 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\FrameworkBundle\Event;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\EventDispatcher\Event;
/**
* Allows to inspect input and output of a command.
*
* @author Francesco Levorato <git@flevour.net>
*/
class ConsoleEvent extends Event
{
private $input;
private $output;
public function __construct(InputInterface $input, OutputInterface $output)
{
$this->input = $input;
$this->output = $output;
}
/**
* Returns the input object
*
* @return InputInterface
*/
public function getInput()
{
return $this->input;
}
/**
* Returns the output object
*
* @return OutputInterface
*/
public function getOutput()
{
return $this->output;
}
}

View File

@ -0,0 +1,46 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\FrameworkBundle\Event;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Allows to receive the exit code of a command after its execution.
*
* @author Francesco Levorato <git@flevour.net>
*/
class ConsoleTerminateEvent extends ConsoleEvent
{
/**
* The exit code of the command.
*
* @var integer
*/
private $exitCode;
public function __construct(InputInterface $input, OutputInterface $output, $exitCode)
{
parent::__construct($input, $output);
$this->exitCode = $exitCode;
}
/**
* Returns the exit code.
*
* @return integer
*/
public function getExitCode()
{
return $this->exitCode;
}
}

View File

@ -12,6 +12,8 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Console;
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
use Symfony\Bundle\FrameworkBundle\Tests\Console\Fixtures\FooCommand;
use Symfony\Bundle\FrameworkBundle\Tests\Console\Fixtures\SilentCommand;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
@ -22,7 +24,7 @@ class ApplicationTest extends TestCase
{
$bundle = $this->getMock("Symfony\Component\HttpKernel\Bundle\BundleInterface");
$kernel = $this->getKernel(array($bundle));
$kernel = $this->getKernel(array($bundle), $this->never());
$application = new Application($kernel);
$application->doRun(new ArrayInput(array('list')), new NullOutput());
@ -33,13 +35,33 @@ class ApplicationTest extends TestCase
$bundle = $this->getMock("Symfony\Component\HttpKernel\Bundle\Bundle");
$bundle->expects($this->once())->method('registerCommands');
$kernel = $this->getKernel(array($bundle));
$kernel = $this->getKernel(array($bundle), $this->never());
$application = new Application($kernel);
$application->doRun(new ArrayInput(array('list')), new NullOutput());
}
private function getKernel(array $bundles)
public function testCommandDispatchEvents()
{
$kernel = $this->getKernel(array(), $this->once());
$application = new Application($kernel);
$application->add(new FooCommand('foo'));
$application->doRun(new ArrayInput(array('foo')), new NullOutput());
}
public function testSilentCommand()
{
$kernel = $this->getKernel(array(), $this->never());
$application = new Application($kernel);
$application->add(new SilentCommand('chut'));
$application->doRun(new ArrayInput(array('chut')), new NullOutput());
}
private function getKernel(array $bundles, $dispatcherExpected = null)
{
$kernel = $this->getMock("Symfony\Component\HttpKernel\KernelInterface");
$kernel
@ -47,6 +69,31 @@ class ApplicationTest extends TestCase
->method('getBundles')
->will($this->returnValue($bundles))
;
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
$dispatcherExpected = $dispatcherExpected ?: $this->any();
if ($this->never() == $dispatcherExpected) {
$container
->expects($dispatcherExpected)
->method('get');
} else {
$eventDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
$eventDispatcher
->expects($this->atLeastOnce())
->method('dispatch');
$container
->expects($dispatcherExpected)
->method('get')
->with($this->equalTo('event_dispatcher'))
->will($this->returnValue($eventDispatcher));
}
$kernel
->expects($this->any())
->method('getContainer')
->will($this->returnValue($container))
;
return $kernel;
}

View File

@ -0,0 +1,24 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\FrameworkBundle\Tests\Console\Fixtures;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class FooCommand extends ContainerAwareCommand
{
protected function execute(InputInterface $input, OutputInterface $output)
{
return 0;
}
}

View File

@ -0,0 +1,25 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\FrameworkBundle\Tests\Console\Fixtures;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class SilentCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output)
{
return 0;
}
}