Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit ce53c8a

Browse filesBrowse files
Matthieu Augermatthieuauger
authored andcommitted
[FrameworkBundle] Add Event Dispatcher debug command
1 parent 8725243 commit ce53c8a
Copy full SHA for ce53c8a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Dismiss banner
Expand file treeCollapse file tree

44 files changed

+778
-0
lines changed
+84Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Bundle\FrameworkBundle\Command;
13+
14+
use Symfony\Bundle\FrameworkBundle\Console\Helper\DescriptorHelper;
15+
use Symfony\Component\Console\Input\InputArgument;
16+
use Symfony\Component\Console\Input\InputOption;
17+
use Symfony\Component\Console\Input\InputInterface;
18+
use Symfony\Component\Console\Output\OutputInterface;
19+
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
20+
21+
/**
22+
* A console command for retrieving information about event dispatcher
23+
*
24+
* @author Matthieu Auger <mail@matthieuauger.com>
25+
*/
26+
class EventDispatcherDebugCommand extends ContainerAwareCommand
27+
{
28+
/**
29+
* {@inheritdoc}
30+
*/
31+
protected function configure()
32+
{
33+
$this
34+
->setName('debug:event-dispatcher')
35+
->setDefinition(array(
36+
new InputArgument('event', InputArgument::OPTIONAL, 'An event name (foo)'),
37+
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'To output description in other formats', 'txt'),
38+
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw description'),
39+
))
40+
->setDescription('Displays configured listeners for an application')
41+
->setHelp(<<<EOF
42+
The <info>%command.name%</info> command displays all configured listeners:
43+
44+
<info>php %command.full_name%</info>
45+
46+
To get specific listeners for an event, specify its name:
47+
48+
<info>php %command.full_name% kernel.request</info>
49+
EOF
50+
)
51+
;
52+
}
53+
54+
/**
55+
* {@inheritdoc}
56+
*
57+
* @throws \LogicException
58+
*/
59+
protected function execute(InputInterface $input, OutputInterface $output)
60+
{
61+
if ($event = $input->getArgument('event')) {
62+
$options = array('event' => $event);
63+
} else {
64+
$options = array();
65+
}
66+
67+
$dispatcher = $this->getEventDispatcher();
68+
69+
$helper = new DescriptorHelper();
70+
$options['format'] = $input->getOption('format');
71+
$options['raw_text'] = $input->getOption('raw');
72+
$helper->describe($output, $dispatcher, $options);
73+
}
74+
75+
/**
76+
* Loads the Event Dispatcher from the container
77+
*
78+
* @return EventDispatcherInterface
79+
*/
80+
protected function getEventDispatcher()
81+
{
82+
return $this->getContainer()->get('event_dispatcher');
83+
}
84+
}

‎src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php
+26Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Symfony\Component\DependencyInjection\ContainerBuilder;
1919
use Symfony\Component\DependencyInjection\Definition;
2020
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
21+
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
2122
use Symfony\Component\Routing\Route;
2223
use Symfony\Component\Routing\RouteCollection;
2324

