[FrameworkBundle] Add Event Dispatcher debug command

This commit is contained in:
Matthieu Auger 2014-07-15 22:36:02 +02:00 committed by Matthieu Auger
parent 8725243a88
commit ce53c8a00b
44 changed files with 778 additions and 0 deletions

View File

@ -0,0 +1,84 @@
<?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\Bundle\FrameworkBundle\Command;
use Symfony\Bundle\FrameworkBundle\Console\Helper\DescriptorHelper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* A console command for retrieving information about event dispatcher
*
* @author Matthieu Auger <mail@matthieuauger.com>
*/
class EventDispatcherDebugCommand extends ContainerAwareCommand
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('debug:event-dispatcher')
->setDefinition(array(
new InputArgument('event', InputArgument::OPTIONAL, 'An event name (foo)'),
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'To output description in other formats', 'txt'),
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw description'),
))
->setDescription('Displays configured listeners for an application')
->setHelp(<<<EOF
The <info>%command.name%</info> command displays all configured listeners:
<info>php %command.full_name%</info>
To get specific listeners for an event, specify its name:
<info>php %command.full_name% kernel.request</info>
EOF
)
;
}
/**
* {@inheritdoc}
*
* @throws \LogicException
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
if ($event = $input->getArgument('event')) {
$options = array('event' => $event);
} else {
$options = array();
}
$dispatcher = $this->getEventDispatcher();
$helper = new DescriptorHelper();
$options['format'] = $input->getOption('format');
$options['raw_text'] = $input->getOption('raw');
$helper->describe($output, $dispatcher, $options);
}
/**
* Loads the Event Dispatcher from the container
*
* @return EventDispatcherInterface
*/
protected function getEventDispatcher()
{
return $this->getContainer()->get('event_dispatcher');
}
}

View File

@ -18,6 +18,7 @@ use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Routing\Route; use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\RouteCollection;
@ -66,6 +67,12 @@ abstract class Descriptor implements DescriptorInterface
case $object instanceof Alias: case $object instanceof Alias:
$this->describeContainerAlias($object, $options); $this->describeContainerAlias($object, $options);
break; break;
case $object instanceof EventDispatcherInterface:
$this->describeEventDispatcherListeners($object, $options);
break;
case is_callable($object):
$this->describeCallable($object, $options);
break;
default: default:
throw new \InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_class($object))); throw new \InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_class($object)));
} }
@ -176,6 +183,25 @@ abstract class Descriptor implements DescriptorInterface
*/ */
abstract protected function describeContainerParameter($parameter, array $options = array()); abstract protected function describeContainerParameter($parameter, array $options = array());
/**
* Describes event dispatcher listeners.
*
* Common options are:
* * name: name of listened event
*
* @param EventDispatcherInterface $eventDispatcher
* @param array $options
*/
abstract protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = array());
/**
* Describes a callable.
*
* @param callable $callable
* @param array $options
*/
abstract protected function describeCallable($callable, array $options = array());
/** /**
* Formats a value as string. * Formats a value as string.
* *

View File

@ -19,6 +19,7 @@ use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Routing\Route; use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\RouteCollection;
@ -134,6 +135,22 @@ class JsonDescriptor extends Descriptor
$this->writeData($this->getContainerAliasData($alias), $options); $this->writeData($this->getContainerAliasData($alias), $options);
} }
/**
* {@inheritdoc}
*/
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = array())
{
$this->writeData($this->getEventDispatcherListenersData($eventDispatcher, array_key_exists('event', $options) ? $options['event'] : null), $options);
}
/**
* {@inheritdoc}
*/
protected function describeCallable($callable, array $options = array())
{
$this->writeData($this->getCallableData($callable, $options), $options);
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -222,4 +239,96 @@ class JsonDescriptor extends Descriptor
'public' => $alias->isPublic(), 'public' => $alias->isPublic(),
); );
} }
/**
* @param EventDispatcherInterface $eventDispatcher
* @param string|null $event
*
* @return array
*/
private function getEventDispatcherListenersData(EventDispatcherInterface $eventDispatcher, $event = null)
{
$data = array();
$registeredListeners = $eventDispatcher->getListeners($event);
if (null !== $event) {
foreach ($registeredListeners as $listener) {
$data[] = $this->getCallableData($listener);
}
} else {
ksort($registeredListeners);
foreach ($registeredListeners as $eventListened => $eventListeners) {
foreach ($eventListeners as $eventListener) {
$data[$eventListened][] = $this->getCallableData($eventListener);
}
}
}
return $data;
}
/**
* @param callable $callable
* @param array $options
*
* @return array
*/
private function getCallableData($callable, array $options = array())
{
$data = array();
if (is_array($callable)) {
$data['type'] = 'function';
if (is_object($callable[0])) {
$data['name'] = $callable[1];
$data['class'] = get_class($callable[0]);
} else {
if (0 !== strpos($callable[1], 'parent::')) {
$data['name'] = $callable[1];
$data['class'] = $callable[0];
$data['static'] = true;
} else {
$data['name'] = substr($callable[1], 8);
$data['class'] = $callable[0];
$data['static'] = true;
$data['parent'] = true;
}
}
return $data;
}
if (is_string($callable)) {
$data['type'] = 'function';
if (false === strpos($callable, '::')) {
$data['name'] = $callable;
} else {
$callableParts = explode('::', $callable);
$data['name'] = $callableParts[1];
$data['class'] = $callableParts[0];
$data['static'] = true;
}
return $data;
}
if ($callable instanceof \Closure) {
$data['type'] = 'closure';
return $data;
}
if (method_exists($callable, '__invoke')) {
$data['type'] = 'object';
$data['name'] = get_class($callable);
return $data;
}
throw new \InvalidArgumentException('Callable is not describable.');
}
} }

