Skip to content

Commit 9ff4b70

Browse files
committed
Add Console ExceptionListener
Handle non string-castable inputs Cleanup input for display Naming changes InputInterface doesnt have a toString() Logger must be private Remove useless doc blocks Tweak tests
1 parent 87eee63 commit 9ff4b70

File tree

6 files changed

+90
-66
lines changed

6 files changed

+90
-66
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

+5-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
use Symfony\Component\Workflow;
3939
use Symfony\Component\Workflow\SupportStrategy\ClassInstanceSupportStrategy;
4040
use Symfony\Component\Yaml\Yaml;
41+
use Symfony\Component\Console\Application;
4142

4243
/**
4344
* FrameworkExtension.
@@ -82,7 +83,10 @@ public function load(array $configs, ContainerBuilder $container)
8283
}
8384

8485
$loader->load('fragment_renderer.xml');
85-
$loader->load('console.xml');
86+
87+
if (class_exists(Application::class)) {
88+
$loader->load('console.xml');
89+
}
8690

8791
// Property access is used by both the Form and the Validator component
8892
$loader->load('property_access.xml');

src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml

+5-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
66

77
<services>
8-
<service id="console.exception_listener" class="Symfony\Component\Console\EventListener\ExceptionListener">
9-
<tag name="kernel.event_subscriber" />
8+
9+
<service id="console.exception_listener" class="Symfony\Component\Console\EventListener\ExceptionListener" public="false">
1010
<argument type="service" id="logger" on-invalid="null" />
11+
<tag name="kernel.event_subscriber" />
12+
<tag name="monolog.logger" channel="console" />
1113
</service>
14+
1215
</services>
1316
</container>

src/Symfony/Bundle/FrameworkBundle/composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"symfony/class-loader": "~3.2",
2222
"symfony/dependency-injection": "~3.3",
2323
"symfony/config": "~3.3",
24-
"symfony/event-dispatcher": "~2.8|~3.0",
24+
"symfony/event-dispatcher": "~3.3",
2525
"symfony/http-foundation": "~3.1",
2626
"symfony/http-kernel": "~3.3",
2727
"symfony/polyfill-mbstring": "~1.0",

src/Symfony/Component/Console/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
3.3.0
55
-----
66

7+
* added `ExceptionListener`
78
* added `AddConsoleCommandPass` (originally in FrameworkBundle)
89

910
3.2.0

src/Symfony/Component/Console/EventListener/ExceptionListener.php

+23-34
Original file line numberDiff line numberDiff line change
@@ -12,79 +12,68 @@
1212
namespace Symfony\Component\Console\EventListener;
1313

1414
use Psr\Log\LoggerInterface;
15+
use Symfony\Component\Console\Event\ConsoleEvent;
1516
use Symfony\Component\Console\ConsoleEvents;
1617
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
1718
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
1819
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
1920

2021
/**
21-
* Console exception listener.
22-
*
23-
* Attempts to log exceptions or abnormal terminations of console commands.
24-
*
2522
* @author James Halsall <james.t.halsall@googlemail.com>
23+
* @author Robin Chalas <robin.chalas@gmail.com>
2624
*/
2725
class ExceptionListener implements EventSubscriberInterface
2826
{
29-
/**
30-
* @var LoggerInterface
31-
*/
32-
protected $logger;
33-
34-
/**
35-
* Constructor.
36-
*
37-
* @param LoggerInterface $logger A logger
38-
*/
27+
private $logger;
28+
3929
public function __construct(LoggerInterface $logger = null)
4030
{
4131
$this->logger = $logger;
4232
}
4333

44-
/**
45-
* Handles console command exception.
46-
*
47-
* @param ConsoleExceptionEvent $event Console event
48-
*/
49-
public function onKernelException(ConsoleExceptionEvent $event)
34+
public function onConsoleException(ConsoleExceptionEvent $event)
5035
{
5136
if (null === $this->logger) {
5237
return;
5338
}
5439

5540
$exception = $event->getException();
56-
$input = (string) $event->getInput();
5741

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

61-
/**
62-
* Handles termination of console command.
63-
*
64-
* @param ConsoleTerminateEvent $event Console event
65-
*/
66-
public function onKernelTerminate(ConsoleTerminateEvent $event)
45+
public function onConsoleTerminate(ConsoleTerminateEvent $event)
6746
{
6847
if (null === $this->logger) {
6948
return;
7049
}
7150

7251
$exitCode = $event->getExitCode();
7352

74-
if ($exitCode === 0) {
53+
if (0 === $exitCode) {
7554
return;
7655
}
7756

78-
$input = (string) $event->getInput();
79-
80-
$this->logger->error('Command "{command}" exited with status code "{code}"', array('command' => (string) $input, 'code' => $exitCode));
57+
$this->logger->error('Command "{command}" exited with code "{code}"', array('command' => $this->getInputString($event), 'code' => $exitCode));
8158
}
8259

8360
public static function getSubscribedEvents()
8461
{
8562
return array(
86-
ConsoleEvents::EXCEPTION => array('onKernelException', -128),
87-
ConsoleEvents::TERMINATE => array('onKernelTerminate', -128),
63+
ConsoleEvents::EXCEPTION => array('onConsoleException', -128),
64+
ConsoleEvents::TERMINATE => array('onConsoleTerminate', -128),
8865
);
8966
}
67+
68+
private static function getInputString(ConsoleEvent $event)
69+
{
70+
$commandName = $event->getCommand()->getName();
71+
$input = $event->getInput();
72+
73+
if (method_exists($input, '__toString')) {
74+
return str_replace(array("'$commandName'", "\"$commandName\""), $commandName, (string) $input);
75+
}
76+
77+
return $commandName;
78+
}
9079
}

src/Symfony/Component/Console/Tests/EventListener/ExceptionListenerTest.php

+55-28
Original file line numberDiff line numberDiff line change
@@ -16,83 +16,110 @@
1616
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
1717
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
1818
use Symfony\Component\Console\EventListener\ExceptionListener;
19+
use Symfony\Component\Console\Input\ArgvInput;
1920
use Symfony\Component\Console\Input\ArrayInput;
20-
use Symfony\Component\Console\Tests\Output\TestOutput;
21+
use Symfony\Component\Console\Input\StringInput;
22+
use Symfony\Component\Console\Input\InputInterface;
23+
use Symfony\Component\Console\Output\OutputInterface;
2124

2225
class ExceptionListenerTest extends \PHPUnit_Framework_TestCase
2326
{
24-
public function testOnKernelException()
27+
public function testOnConsoleException()
2528
{
26-
$logger = $this->getLogger();
27-
$listener = new ExceptionListener($logger);
28-
2929
$exception = new \RuntimeException('An error occurred');
3030

31+
$logger = $this->getLogger();
3132
$logger
3233
->expects($this->once())
3334
->method('error')
34-
->with('Exception thrown while running command: "{command}". Message: "{message}"', array('exception' => $exception, 'command' => '\'test:run\' --foo=baz buzz', 'message' => 'An error occurred'))
35+
->with('Exception thrown while running command "{command}". Message: "{message}"', array('exception' => $exception, 'command' => 'test:run --foo=baz buzz', 'message' => 'An error occurred'))
3536
;
3637

37-
$input = array(
38-
'name' => 'test:run',
39-
'--foo' => 'baz',
40-
'bar' => 'buzz'
41-
);
42-
43-
$listener->onKernelException($this->getConsoleExceptionEvent($exception, $input, 1));
38+
$listener = new ExceptionListener($logger);
39+
$listener->onConsoleException($this->getConsoleExceptionEvent($exception, new ArgvInput(array('console.php', 'test:run', '--foo=baz', 'buzz')), 1));
4440
}
4541

46-
public function testOnKernelTerminateForNonZeroExitCodeWritesToLog()
42+
public function testOnConsoleTerminateForNonZeroExitCodeWritesToLog()
4743
{
4844
$logger = $this->getLogger();
49-
$listener = new ExceptionListener($logger);
50-
5145
$logger
5246
->expects($this->once())
5347
->method('error')
54-
->with('Command "{command}" exited with status code "{code}"', array('command' => '\'test:run\'', 'code' => 255))
48+
->with('Command "{command}" exited with code "{code}"', array('command' => 'test:run', 'code' => 255))
5549
;
5650

57-
$listener->onKernelTerminate($this->getConsoleTerminateEvent(array('name' => 'test:run'), 255));
51+
$listener = new ExceptionListener($logger);
52+
$listener->onConsoleTerminate($this->getConsoleTerminateEvent(new ArgvInput(array('console.php', 'test:run')), 255));
5853
}
5954

60-
public function testOnKernelTerminateForZeroExitCodeDoesNotWriteToLog()
55+
public function testOnConsoleTerminateForZeroExitCodeDoesNotWriteToLog()
6156
{
6257
$logger = $this->getLogger();
63-
$listener = new ExceptionListener($logger);
64-
6558
$logger
6659
->expects($this->never())
6760
->method('error')
6861
;
6962

70-
$listener->onKernelTerminate($this->getConsoleTerminateEvent(array('name' => 'test:run'), 0));
63+
$listener = new ExceptionListener($logger);
64+
$listener->onConsoleTerminate($this->getConsoleTerminateEvent(new ArgvInput(array('console.php', 'test:run')), 0));
7165
}
7266

7367
public function testGetSubscribedEvents()
7468
{
7569
$this->assertEquals(
7670
array(
77-
'console.exception' => array('onKernelException', -128),
78-
'console.terminate' => array('onKernelTerminate', -128),
71+
'console.exception' => array('onConsoleException', -128),
72+
'console.terminate' => array('onConsoleTerminate', -128),
7973
),
8074
ExceptionListener::getSubscribedEvents()
8175
);
8276
}
8377

78+
public function testAllKindsOfInputCanBeLogged()
79+
{
80+
$logger = $this->getLogger();
81+
$logger
82+
->expects($this->exactly(3))
83+
->method('error')
84+
->with('Command "{command}" exited with code "{code}"', array('command' => 'test:run --foo=bar', 'code' => 255))
85+
;
86+
87+
$listener = new ExceptionListener($logger);
88+
$listener->onConsoleTerminate($this->getConsoleTerminateEvent(new ArgvInput(array('console.php', 'test:run', '--foo=bar')), 255));
89+
$listener->onConsoleTerminate($this->getConsoleTerminateEvent(new ArrayInput(array('name' => 'test:run', '--foo' => 'bar')), 255));
90+
$listener->onConsoleTerminate($this->getConsoleTerminateEvent(new StringInput('test:run --foo=bar'), 255));
91+
}
92+
93+
public function testCommandNameIsDisplayedForNonStringableInput()
94+
{
95+
$logger = $this->getLogger();
96+
$logger
97+
->expects($this->once())
98+
->method('error')
99+
->with('Command "{command}" exited with code "{code}"', array('command' => 'test:run', 'code' => 255))
100+
;
101+
102+
$listener = new ExceptionListener($logger);
103+
$listener->onConsoleTerminate($this->getConsoleTerminateEvent($this->getMockBuilder(InputInterface::class)->getMock(), 255));
104+
}
105+
84106
private function getLogger()
85107
{
86108
return $this->getMockForAbstractClass(LoggerInterface::class);
87109
}
88110

89-
private function getConsoleExceptionEvent(\Exception $exception, $input, $exitCode)
111+
private function getConsoleExceptionEvent(\Exception $exception, InputInterface $input, $exitCode)
112+
{
113+
return new ConsoleExceptionEvent(new Command('test:run'), $input, $this->getOutput(), $exception, $exitCode);
114+
}
115+
116+
private function getConsoleTerminateEvent(InputInterface $input, $exitCode)
90117
{
91-
return new ConsoleExceptionEvent(new Command('test:run'), new ArrayInput($input), new TestOutput(), $exception, $exitCode);
118+
return new ConsoleTerminateEvent(new Command('test:run'), $input, $this->getOutput(), $exitCode);
92119
}
93120

94-
private function getConsoleTerminateEvent($input, $exitCode)
121+
private function getOutput()
95122
{
96-
return new ConsoleTerminateEvent(new Command('test:run'), new ArrayInput($input), new TestOutput(), $exitCode);
123+
return $this->getMockBuilder(OutputInterface::class)->getMock();
97124
}
98125
}

0 commit comments

Comments
 (0)