diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 5725d442c0914..d0cca7badd2b8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -21,6 +21,7 @@ CHANGELOG You can customize it for your functional tests or for generating urls with the right base url when your are in the cli context. * Added support for default templates per render tag + * added an init and terminate event dispatched by CLI commands 2.1.0 ----- diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php index a9aa7a5b8f6fc..94e4c025b5eba 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php @@ -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,10 +24,12 @@ * @author Francis Besset * @author Fabien Potencier */ -class CacheClearCommand extends ContainerAwareCommand +class CacheClearCommand extends Command { protected $name; + private $container; + /** * @see Command */ @@ -174,4 +177,16 @@ protected function getContainerClass() 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; + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerAwareCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerAwareCommand.php index 0540870657417..e87cb3108235a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerAwareCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerAwareCommand.php @@ -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,27 @@ abstract class ContainerAwareCommand extends Command implements ContainerAwareIn */ private $container; + /** + * {@inheritdoc} + */ + public function run(InputInterface $input, OutputInterface $output) + { + $dispatcher = $this->getContainer()->get('event_dispatcher'); + $helperSet = $this->getHelperSet(); + + $initEvent = new ConsoleEvent($input, $output); + $initEvent->setHelperSet($helperSet); + $dispatcher->dispatch(ConsoleEvents::INIT, $initEvent); + + $exitCode = parent::run($input, $output); + + $terminateEvent = new ConsoleTerminateEvent($input, $output, $exitCode); + $terminateEvent->setHelperSet($helperSet); + $dispatcher->dispatch(ConsoleEvents::TERMINATE, $terminateEvent); + + return $exitCode; + } + /** * @return ContainerInterface */ diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/ConsoleEvents.php b/src/Symfony/Bundle/FrameworkBundle/Console/ConsoleEvents.php new file mode 100644 index 0000000000000..b8fee5fcee9f0 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Console/ConsoleEvents.php @@ -0,0 +1,43 @@ + + * + * 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 + */ +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'; +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Event/ConsoleEvent.php b/src/Symfony/Bundle/FrameworkBundle/Event/ConsoleEvent.php new file mode 100644 index 0000000000000..76a72d1e05d7e --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Event/ConsoleEvent.php @@ -0,0 +1,77 @@ + + * + * 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\Helper\HelperSet; +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 + */ +class ConsoleEvent extends Event +{ + private $input; + + private $output; + + private $helperSet; + + public function __construct(InputInterface $input, OutputInterface $output) + { + $this->input = $input; + $this->output = $output; + } + + /** + * Sets the helper set. + * + * @param HelperSet $helperSet A HelperSet instance + */ + public function setHelperSet(HelperSet $helperSet) + { + $this->helperSet = $helperSet; + } + + /** + * Gets the helper set. + * + * @return HelperSet A HelperSet instance + */ + public function getHelperSet() + { + return $this->helperSet; + } + + /** + * Returns the input object + * + * @return InputInterface + */ + public function getInput() + { + return $this->input; + } + + /** + * Returns the output object + * + * @return OutputInterface + */ + public function getOutput() + { + return $this->output; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Event/ConsoleTerminateEvent.php b/src/Symfony/Bundle/FrameworkBundle/Event/ConsoleTerminateEvent.php new file mode 100644 index 0000000000000..8ade530a85dc5 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Event/ConsoleTerminateEvent.php @@ -0,0 +1,46 @@ + + * + * 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 + */ +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; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php index 1427453b10650..8c83891ec0496 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php @@ -12,7 +12,9 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Console; use Symfony\Bundle\FrameworkBundle\Tests\TestCase; +use Symfony\Bundle\FrameworkBundle\Tests\Console\Fixtures\FooCommand; use Symfony\Bundle\FrameworkBundle\Console\Application; +use Symfony\Bundle\FrameworkBundle\Console\ConsoleEvents; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\NullOutput; @@ -22,7 +24,7 @@ public function testBundleInterfaceImplementation() { $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,23 @@ public function testBundleCommandsAreRegistered() $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()); + } + + private function getKernel(array $bundles, $dispatcherExpected = null) { $kernel = $this->getMock("Symfony\Component\HttpKernel\KernelInterface"); $kernel @@ -47,6 +59,42 @@ private function getKernel(array $bundles) ->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->at(0)) + ->method('dispatch') + ->with( + $this->equalTo(ConsoleEvents::INIT), + $this->isInstanceOf('Symfony\Bundle\FrameworkBundle\Event\ConsoleEvent') + ); + $eventDispatcher + ->expects($this->at(1)) + ->method('dispatch') + ->with( + $this->equalTo(ConsoleEvents::TERMINATE), + $this->isInstanceOf('Symfony\Bundle\FrameworkBundle\Event\ConsoleTerminateEvent') + ); + $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; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Fixtures/FooCommand.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Fixtures/FooCommand.php new file mode 100644 index 0000000000000..513f60198f78b --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Fixtures/FooCommand.php @@ -0,0 +1,24 @@ + + * + * 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; + } +}