View File

@ -15,6 +15,7 @@ use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Routing\Route; use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\RouteCollection;
@ -215,6 +216,106 @@ class MarkdownDescriptor extends Descriptor
$this->write(isset($options['parameter']) ? sprintf("%s\n%s\n\n%s", $options['parameter'], str_repeat('=', strlen($options['parameter'])), $this->formatParameter($parameter)): $parameter); $this->write(isset($options['parameter']) ? sprintf("%s\n%s\n\n%s", $options['parameter'], str_repeat('=', strlen($options['parameter'])), $this->formatParameter($parameter)): $parameter);
} }
/**
* {@inheritdoc}
*/
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = array())
{
$event = array_key_exists('event', $options) ? $options['event'] : null;
$title = 'Registered listeners';
if (null !== $event) {
$title .= sprintf(' for event `%s` ordered by descending priority', $event);
}
$this->write(sprintf('# %s', $title)."\n");
$registeredListeners = $eventDispatcher->getListeners($event);
if (null !== $event) {
foreach ($registeredListeners as $order => $listener) {
$this->write("\n".sprintf('## Listener %d', $order + 1)."\n");
$this->describeCallable($listener);
}
} else {
ksort($registeredListeners);
foreach ($registeredListeners as $eventListened => $eventListeners) {
$this->write("\n".sprintf('## %s', $eventListened)."\n");
foreach ($eventListeners as $order => $eventListener) {
$this->write("\n".sprintf('### Listener %d', $order + 1)."\n");
$this->describeCallable($eventListener);
}
}
}
}
/**
* {@inheritdoc}
*/
protected function describeCallable($callable, array $options = array())
{
$string = '';
if (is_array($callable)) {
$string .= "\n- Type: `function`";
if (is_object($callable[0])) {
$string .= "\n".sprintf('- Name: `%s`', $callable[1]);
$string .= "\n".sprintf('- Class: `%s`', get_class($callable[0]));
} else {
if (0 !== strpos($callable[1], 'parent::')) {
$string .= "\n".sprintf('- Name: `%s`', $callable[1]);
$string .= "\n".sprintf('- Class: `%s`', $callable[0]);
$string .= "\n- Static: yes";
} else {
$string .= "\n".sprintf('- Name: `%s`', substr($callable[1], 8));
$string .= "\n".sprintf('- Class: `%s`', $callable[0]);
$string .= "\n- Static: yes";
$string .= "\n- Parent: yes";
}
}
return $this->write($string."\n");
}
if (is_string($callable)) {
$string .= "\n- Type: `function`";
if (false === strpos($callable, '::')) {
$string .= "\n".sprintf('- Name: `%s`', $callable);
} else {
$callableParts = explode('::', $callable);
$string .= "\n".sprintf('- Name: `%s`', $callableParts[1]);
$string .= "\n".sprintf('- Class: `%s`', $callableParts[0]);
$string .= "\n- Static: yes";
}
return $this->write($string."\n");
}
if ($callable instanceof \Closure) {
$string .= "\n- Type: `closure`";
return $this->write($string."\n");
}
if (method_exists($callable, '__invoke')) {
$string .= "\n- Type: `object`";
$string .= "\n".sprintf('- Name: `%s`', get_class($callable));
return $this->write($string."\n");
}
throw new \InvalidArgumentException('Callable is not describable.');
}
/**
* @param array $array
*
* @return string
*/
private function formatRouterConfig(array $array) private function formatRouterConfig(array $array)
{ {
if (!count($array)) { if (!count($array)) {

View File

@ -16,6 +16,7 @@ use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Routing\Route; use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\RouteCollection;
@ -284,6 +285,58 @@ class TextDescriptor extends Descriptor
$this->writeText($this->formatParameter($parameter), $options); $this->writeText($this->formatParameter($parameter), $options);
} }
/**
* {@inheritdoc}
*/
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = array())
{
$event = array_key_exists('event', $options) ? $options['event'] : null;
$label = 'Registered listeners';
if (null !== $event) {
$label .= sprintf(' for event <info>%s</info>', $event);
} else {
$label .= ' by event';
}
$this->writeText($this->formatSection('event_dispatcher', $label)."\n", $options);
$registeredListeners = $eventDispatcher->getListeners($event);
if (null !== $event) {
$this->writeText("\n");
$table = new TableHelper();
$table->setHeaders(array('Order', 'Callable'));
foreach ($registeredListeners as $order => $listener) {
$table->addRow(array(sprintf('#%d', $order + 1), $this->formatCallable($listener)));
}
$this->renderTable($table);
} else {
ksort($registeredListeners);
foreach ($registeredListeners as $eventListened => $eventListeners) {
$this->writeText(sprintf("\n<info>[Event]</info> %s\n", $eventListened), $options);
$table = new TableHelper();
$table->setHeaders(array('Order', 'Callable'));
foreach ($eventListeners as $order => $eventListener) {
$table->addRow(array(sprintf('#%d', $order + 1), $this->formatCallable($eventListener)));
}
$this->renderTable($table);
}
}
}
/**
* {@inheritdoc}
*/
protected function describeCallable($callable, array $options = array())
{
$this->writeText($this->formatCallable($callable), $options);
}
/** /**
* @param array $array * @param array $array
* *
@ -311,6 +364,36 @@ class TextDescriptor extends Descriptor
return sprintf('<info>[%s]</info> %s', $section, $message); return sprintf('<info>[%s]</info> %s', $section, $message);
} }
/**
* @param callable $callable
*
* @return string
*/
private function formatCallable($callable)
{
if (is_array($callable)) {
if (is_object($callable[0])) {
return sprintf('%s::%s()', get_class($callable[0]), $callable[1]);
}
return sprintf('%s::%s()', $callable[0], $callable[1]);
}
if (is_string($callable)) {
return sprintf('%s()', $callable);
}
if ($callable instanceof \Closure) {
return '\Closure()';
}
if (method_exists($callable, '__invoke')) {
return sprintf('%s::__invoke()', get_class($callable));
}
throw new \InvalidArgumentException('Callable is not describable.');
}
/** /**
* @param string $content * @param string $content
* @param array $options * @param array $options

View File

@ -15,6 +15,7 @@ use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Routing\Route; use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\RouteCollection;
@ -91,6 +92,22 @@ class XmlDescriptor extends Descriptor
$this->writeDocument($this->getContainerAliasDocument($alias, isset($options['id']) ? $options['id'] : null)); $this->writeDocument($this->getContainerAliasDocument($alias, isset($options['id']) ? $options['id'] : null));
} }
/**
* {@inheritdoc}
*/
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = array())
{
$this->writeDocument($this->getEventDispatcherListenersDocument($eventDispatcher, array_key_exists('event', $options) ? $options['event'] : null));
}
/**
* {@inheritdoc}
*/
protected function describeCallable($callable, array $options = array())
{
$this->writeDocument($this->getCallableDocument($callable));
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -393,4 +410,104 @@ class XmlDescriptor extends Descriptor
return $dom; return $dom;
} }
/**
* @param EventDispatcherInterface $eventDispatcher
* @param string|null $event
*
* @return \DOMDocument
*/
private function getEventDispatcherListenersDocument(EventDispatcherInterface $eventDispatcher, $event = null)
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($eventDispatcherXML = $dom->createElement('event-dispatcher'));
$registeredListeners = $eventDispatcher->getListeners($event);
if (null !== $event) {
foreach ($registeredListeners as $listener) {
$callableXML = $this->getCallableDocument($listener);
$eventDispatcherXML->appendChild($eventDispatcherXML->ownerDocument->importNode($callableXML->childNodes->item(0), true));
}
} else {
ksort($registeredListeners);
foreach ($registeredListeners as $eventListened => $eventListeners) {
$eventDispatcherXML->appendChild($eventXML = $dom->createElement('event'));
$eventXML->setAttribute('name', $eventListened);
foreach ($eventListeners as $eventListener) {
$callableXML = $this->getCallableDocument($eventListener);
$eventXML->appendChild($eventXML->ownerDocument->importNode($callableXML->childNodes->item(0), true));
}
}
}
return $dom;
}
/**
* @param callable $callable
*
* @return \DOMDocument
*/
private function getCallableDocument($callable)
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($callableXML = $dom->createElement('callable'));
if (is_array($callable)) {
$callableXML->setAttribute('type', 'function');
if (is_object($callable[0])) {
$callableXML->setAttribute('name', $callable[1]);
$callableXML->setAttribute('class', get_class($callable[0]));
} else {
if (0 !== strpos($callable[1], 'parent::')) {
$callableXML->setAttribute('name', $callable[1]);
$callableXML->setAttribute('class', $callable[0]);
$callableXML->setAttribute('static', 'true');
} else {
$callableXML->setAttribute('name', substr($callable[1], 8));
$callableXML->setAttribute('class', $callable[0]);
$callableXML->setAttribute('static', 'true');
$callableXML->setAttribute('parent', 'true');
}
}
return $dom;
}
if (is_string($callable)) {
$callableXML->setAttribute('type', 'function');
if (false === strpos($callable, '::')) {
$callableXML->setAttribute('name', $callable);
} else {
$callableParts = explode('::', $callable);
$callableXML->setAttribute('name', $callableParts[1]);
$callableXML->setAttribute('class', $callableParts[0]);
$callableXML->setAttribute('static', 'true');
}
return $dom;
}
if ($callable instanceof \Closure) {
$callableXML->setAttribute('type', 'closure');
return $dom;
}
if (method_exists($callable, '__invoke')) {
$callableXML->setAttribute('type', 'object');
$callableXML->setAttribute('name', get_class($callable));
return $dom;
}
throw new \InvalidArgumentException('Callable is not describable.');
}
} }

