Skip to content

Instantly share code, notes, and snippets.

@peterjmit
Last active January 4, 2018 09:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save peterjmit/1653643cb7b48782e64a to your computer and use it in GitHub Desktop.
Save peterjmit/1653643cb7b48782e64a to your computer and use it in GitHub Desktop.
Console events are not dispatched in Symfony when using the CommandTester class shown in http://symfony.com/doc/current/components/console/introduction.html#testing-commands. This class fixes that
<?php
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\StreamOutput;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class EventDispatchingCommandTester
{
private $command;
private $input;
private $output;
private $statusCode;
private $dispatcher;
/**
* Constructor.
*
* @param Command $command A Command instance to test.
*/
public function __construct(Command $command, EventDispatcherInterface $dispatcher)
{
$this->command = $command;
$this->dispatcher = $dispatcher;
}
/**
* Same behaviour as the CommandTester::execute method, with the addition of
* the event dispatching mechanism that happens in a "production" code command
*
* @see Symfony\Component\Console\Tester\CommandTester::execute
* @see Symfony\Component\Console\Application::doRunCommand
*/
public function execute(array $input, array $options = array())
{
$this->createIO($input, $options);
$event = new ConsoleCommandEvent($this->command, $this->input, $this->output);
$this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event);
if ($event->commandShouldRun()) {
try {
$exitCode = $this->command->run($this->input, $this->output);
} catch (\Exception $e) {
$event = new ConsoleTerminateEvent($this->command, $this->input, $this->output, $e->getCode());
$this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);
$event = new ConsoleExceptionEvent($this->command, $this->input, $this->output, $e, $event->getExitCode());
$this->dispatcher->dispatch(ConsoleEvents::EXCEPTION, $event);
throw $event->getException();
}
} else {
$exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED;
}
$event = new ConsoleTerminateEvent($this->command, $this->input, $this->output, $exitCode);
$this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);
return $this->statusCode = $event->getExitCode();
}
/**
* Gets the display returned by the last execution of the command.
*
* @param bool $normalize Whether to normalize end of lines to \n or not
*
* @return string The display
*/
public function getDisplay($normalize = false)
{
rewind($this->output->getStream());
$display = stream_get_contents($this->output->getStream());
if ($normalize) {
$display = str_replace(PHP_EOL, "\n", $display);
}
return $display;
}
/**
* Gets the input instance used by the last execution of the command.
*
* @return InputInterface The current input instance
*/
public function getInput()
{
return $this->input;
}
/**
* Gets the output instance used by the last execution of the command.
*
* @return OutputInterface The current output instance
*/
public function getOutput()
{
return $this->output;
}
/**
* Gets the status code returned by the last execution of the application.
*
* @return int The status code
*/
public function getStatusCode()
{
return $this->statusCode;
}
private function createIO(array $input, array $options = array())
{
// set the command name automatically if the application requires
// this argument and no command name was passed
if (!isset($input['command'])
&& (null !== $application = $this->command->getApplication())
&& $application->getDefinition()->hasArgument('command')
) {
$input['command'] = $this->command->getName();
}
$this->input = new ArrayInput($input);
if (isset($options['interactive'])) {
$this->input->setInteractive($options['interactive']);
}
$this->output = new StreamOutput(fopen('php://memory', 'w', false));
if (isset($options['decorated'])) {
$this->output->setDecorated($options['decorated']);
}
if (isset($options['verbosity'])) {
$this->output->setVerbosity($options['verbosity']);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment