Permalink
Browse files

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).
  • Loading branch information...
1 parent ddd30d0 commit f224102c72f8153822bc54cc92685d30faade0da @flevour flevour committed with fabpot Apr 11, 2012
@@ -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
@@ -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 @@
* @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 @@ public function getRootDir()
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;
+ }
}
@@ -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;
@@ -28,6 +33,24 @@
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
*/
protected function getContainer()
@@ -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';
+}
@@ -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;
+ }
+}
@@ -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;
+ }
+}
@@ -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 @@ 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,20 +35,65 @@ 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());
+ }
+
+ 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
->expects($this->any())
->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;
}
@@ -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;
+ }
+}
@@ -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;
+ }
+}

0 comments on commit f224102

Please sign in to comment.