View File

@ -16,6 +16,7 @@ use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Routing\Route; use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\RouteCollection;
@ -102,6 +103,28 @@ abstract class AbstractDescriptorTest extends \PHPUnit_Framework_TestCase
return $data; return $data;
} }
/** @dataProvider getDescribeEventDispatcherTestData */
public function testDescribeEventDispatcher(EventDispatcher $eventDispatcher, $expectedDescription, array $options)
{
$this->assertDescription($expectedDescription, $eventDispatcher, $options);
}
public function getDescribeEventDispatcherTestData()
{
return $this->getEventDispatcherDescriptionTestData(ObjectsProvider::getEventDispatchers());
}
/** @dataProvider getDescribeCallableTestData */
public function testDescribeCallable($callable, $expectedDescription)
{
$this->assertDescription($expectedDescription, $callable);
}
public function getDescribeCallableTestData()
{
return $this->getDescriptionTestData(ObjectsProvider::getCallables());
}
abstract protected function getDescriptor(); abstract protected function getDescriptor();
abstract protected function getFormat(); abstract protected function getFormat();
@ -148,4 +171,22 @@ abstract class AbstractDescriptorTest extends \PHPUnit_Framework_TestCase
return $data; return $data;
} }
private function getEventDispatcherDescriptionTestData(array $objects)
{
$variations = array(
'events' => array(),
'event1' => array('event' => 'event1'),
);
$data = array();
foreach ($objects as $name => $object) {
foreach ($variations as $suffix => $options) {
$description = file_get_contents(sprintf('%s/../../Fixtures/Descriptor/%s_%s.%s', __DIR__, $name, $suffix, $this->getFormat()));
$data[] = array($object, $description, $options);
}
}
return $data;
}
} }