@@ -66,6 +67,12 @@ public function describe(OutputInterface $output, $object, array $options = arra
6667
case $object instanceof Alias:
6768
$this->describeContainerAlias($object, $options);
6869
break;
70+
case $object instanceof EventDispatcherInterface:
71+
$this->describeEventDispatcherListeners($object, $options);
72+
break;
73+
case is_callable($object):
74+
$this->describeCallable($object, $options);
75+
break;
6976
default:
7077
throw new \InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_class($object)));
7178
}
@@ -176,6 +183,25 @@ abstract protected function describeContainerAlias(Alias $alias, array $options
176183
*/
177184
abstract protected function describeContainerParameter($parameter, array $options = array());
178185

186+
/**
187+
* Describes event dispatcher listeners.
188+
*
189+
* Common options are:
190+
* * name: name of listened event
191+
*
192+
* @param EventDispatcherInterface $eventDispatcher
193+
* @param array $options
194+
*/
195+
abstract protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = array());
196+
197+
/**
198+
* Describes a callable.
199+
*
200+
* @param callable $callable
201+
* @param array $options
202+
*/
203+
abstract protected function describeCallable($callable, array $options = array());
204+
179205
/**
180206
* Formats a value as string.
181207
*

‎src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php
+109Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\DependencyInjection\ContainerBuilder;
2020
use Symfony\Component\DependencyInjection\Definition;
2121
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
22+
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
2223
use Symfony\Component\Routing\Route;
2324
use Symfony\Component\Routing\RouteCollection;
2425

@@ -134,6 +135,22 @@ protected function describeContainerAlias(Alias $alias, array $options = array()
134135
$this->writeData($this->getContainerAliasData($alias), $options);
135136
}
136137

138+
/**
139+
* {@inheritdoc}
140+
*/
141+
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = array())
142+
{
143+
$this->writeData($this->getEventDispatcherListenersData($eventDispatcher, array_key_exists('event', $options) ? $options['event'] : null), $options);
144+
}
145+
146+
/**
147+
* {@inheritdoc}
148+
*/
149+
protected function describeCallable($callable, array $options = array())
150+
{
151+
$this->writeData($this->getCallableData($callable, $options), $options);
152+
}
153+
137154
/**
138155
* {@inheritdoc}
139156
*/
@@ -222,4 +239,96 @@ private function getContainerAliasData(Alias $alias)
222239
'public' => $alias->isPublic(),
223240
);
224241
}
242+
243+
/**
244+
* @param EventDispatcherInterface $eventDispatcher
245+
* @param string|null $event
246+
*
247+
* @return array
248+
*/
249+
private function getEventDispatcherListenersData(EventDispatcherInterface $eventDispatcher, $event = null)
250+
{
251+
$data = array();
252+
253+
$registeredListeners = $eventDispatcher->getListeners($event);
254+
if (null !== $event) {
255+
foreach ($registeredListeners as $listener) {
256+
$data[] = $this->getCallableData($listener);
257+
}
258+
} else {
259+
ksort($registeredListeners);
260+
261+
foreach ($registeredListeners as $eventListened => $eventListeners) {
262+
foreach ($eventListeners as $eventListener) {
263+
$data[$eventListened][] = $this->getCallableData($eventListener);
264+
}
265+
}
266+
}
267+
268+
return $data;
269+
}
270+
271+
/**
272+
* @param callable $callable
273+
* @param array $options
274+
*
275+
* @return array
276+
*/
277+
private function getCallableData($callable, array $options = array())
278+
{
279+
$data = array();
280+
281+
if (is_array($callable)) {
282+
$data['type'] = 'function';
283+
284+
if (is_object($callable[0])) {
285+
$data['name'] = $callable[1];
286+
$data['class'] = get_class($callable[0]);
287+
} else {
288+
if (0 !== strpos($callable[1], 'parent::')) {
289+
$data['name'] = $callable[1];
290+
$data['class'] = $callable[0];
291+
$data['static'] = true;
292+
} else {
293+
$data['name'] = substr($callable[1], 8);
294+
$data['class'] = $callable[0];
295+
$data['static'] = true;
296+
$data['parent'] = true;
297+
}
298+
}
299+
300+
return $data;
301+
}
302+
303+
if (is_string($callable)) {
304+
$data['type'] = 'function';
305+
306+
if (false === strpos($callable, '::')) {
307+
$data['name'] = $callable;
308+
} else {
309+
$callableParts = explode('::', $callable);
310+
311+
$data['name'] = $callableParts[1];
312+
$data['class'] = $callableParts[0];
313+
$data['static'] = true;
314+
}
315+
316+
return $data;
317+
}
318+
319+
if ($callable instanceof \Closure) {
320+
$data['type'] = 'closure';
321+
322+
return $data;
323+
}
324+
325+
if (method_exists($callable, '__invoke')) {
326+
$data['type'] = 'object';
327+
$data['name'] = get_class($callable);
328+
329+
return $data;
330+
}
331+
332+
throw new \InvalidArgumentException('Callable is not describable.');
333+
}
225334
}

