Skip to content

Commit

Permalink
Added a console.ERROR event
Browse files Browse the repository at this point in the history
  • Loading branch information
wouterj committed Feb 4, 2017
1 parent b3b3dac commit c02a4c9
Show file tree
Hide file tree
Showing 12 changed files with 298 additions and 55 deletions.
7 changes: 7 additions & 0 deletions UPGRADE-3.3.md
Expand Up @@ -11,6 +11,13 @@ Debug

* The `ContextErrorException` class is deprecated. `\ErrorException` will be used instead in 4.0.

Console
-------

* The `console.exception` event and the related `ConsoleExceptionEvent` class
have been deprecated in favor of the `console.error` event and the `ConsoleErrorEvent`
class. The deprecated event and class will be removed in 4.0.

DependencyInjection
-------------------

Expand Down
3 changes: 3 additions & 0 deletions UPGRADE-4.0.md
Expand Up @@ -12,6 +12,9 @@ Console
* Setting unknown style options is not supported anymore and throws an
exception.

* The `console.exception` event and the related `ConsoleExceptionEvent` class have
been removed in favor of the `console.error` event and the `ConsoleErrorEvent` class.

Debug
-----

Expand Down
37 changes: 31 additions & 6 deletions src/Symfony/Component/Console/Application.php
Expand Up @@ -33,6 +33,7 @@
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Helper\FormatterHelper;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\Console\Event\ConsoleErrorEvent;
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\Console\Exception\CommandNotFoundException;
Expand Down Expand Up @@ -118,16 +119,40 @@ public function run(InputInterface $input = null, OutputInterface $output = null
$this->configureIO($input, $output);

try {
$e = null;
$exitCode = $this->doRun($input, $output);
} catch (\Exception $e) {
$exception = $e;
} catch (\Throwable $e) {
$exception = new FatalThrowableError($e);
}

if (null !== $e && null !== $this->dispatcher) {
$event = new ConsoleErrorEvent($this->runningCommand, $input, $output, $e, $e->getCode());

This comment has been minimized.

Copy link
@Johnmeurt

Johnmeurt Mar 24, 2017

I think the property runningCommand is not set when CommandNotFoundException is thrown. This will trigger a php error.

This comment has been minimized.

Copy link
@xabbuh

xabbuh Mar 24, 2017

Member

see #22144

$this->dispatcher->dispatch(ConsoleEvents::ERROR, $event);

$e = $event->getError();

if ($event->isErrorHandled()) {
$e = null;
$exitCode = 0;
} else {
$exitCode = $e->getCode();
}

$event = new ConsoleTerminateEvent($this->runningCommand, $input, $output, $exitCode);
$this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);
}

if (null !== $e) {
if (!$this->catchExceptions) {
throw $e;
}

if ($output instanceof ConsoleOutputInterface) {
$this->renderException($e, $output->getErrorOutput());
$this->renderException($exception, $output->getErrorOutput());
} else {
$this->renderException($e, $output);
$this->renderException($exception, $output);
}

$exitCode = $e->getCode();
Expand Down Expand Up @@ -863,17 +888,17 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI
} catch (\Throwable $x) {
$e = new FatalThrowableError($x);
}

if (null !== $e) {
$event = new ConsoleExceptionEvent($command, $input, $output, $e, $e->getCode());
$event = new ConsoleExceptionEvent($command, $input, $output, $e, $e->getCode(), false);
$this->dispatcher->dispatch(ConsoleEvents::EXCEPTION, $event);

if ($e !== $event->getException()) {
@trigger_error('The "console.exception" event is deprecated since version 3.3 and will be removed in 4.0. Use the "console.error" event instead.', E_USER_DEPRECATED);

$x = $e = $event->getException();
}

$event = new ConsoleTerminateEvent($command, $input, $output, $e->getCode());
$this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);