View File

@ -15,6 +15,7 @@ use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Routing\Route; use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\RouteCollection;
@ -121,4 +122,48 @@ class ObjectsProvider
'alias_2' => new Alias('service_2', false), 'alias_2' => new Alias('service_2', false),
); );
} }
public static function getEventDispatchers()
{
$eventDispatcher = new EventDispatcher();
$eventDispatcher->addListener('event1', 'global_function');
$eventDispatcher->addListener('event1', function () { return 'Closure'; });
$eventDispatcher->addListener('event2', new CallableClass());
return array('event_dispatcher_1' => $eventDispatcher);
}
public static function getCallables()
{
return array(
'callable_1' => 'array_key_exists',
'callable_2' => array('Symfony\\Bundle\\FrameworkBundle\\Tests\\Console\\Descriptor\\CallableClass', 'staticMethod'),
'callable_3' => array(new CallableClass(), 'method'),
'callable_4' => 'Symfony\\Bundle\\FrameworkBundle\\Tests\\Console\\Descriptor\\CallableClass::staticMethod',
'callable_5' => array('Symfony\\Bundle\\FrameworkBundle\\Tests\\Console\\Descriptor\\ExtendedCallableClass', 'parent::staticMethod'),
'callable_6' => function () { return 'Closure'; },
'callable_7' => new CallableClass()
);
}
}
class CallableClass
{
public function __invoke()
{
}
public static function staticMethod()
{
}
public function method()
{
}
}
class ExtendedCallableClass extends CallableClass
{
public static function staticMethod()
{
}
} }