‎src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php
+101Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\DependencyInjection\ContainerBuilder;
1616
use Symfony\Component\DependencyInjection\Definition;
1717
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
18+
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
1819
use Symfony\Component\Routing\Route;
1920
use Symfony\Component\Routing\RouteCollection;
2021

@@ -215,6 +216,106 @@ protected function describeContainerParameter($parameter, array $options = array
215216
$this->write(isset($options['parameter']) ? sprintf("%s\n%s\n\n%s", $options['parameter'], str_repeat('=', strlen($options['parameter'])), $this->formatParameter($parameter)): $parameter);
216217
}
217218

219+
/**
220+
* {@inheritdoc}
221+
*/
222+
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = array())
223+
{
224+
$event = array_key_exists('event', $options) ? $options['event'] : null;
225+
226+
$title = 'Registered listeners';
227+
if (null !== $event) {
228+
$title .= sprintf(' for event `%s` ordered by descending priority', $event);
229+
}
230+
231+
$this->write(sprintf('# %s', $title)."\n");
232+
233+
$registeredListeners = $eventDispatcher->getListeners($event);
234+
if (null !== $event) {
235+
foreach ($registeredListeners as $order => $listener) {
236+
$this->write("\n".sprintf('## Listener %d', $order + 1)."\n");
237+
$this->describeCallable($listener);
238+
}
239+
} else {
240+
ksort($registeredListeners);
241+
242+
foreach ($registeredListeners as $eventListened => $eventListeners) {
243+
$this->write("\n".sprintf('## %s', $eventListened)."\n");
244+
245+
foreach ($eventListeners as $order => $eventListener) {
246+
$this->write("\n".sprintf('### Listener %d', $order + 1)."\n");
247+
$this->describeCallable($eventListener);
248+
}
249+
}
250+
}
251+
}
252+
253+
/**
254+
* {@inheritdoc}
255+
*/
256+
protected function describeCallable($callable, array $options = array())
257+
{
258+
$string = '';
259+
260+
if (is_array($callable)) {
261+
$string .= "\n- Type: `function`";
262+
263+
if (is_object($callable[0])) {
264+
$string .= "\n".sprintf('- Name: `%s`', $callable[1]);
265+
$string .= "\n".sprintf('- Class: `%s`', get_class($callable[0]));
266+
} else {
267+
if (0 !== strpos($callable[1], 'parent::')) {
268+
$string .= "\n".sprintf('- Name: `%s`', $callable[1]);
269+
$string .= "\n".sprintf('- Class: `%s`', $callable[0]);
270+
$string .= "\n- Static: yes";
271+
} else {
272+
$string .= "\n".sprintf('- Name: `%s`', substr($callable[1], 8));
273+
$string .= "\n".sprintf('- Class: `%s`', $callable[0]);
274+
$string .= "\n- Static: yes";
275+
$string .= "\n- Parent: yes";
276+
}
277+
}
278+
279+
return $this->write($string."\n");
280+
}
281+
282+
if (is_string($callable)) {
283+
$string .= "\n- Type: `function`";
284+
285+
if (false === strpos($callable, '::')) {
286+
$string .= "\n".sprintf('- Name: `%s`', $callable);
287+
} else {
288+
$callableParts = explode('::', $callable);
289+
290+
$string .= "\n".sprintf('- Name: `%s`', $callableParts[1]);
291+
$string .= "\n".sprintf('- Class: `%s`', $callableParts[0]);
292+
$string .= "\n- Static: yes";
293+
}
294+
295+
return $this->write($string."\n");
296+
}
297+
298+
if ($callable instanceof \Closure) {
299+
$string .= "\n- Type: `closure`";
300+
301+
return $this->write($string."\n");
302+
}
303+
304+
if (method_exists($callable, '__invoke')) {
305+
$string .= "\n- Type: `object`";
306+
$string .= "\n".sprintf('- Name: `%s`', get_class($callable));
307+
308+
return $this->write($string."\n");
309+
}
310+
311+
throw new \InvalidArgumentException('Callable is not describable.');
312+
}
313+
314+
/**
315+
* @param array $array
316+
*
317+
* @return string
318+
*/
218319
private function formatRouterConfig(array $array)
219320
{
220321
if (!count($array)) {

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.