Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Console] Add console.ERROR event and deprecate console.EXCEPTION #18140

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 22, 2017

Conversation

wouterj
Copy link
Member

@wouterj wouterj commented Mar 12, 2016

Q A
Branch master
Bug fix? yes
New feature? yes
BC breaks? no
Deprecations? yes
Tests pass? yes
Fixed tickets -
License MIT
Doc PR todo

The Problem

The current console.EXCEPTION event is only dispatched for exceptions during the execution of Command#execute(). All other exceptions (e.g. the ones thrown by listeners to events) are catched by the try ... catch loop in Application#doRunCommand(). This means that there is no way to override exception handling.

The Solution

This PR adds a console.ERROR event which has the same scope as the default try ... catch loop. This allows to customize all exception handling.

In order to keep BC, a new event was created and console.EXCEPTION was deprecated.

*/
public function setException(\Exception $exception)
public function setException(\Exception $exception = null)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strictly speaking, this is a BC break. But only the public API is important for event classes, so I don't think we should consider this a BC break.

$this->renderException($e, $output->getErrorOutput());
} else {
$this->renderException($e, $output);
$e = $event->getException();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize that you want a listener to ERROR to be able to "handle" the exception so that things don't continue. To do this, the listener will call $event->setException(null), which just looks like a weird way to do it.

Perhaps a $event->setExceptionAsHandled() or something to signal that the Application shouldn't continue and render the exception? It would also simplify the $exitCode code below, since there will be an exception still.

@nicolas-grekas nicolas-grekas added this to the 3.x milestone Dec 6, 2016
@xabbuh
Copy link
Member

xabbuh commented Dec 25, 2016

@wouterj Are you able to address the comments here?

@wouterj wouterj force-pushed the issue_16497 branch 2 times, most recently from c0dbc95 to 741c752 Compare December 25, 2016 23:33
@wouterj
Copy link
Member Author

wouterj commented Dec 25, 2016

Updated this PR:

  • A new ConsoleErrorEvent was introduced, replacing ConsoleExceptionEvent. This now adds full PHP 7 support (\Throwable instead of \Exception) and makes it a lot easier to trigger deprecation notices.
  • Instead of passing null to setException(), markErrorAsHandled() and isErrorHandled() were introduced.
  • Tests were updated to use the new event and a new legacy test was added for the old behaviour.

@wouterj
Copy link
Member Author

wouterj commented Dec 25, 2016

Fabbot.io failures should be ignored, this is a bug in the CS fixer config

*/
public function getException()
{
@trigger_error('The ConsoleExceptionEvent::'.__METHOD__.'() method is deprecated since version 3.3 and will be removed in 4.0. Use ConsoleErrorEvent::getError() instead.', E_USER_DEPRECATED);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should use sprintf and __METHOD__ already contains the namespace.

@@ -19,17 +19,24 @@
* Allows to handle exception thrown in a command.
*
* @author Fabien Potencier <[email protected]>
*
* @deprecated ConsoleExceptionEvent is deprecated since version 3.2 and will be removed in 4.0. Use ConsoleErrorEvent instead.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since 3.3

{
if ($deprecation) {
@trigger_error('The '.__CLASS__.' class is deprecated since version 3.3 and will be removed in 4.0. Use the ConsoleErrorEvent instead.', E_USER_DEPRECATED);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sprintf

@wouterj
Copy link
Member Author

wouterj commented Dec 26, 2016

Thanks for the quick review. PR is now updated (also added related UPGRADE and CHANGELOG notes).

UPGRADE-3.3.md Outdated
Console
-------

* The `console.exception` event and related `ConsoleExceptionEvent` class have been deprecated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[...] and the related [...]

UPGRADE-3.3.md Outdated
-------

* The `console.exception` event and related `ConsoleExceptionEvent` class have been deprecated
in favor of the `console.error` event and `ConsoleErrorEvent` class. The deprecated event and
Copy link
Member

@xabbuh xabbuh Dec 28, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[...] and the ConsoleErrorEvent [...]

UPGRADE-4.0.md Outdated
@@ -13,6 +13,9 @@ Console
* Setting unknown style options is not supported anymore and throws an
exception.

* The `console.exception` event and related `ConsoleExceptionEvent` class have
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[...] and the related [...]

UPGRADE-4.0.md Outdated
@@ -13,6 +13,9 @@ Console
* Setting unknown style options is not supported anymore and throws an
exception.

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[...] and the ConsoleErrorEvent [...]

@@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, this is a BC break.

Copy link
Member Author

@wouterj wouterj Dec 28, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah see #18140 (comment) :

Strictly speaking, this is a BC break. But only the public API is important for event classes, so I don't think we should consider this a BC break.

Yeah, but this only happends on the new console.error event. All other events behave the same.

@wouterj
Copy link
Member Author

wouterj commented Feb 1, 2017

Updated the PR. Should be ready to merge now (finally).

@wouterj wouterj force-pushed the issue_16497 branch 2 times, most recently from 8be9f16 to d25f8e4 Compare February 1, 2017 10:13
* a Symfony\Component\Console\Event\ConsoleExceptionEvent
* instance.
*
* @Event
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be @Event("Symfony\Component\Console\Event\ConsoleExceptionEvent")

*
* This event allows you to deal with the exception/error or
* to modify the thrown exception. The event listener method receives
* a Symfony\Component\Console\Event\ConsoleExceptionEvent
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment can be removed if you fix the @Event annotation (see below).

* If it is not marked as handled, the error/exception will be displayed in
* the command output.
*/
public function markErrorAsHandled()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of having this marker, can't we just set the error as null to signify that error handling is done?

Copy link
Member Author

@wouterj wouterj Feb 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did it that way before, but @weaverryan suggested to use a marker:

I realize that you want a listener to ERROR to be able to "handle" the exception so that things don't continue. To do this, the listener will call $event->setException(null), which just looks like a weird way to do it.

Perhaps a $event->setExceptionAsHandled() or something to signal that the Application shouldn't continue and render the exception?

-- #18140 (comment)

@wouterj
Copy link
Member Author

wouterj commented Mar 16, 2017

So, what's the decision here:

  1. Keep current proposal, using $event->markErrorAsHandled() to indicate console shouldn't output the error
  2. Change to $event->setException(null) again

I'm getting a bit tired of rebasing my PRs each month, so I would like to have some quick decision making on this. Happy to close as well.

@fabpot
Copy link
Member

fabpot commented Mar 22, 2017

Thank you @wouterj.

@fabpot fabpot merged commit c02a4c9 into symfony:master Mar 22, 2017
fabpot added a commit that referenced this pull request Mar 22, 2017
…e.EXCEPTION (wouterj)

This PR was merged into the 3.3-dev branch.

Discussion
----------

[Console] Add console.ERROR event and deprecate console.EXCEPTION

| Q | A |
| --- | --- |
| Branch | master |
| Bug fix? | yes |
| New feature? | yes |
| BC breaks? | no |
| Deprecations? | yes |
| Tests pass? | yes |
| Fixed tickets | - |
| License | MIT |
| Doc PR | todo |
## The Problem

The current `console.EXCEPTION` event is only dispatched for exceptions during the execution of `Command#execute()`. All other exceptions (e.g. the ones thrown by listeners to events) are catched by the `try ... catch` loop in `Application#doRunCommand()`. This means that there is _no way to override exception handling_.
## The Solution

This PR adds a `console.ERROR` event which has the same scope as the default `try ... catch` loop. This allows to customize all exception handling.

In order to keep BC, a new event was created and `console.EXCEPTION` was deprecated.

Commits
-------

c02a4c9 Added a console.ERROR event
@wouterj wouterj deleted the issue_16497 branch March 23, 2017 00:26
*/
class ConsoleExceptionEvent extends ConsoleEvent
{
private $exception;
private $exitCode;
private $handled = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wouterj this prop doesn't seem to be used, should we remove it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, seems to be a left-over of the previous implementation

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 2ad5923

}

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

@lyrixx lyrixx Mar 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With everything on master, if you run: bin/console mldsqlkmldmksq you got this:

Fatal error: Uncaught Symfony\Component\Debug\Exception\FatalThrowableError: Type error: Argument 1 passed to Symfony\Component\Console\Event\ConsoleErrorEvent::__construct() must be an instance of Symfony\Component\Console\Command\Command, null given, called in /home/greg/dev/github.com/lyrixx/symfony/src/Symfony/Component/Console/Application.php on line 131 in /home/greg/dev/github.com/lyrixx/symfony/src/Symfony/Component/Console/Event/ConsoleErrorEvent.php:30
Stack trace:
#0 /home/greg/dev/github.com/lyrixx/symfony/src/Symfony/Component/Console/Application.php(131): Symfony\Component\Console\Event\ConsoleErrorEvent->__construct(NULL, Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput), Object(Symfony\Component\Console\Exception\CommandNotFoundException), 0)
#1 /home/greg/dev/github.com/lyrixx/symfony-standard/bin/console(28): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput))
#2 {main}
  thrown in /home/greg/dev/github.com/lyrixx/symfony/src/Symfony/Component/Console/Event/ConsoleErrorEvent.php on line 30

It's weird nobody notice that. May be I'm missing something but I really doubt, because all my repository are clean.

  1. Do you experience this behaviour too?
  2. How to patch that ? I can do a PR, but I'm not sure about the how to solve this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran into this yesterday, I believe the same occurs on 2.7 with ConsoleExceptionEvent. Not sure about the better approach to fix it yet

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My attempts to fix that: #22144

@renan
Copy link
Contributor

renan commented Apr 24, 2017

I believe the ability for the application to catch \Throwable and then exit in error is quite an important thing to have. Can we have this backported into a 3.2 release?

@nicolas-grekas
Copy link
Member

nicolas-grekas commented Apr 24, 2017

@renan it already does. What this PR provides is access to the original throwable (they are cast to FatalErrorException before), and dispatching for exceptions thrown when a command is found/not found.

@renan
Copy link
Contributor

renan commented Apr 25, 2017

@nicolas-grekas Indeed I can't reproduce it with a minimalist script. Looks like there's a bad mix of Doctrine + Framework Bundle + Debug Component (ErrorHandler) on my application that's causing exceptions thrown on migrations to not mark the script execution as failed.

PS: Sorry for the noise.

fabpot added a commit that referenced this pull request Apr 26, 2017
…as-grekas)

This PR was merged into the 3.3-dev branch.

Discussion
----------

[Console] Review console.ERROR related behavior

| Q             | A
| ------------- | ---
| Branch?       | 3.3
| Bug fix?      | yes
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

This PR is a follow up of #18140 that I wanted to do since a few weeks.
It enhances this work with fixes and behavior changes.
It embeds #22435 and resolves issues like the one described in #20808.

- makes ConsoleErrorEvent *not* extend the deprecated ConsoleExceptionEvent
- replace ConsoleErrorEvent::markErrorAsHandled by ConsoleErrorEvent::setExitCode
- triggers the deprecation in a more appropriate moment
- renames ExceptionListener to ErrorListener
- tweaks the behavior in relation to  #22435

Commits
-------

a7c67c9 [Console] Review console.ERROR related behavior
@fabpot fabpot mentioned this pull request May 1, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.