throw $x;
}
} else {
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Component/Console/CHANGELOG.md
Expand Up @@ -6,6 +6,8 @@ CHANGELOG

* added `ExceptionListener`
* added `AddConsoleCommandPass` (originally in FrameworkBundle)
* added console.error event to catch exceptions thrown by other listeners
* deprecated console.exception event in favor of console.error

3.2.0
------
Expand Down
18 changes: 17 additions & 1 deletion src/Symfony/Component/Console/ConsoleEvents.php
Expand Up @@ -40,14 +40,30 @@ final class ConsoleEvents
const TERMINATE = 'console.terminate';

/**
* The EXCEPTION event occurs when an uncaught exception appears.
* The EXCEPTION event occurs when an uncaught exception appears
* while executing Command#run().
*
* This event allows you to deal with the exception or
* to modify the thrown exception.
*
* @Event("Symfony\Component\Console\Event\ConsoleExceptionEvent")
*
* @var string
*
* @deprecated The console.exception event is deprecated since version 3.3 and will be removed in 4.0. Use the console.error event instead.
*/
const EXCEPTION = 'console.exception';

/**
* The ERROR event occurs when an uncaught exception appears or
* a throwable error.
*
* This event allows you to deal with the exception/error or
* to modify the thrown exception.
*
* @Event("Symfony\Component\Console\Event\ConsoleErrorEvent")
*
* @var string
*/
const ERROR = 'console.error';
}
112 changes: 112 additions & 0 deletions src/Symfony/Component/Console/Event/ConsoleErrorEvent.php
@@ -0,0 +1,112 @@
<?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\Component\Console\Event;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Debug\Exception\FatalThrowableError;

/**
* Allows to handle throwables thrown while running a command.
*
* @author Wouter de Jong <wouter@wouterj.nl>
*/
class ConsoleErrorEvent extends ConsoleExceptionEvent
{
private $error;
private $handled = false;

public function __construct(Command $command, InputInterface $input, OutputInterface $output, $error, $exitCode)
{
if (!$error instanceof \Throwable && !$error instanceof \Exception) {
throw new InvalidArgumentException(sprintf('The error passed to ConsoleErrorEvent must be an instance of \Throwable or \Exception, "%s" was passed instead.', is_object($error) ? get_class($error) : gettype($error)));
}

$exception = $error;
if (!$error instanceof \Exception) {
$exception = new FatalThrowableError($error);
}
parent::__construct($command, $input, $output, $exception, $exitCode, false);

$this->error = $error;
}

/**
* Returns the thrown error/exception.
*
* @return \Throwable
*/
public function getError()
{
return $this->error;
}

/**
* Replaces the thrown error/exception.
*
* @param \Throwable $error
*/
public function setError($error)
{
if (!$error instanceof \Throwable && !$error instanceof \Exception) {
throw new InvalidArgumentException(sprintf('The error passed to ConsoleErrorEvent must be an instance of \Throwable or \Exception, "%s" was passed instead.', is_object($error) ? get_class($error) : gettype($error)));
}

$this->error = $error;
}

/**
* Marks the error/exception as handled.
*
* If it is not marked as handled, the error/exception will be displayed in
* the command output.
*/
public function markErrorAsHandled()
{
$this->handled = true;
}

/**
* Whether the error/exception is handled by a listener or not.
*
* If it is not yet handled, the error/exception will be displayed in the
* command output.
*
* @return bool
*/
public function isErrorHandled()
{
return $this->handled;
}

/**
* @deprecated Since version 3.3, to be removed in 4.0. Use getError() instead
*/
public function getException()
{
@trigger_error(sprintf('The %s() method is deprecated since version 3.3 and will be removed in 4.0. Use ConsoleErrorEvent::getError() instead.', __METHOD__), E_USER_DEPRECATED);

return parent::getException();
}

/**
* @deprecated Since version 3.3, to be removed in 4.0. Use setError() instead
*/
public function setException(\Exception $exception)
{
@trigger_error(sprintf('The %s() method is deprecated since version 3.3 and will be removed in 4.0. Use ConsoleErrorEvent::setError() instead.', __METHOD__), E_USER_DEPRECATED);

parent::setException($exception);
}
}
4 changes: 2 additions & 2 deletions src/Symfony/Component/Console/Event/ConsoleEvent.php
Expand Up @@ -28,7 +28,7 @@ class ConsoleEvent extends Event
private $input;
private $output;