View File

@ -0,0 +1,4 @@
{
"type": "function",
"name": "array_key_exists"
}

View File

@ -0,0 +1,2 @@
- Type: `function`
- Name: `array_key_exists`

View File

@ -0,0 +1 @@
array_key_exists()

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<callable type="function" name="array_key_exists"/>

View File

@ -0,0 +1,6 @@
{
"type": "function",
"name": "staticMethod",
"class": "Symfony\\Bundle\\FrameworkBundle\\Tests\\Console\\Descriptor\\CallableClass",
"static": true
}

View File

@ -0,0 +1,4 @@
- Type: `function`
- Name: `staticMethod`
- Class: `Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass`
- Static: yes

View File

@ -0,0 +1 @@
Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass::staticMethod()

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<callable type="function" name="staticMethod" class="Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass" static="true"/>

View File

@ -0,0 +1,5 @@
{
"type": "function",
"name": "method",
"class": "Symfony\\Bundle\\FrameworkBundle\\Tests\\Console\\Descriptor\\CallableClass"
}

View File

@ -0,0 +1,3 @@
- Type: `function`
- Name: `method`
- Class: `Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass`

View File

@ -0,0 +1 @@
Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass::method()

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<callable type="function" name="method" class="Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass"/>

View File

@ -0,0 +1,6 @@
{
"type": "function",
"name": "staticMethod",
"class": "Symfony\\Bundle\\FrameworkBundle\\Tests\\Console\\Descriptor\\CallableClass",
"static": true
}

