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

Skip to content

Commit c1bd3b5

Browse files
committed
merged branch fabpot/console-dispatcher (PR #7466)
This PR was merged into the master branch. Discussion ---------- Console dispatcher | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #3889, #6124 | License | MIT | Doc PR | symfony/symfony-docs#2352 refs #1884, #1929 This is an alternative implementation for adding events to console applications. This implementation has the following features: * Available for anyone using the Console component and it is not tied to FrameworkBundle (this is important as one thing we are trying to solve is email sending from a command, and frameworks like Silex using the Console component needs a solution too); * Non-intrusive as the current code has not been changed (except for renaming an internal variable that was wrongly named -- so that's not strictly needed for this PR) * The new DispatchableApplication class also works without a dispatcher, falling back to the regular behavior. That makes easy to create applications that can benefit from a dispatcher when available, but can still work otherwise. * Besides the *before* and *after* events, there is also an *exception* event that is dispatched whenever an exception is thrown. * Each event is quite powerful and can manipulate the input, the output, but also the command to be executed. Commits ------- 4f9a55a refactored the implementation of how a console application can handle events 4edf29d added helperSet to console event objects f224102 Added events for CLI commands
2 parents e94346e + 4f9a55a commit c1bd3b5

9 files changed

+423
-9
lines changed

src/Symfony/Component/Console/Application.php

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
use Symfony\Component\Console\Helper\FormatterHelper;
2828
use Symfony\Component\Console\Helper\DialogHelper;
2929
use Symfony\Component\Console\Helper\ProgressHelper;
30+
use Symfony\Component\Console\Event\ConsoleCommandEvent;
31+
use Symfony\Component\Console\Event\ConsoleForExceptionEvent;
32+
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
33+
use Symfony\Component\EventDispatcher\EventDispatcher;
3034

3135
/**
3236
* An Application is the container for a collection of commands.
@@ -56,6 +60,7 @@ class Application
5660
private $autoExit;
5761
private $definition;
5862
private $helperSet;
63+
private $dispatcher;
5964

6065
/**
6166
* Constructor.
@@ -80,6 +85,11 @@ public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
8085
}
8186
}
8287

88+
public function setDispatcher(EventDispatcher $dispatcher)
89+
{
90+
$this->dispatcher = $dispatcher;
91+
}
92+
8393
/**
8494
* Runs the current application.
8595
*
@@ -103,7 +113,7 @@ public function run(InputInterface $input = null, OutputInterface $output = null
103113
}
104114

105115
try {
106-
$statusCode = $this->doRun($input, $output);
116+
$exitCode = $this->doRun($input, $output);
107117
} catch (\Exception $e) {
108118
if (!$this->catchExceptions) {
109119
throw $e;
@@ -114,21 +124,21 @@ public function run(InputInterface $input = null, OutputInterface $output = null
114124
} else {
115125
$this->renderException($e, $output);
116126
}
117-
$statusCode = $e->getCode();
127+
$exitCode = $e->getCode();
118128

119-
$statusCode = is_numeric($statusCode) && $statusCode ? $statusCode : 1;
129+
$exitCode = is_numeric($exitCode) && $exitCode ? $exitCode : 1;
120130
}
121131

122132
if ($this->autoExit) {
123-
if ($statusCode > 255) {
124-
$statusCode = 255;
133+
if ($exitCode > 255) {
134+
$exitCode = 255;
125135
}
126136
// @codeCoverageIgnoreStart
127-
exit($statusCode);
137+
exit($exitCode);
128138
// @codeCoverageIgnoreEnd
129139
}
130140

131-
return $statusCode;
141+
return $exitCode;
132142
}
133143

134144
/**
@@ -190,10 +200,10 @@ public function doRun(InputInterface $input, OutputInterface $output)
190200
$command = $this->find($name);
191201

192202
$this->runningCommand = $command;
193-
$statusCode = $command->run($input, $output);
203+
$exitCode = $this->doRunCommand($command, $input, $output);
194204
$this->runningCommand = null;
195205

196-
return is_numeric($statusCode) ? $statusCode : 0;
206+
return is_numeric($exitCode) ? $exitCode : 0;
197207
}
198208

199209
/**
@@ -911,6 +921,45 @@ public function getTerminalDimensions()
911921
return array(null, null);
912922
}
913923

924+
/**
925+
* Runs the current command.
926+
*
927+
* If an event dispatcher has been attached to the application,
928+
* events are also dispatched during the life-cycle of the command.
929+
*
930+
* @param Command $command A Command instance
931+
* @param InputInterface $input An Input instance
932+
* @param OutputInterface $output An Output instance
933+
*
934+
* @return integer 0 if everything went fine, or an error code
935+
*/
936+
protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output)
937+
{
938+
if (null === $this->dispatcher) {
939+
return $command->run($input, $output);
940+
}
941+
942+
$event = new ConsoleCommandEvent($command, $input, $output);
943+
$this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event);
944+
945+
try {
946+
$exitCode = $command->run($input, $output);
947+
} catch (\Exception $e) {
948+
$event = new ConsoleTerminateEvent($command, $input, $output, $e->getCode());
949+
$this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);
950+
951+
$event = new ConsoleForExceptionEvent($command, $input, $output, $e, $event->getExitCode());
952+
$this->dispatcher->dispatch(ConsoleEvents::EXCEPTION, $event);
953+
954+
throw $event->getException();
955+
}
956+
957+
$event = new ConsoleTerminateEvent($command, $input, $output, $exitCode);
958+
$this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);
959+
960+
return $event->getExitCode();
961+
}
962+
914963
/**
915964
* Gets the name of the command based on input.
916965
*

src/Symfony/Component/Console/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
2.3.0
55
-----
66

7+
* added support for events in `Application`
78
* added a way to normalize EOLs in `ApplicationTester::getDisplay()` and `CommandTester::getDisplay()`
89
* added a way to set the progress bar progress via the `setCurrent` method
910

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Console;
13+
14+
/**
15+
* Contains all events dispatched by an Application.
16+
*
17+
* @author Francesco Levorato <[email protected]>
18+
*/
19+
final class ConsoleEvents
20+
{
21+
/**
22+
* The COMMAND event allows you to attach listeners before any command is
23+
* executed by the console. It also allows you to modify the command, input and output
24+
* before they are handled to the command.
25+
*
26+
* The event listener method receives a Symfony\Component\Console\Event\ConsoleCommandEvent
27+
* instance.
28+
*
29+
* @var string
30+
*/
31+
const COMMAND = 'console.command';
32+
33+
/**
34+
* The TERMINATE event allows you to attach listeners after a command is
35+
* executed by the console.
36+
*
37+
* The event listener method receives a Symfony\Component\Console\Event\ConsoleTerminateEvent
38+
* instance.
39+
*
40+
* @var string
41+
*/
42+
const TERMINATE = 'console.terminate';
43+
44+
/**
45+
* The EXCEPTION event occurs when an uncaught exception appears.
46+
*
47+
* This event allows you to deal with the exception or
48+
* to modify the thrown exception. The event listener method receives
49+
* a Symfony\Component\Console\Event\ConsoleForExceptionEvent
50+
* instance.
51+
*
52+
* @var string
53+
*/
54+
const EXCEPTION = 'console.exception';
55+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Console\Event;
13+
14+
use Symfony\Component\Console\Command\Command;
15+
use Symfony\Component\Console\Input\InputInterface;
16+
use Symfony\Component\Console\Output\OutputInterface;
17+
18+
/**
19+
* Allows to do things before the command is executed.
20+
*
21+
* @author Fabien Potencier <[email protected]>
22+
*/
23+
class ConsoleCommandEvent extends ConsoleEvent
24+
{
25+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Console\Event;
13+
14+
use Symfony\Component\Console\Command\Command;
15+
use Symfony\Component\Console\Input\InputInterface;
16+
use Symfony\Component\Console\Output\OutputInterface;
17+
use Symfony\Component\EventDispatcher\Event;
18+
19+
/**
20+
* Allows to inspect input and output of a command.
21+
*
22+
* @author Francesco Levorato <[email protected]>
23+
*/
24+
class ConsoleEvent extends Event
25+
{
26+
protected $command;
27+
28+
private $input;
29+
private $output;
30+
31+
public function __construct(Command $command, InputInterface $input, OutputInterface $output)
32+
{
33+
$this->command = $command;
34+
$this->input = $input;
35+
$this->output = $output;
36+
}
37+
38+
/**
39+
* Gets the command that is executed.
40+
*
41+
* @return Command A Command instance
42+
*/
43+
public function getCommand()
44+
{
45+
return $this->command;
46+
}
47+
48+
/**
49+
* Gets the input instance.
50+
*
51+
* @return InputInterface An InputInterface instance
52+
*/
53+
public function getInput()
54+
{
55+
return $this->input;
56+
}
57+
58+
/**
59+
* Gets the output instance.
60+
*
61+
* @return OutputInterface An OutputInterface instance
62+
*/
63+
public function getOutput()
64+
{
65+
return $this->output;
66+
}
67+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Console\Event;
13+
14+
use Symfony\Component\Console\Command\Command;
15+
use Symfony\Component\Console\Input\InputInterface;
16+
use Symfony\Component\Console\Output\OutputInterface;
17+
18+
/**
19+
* Allows to handle exception thrown in a command.
20+
*
21+
* @author Fabien Potencier <[email protected]>
22+
*/
23+
class ConsoleForExceptionEvent extends ConsoleEvent
24+
{
25+
private $exception;
26+
private $exitCode;
27+
28+
public function __construct(Command $command, InputInterface $input, OutputInterface $output, \Exception $exception, $exitCode)
29+
{
30+
parent::__construct($command, $input, $output);
31+
32+
$this->setException($exception);
33+
$this->exitCode = $exitCode;
34+
}
35+
36+
/**
37+
* Returns the thrown exception.
38+
*
39+
* @return \Exception The thrown exception
40+
*/
41+
public function getException()
42+
{
43+
return $this->exception;
44+
}
45+
46+
/**
47+
* Replaces the thrown exception.
48+
*
49+
* This exception will be thrown if no response is set in the event.
50+
*
51+
* @param \Exception $exception The thrown exception
52+
*/
53+
public function setException(\Exception $exception)
54+
{
55+
$this->exception = $exception;
56+
}
57+
58+
/**
59+
* Gets the exit code.
60+
*
61+
* @return integer The command exit code
62+
*/
63+
public function getExitCode()
64+
{
65+
return $this->exitCode;
66+
}
67+
}

0 commit comments

Comments
 (0)