public function __construct(Command $command, InputInterface $input, OutputInterface $output)
public function __construct(Command $command = null, InputInterface $input, OutputInterface $output)
{
$this->command = $command;
$this->input = $input;
Expand All @@ -38,7 +38,7 @@ public function __construct(Command $command, InputInterface $input, OutputInter
/**
* Gets the command that is executed.
*
* @return Command A Command instance
* @return Command|null A Command instance
*/
public function getCommand()
{
Expand Down
11 changes: 9 additions & 2 deletions src/Symfony/Component/Console/Event/ConsoleExceptionEvent.php
Expand Up @@ -19,17 +19,24 @@
* Allows to handle exception thrown in a command.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated ConsoleExceptionEvent is deprecated since version 3.3 and will be removed in 4.0. Use ConsoleErrorEvent instead.
*/
class ConsoleExceptionEvent extends ConsoleEvent
{
private $exception;
private $exitCode;
private $handled = false;

public function __construct(Command $command, InputInterface $input, OutputInterface $output, \Exception $exception, $exitCode)
public function __construct(Command $command, InputInterface $input, OutputInterface $output, \Exception $exception, $exitCode, $deprecation = true)
{
if ($deprecation) {
@trigger_error(sprintf('The %s class is deprecated since version 3.3 and will be removed in 4.0. Use the ConsoleErrorEvent instead.', __CLASS__), E_USER_DEPRECATED);
}

parent::__construct($command, $input, $output);

$this->setException($exception);
$this->exception = $exception;
$this->exitCode = (int) $exitCode;
}

Expand Down
Expand Up @@ -29,7 +29,7 @@ class ConsoleTerminateEvent extends ConsoleEvent
*/
private $exitCode;

public function __construct(Command $command, InputInterface $input, OutputInterface $output, $exitCode)
public function __construct(Command $command = null, InputInterface $input, OutputInterface $output, $exitCode)
{
parent::__construct($command, $input, $output);

Expand Down
Expand Up @@ -14,7 +14,7 @@
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Event\ConsoleEvent;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
use Symfony\Component\Console\Event\ConsoleErrorEvent;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

Expand All @@ -31,15 +31,15 @@ public function __construct(LoggerInterface $logger = null)
$this->logger = $logger;
}

public function onConsoleException(ConsoleExceptionEvent $event)
public function onConsoleError(ConsoleErrorEvent $event)
{
if (null === $this->logger) {
return;
}

$exception = $event->getException();
$error = $event->getError();

$this->logger->error('Exception thrown while running command "{command}". Message: "{message}"', array('exception' => $exception, 'command' => $this->getInputString($event), 'message' => $exception->getMessage()));
$this->logger->error('Error thrown while running command "{command}". Message: "{message}"', array('error' => $error, 'command' => $this->getInputString($event), 'message' => $error->getMessage()));
}

public function onConsoleTerminate(ConsoleTerminateEvent $event)
Expand All @@ -60,7 +60,7 @@ public function onConsoleTerminate(ConsoleTerminateEvent $event)
public static function getSubscribedEvents()
{
return array(
ConsoleEvents::EXCEPTION => array('onConsoleException', -128),
ConsoleEvents::ERROR => array('onConsoleError', -128),
ConsoleEvents::TERMINATE => array('onConsoleTerminate', -128),
);
}
Expand Down

0 comments on commit c02a4c9

Please sign in to comment.