View File

@ -0,0 +1,4 @@
- Type: `function`
- Name: `staticMethod`
- Class: `Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass`
- Static: yes

View File

@ -0,0 +1 @@
Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass::staticMethod()

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<callable type="function" name="staticMethod" class="Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass" static="true"/>

View File

@ -0,0 +1,7 @@
{
"type": "function",
"name": "staticMethod",
"class": "Symfony\\Bundle\\FrameworkBundle\\Tests\\Console\\Descriptor\\ExtendedCallableClass",
"static": true,
"parent": true
}

View File

@ -0,0 +1,5 @@
- Type: `function`
- Name: `staticMethod`
- Class: `Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\ExtendedCallableClass`
- Static: yes
- Parent: yes

View File

@ -0,0 +1 @@
Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\ExtendedCallableClass::parent::staticMethod()

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<callable type="function" name="staticMethod" class="Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\ExtendedCallableClass" static="true" parent="true"/>

View File

@ -0,0 +1,3 @@
{
"type": "closure"
}

View File

@ -0,0 +1 @@
- Type: `closure`

View File

@ -0,0 +1 @@
\Closure()

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<callable type="closure"/>

View File

@ -0,0 +1,4 @@
{
"type": "object",
"name": "Symfony\\Bundle\\FrameworkBundle\\Tests\\Console\\Descriptor\\CallableClass"
}

View File

@ -0,0 +1,3 @@
- Type: `object`
- Name: `Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass`

View File

@ -0,0 +1 @@
Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass::__invoke()

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<callable type="object" name="Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass"/>

View File

@ -0,0 +1,9 @@
[
{
"type": "function",
"name": "global_function"
},
{
"type": "closure"
}
]

View File

@ -0,0 +1,10 @@
# Registered listeners for event `event1` ordered by descending priority
## Listener 1
- Type: `function`
- Name: `global_function`
## Listener 2
- Type: `closure`

View File

@ -0,0 +1,8 @@
<info>[event_dispatcher]</info> Registered listeners for event <info>event1</info>
+-------+-------------------+
| Order | Callable |
+-------+-------------------+
| #1 | global_function() |
| #2 | \Closure() |
+-------+-------------------+

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<event-dispatcher>
<callable type="function" name="global_function"/>
<callable type="closure"/>
</event-dispatcher>

View File

@ -0,0 +1,17 @@
{
"event1": [
{
"type": "function",
"name": "global_function"
},
{
"type": "closure"
}
],
"event2": [
{
"type": "object",
"name": "Symfony\\Bundle\\FrameworkBundle\\Tests\\Console\\Descriptor\\CallableClass"
}
]
}

View File

@ -0,0 +1,19 @@
# Registered listeners
## event1
### Listener 1
- Type: `function`
- Name: `global_function`
### Listener 2
- Type: `closure`
## event2
### Listener 1
- Type: `object`
- Name: `Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass`

View File

@ -0,0 +1,16 @@
<info>[event_dispatcher]</info> Registered listeners by event
<info>[Event]</info> event1
+-------+-------------------+
| Order | Callable |
+-------+-------------------+
| #1 | global_function() |
| #2 | \Closure() |
+-------+-------------------+
<info>[Event]</info> event2
+-------+-----------------------------------------------------------------------------------+
| Order | Callable |
+-------+-----------------------------------------------------------------------------------+
| #1 | Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass::__invoke() |
+-------+-----------------------------------------------------------------------------------+

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<event-dispatcher>
<event name="event1">
<callable type="function" name="global_function"/>
<callable type="closure"/>
</event>
<event name="event2">
<callable type="object" name="Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass"/>
</event>
</event-dispatcher>