[FrameworkBundle] Add Event Dispatcher debug command
This commit is contained in:
parent
8725243a88
commit
ce53c8a00b
@ -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');
|
||||||
|
}
|
||||||
|
}
|
@ -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.
|
||||||
*
|
*
|
||||||
|
@ -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.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)) {
|
||||||
|
@ -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
|
||||||
|
@ -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.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"name": "array_key_exists"
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
- Type: `function`
|
||||||
|
- Name: `array_key_exists`
|
@ -0,0 +1 @@
|
|||||||
|
array_key_exists()
|
@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<callable type="function" name="array_key_exists"/>
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"name": "staticMethod",
|
||||||
|
"class": "Symfony\\Bundle\\FrameworkBundle\\Tests\\Console\\Descriptor\\CallableClass",
|
||||||
|
"static": true
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
- Type: `function`
|
||||||
|
- Name: `staticMethod`
|
||||||
|
- Class: `Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass`
|
||||||
|
- Static: yes
|
@ -0,0 +1 @@
|
|||||||
|
Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass::staticMethod()
|
@ -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"/>
|
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"name": "method",
|
||||||
|
"class": "Symfony\\Bundle\\FrameworkBundle\\Tests\\Console\\Descriptor\\CallableClass"
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
- Type: `function`
|
||||||
|
- Name: `method`
|
||||||
|
- Class: `Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass`
|
@ -0,0 +1 @@
|
|||||||
|
Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass::method()
|
@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<callable type="function" name="method" class="Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass"/>
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"name": "staticMethod",
|
||||||
|
"class": "Symfony\\Bundle\\FrameworkBundle\\Tests\\Console\\Descriptor\\CallableClass",
|
||||||
|
"static": true
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
- Type: `function`
|
||||||
|
- Name: `staticMethod`
|
||||||
|
- Class: `Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass`
|
||||||
|
- Static: yes
|
@ -0,0 +1 @@
|
|||||||
|
Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass::staticMethod()
|
@ -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"/>
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"name": "staticMethod",
|
||||||
|
"class": "Symfony\\Bundle\\FrameworkBundle\\Tests\\Console\\Descriptor\\ExtendedCallableClass",
|
||||||
|
"static": true,
|
||||||
|
"parent": true
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
- Type: `function`
|
||||||
|
- Name: `staticMethod`
|
||||||
|
- Class: `Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\ExtendedCallableClass`
|
||||||
|
- Static: yes
|
||||||
|
- Parent: yes
|
@ -0,0 +1 @@
|
|||||||
|
Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\ExtendedCallableClass::parent::staticMethod()
|
@ -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"/>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"type": "closure"
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
- Type: `closure`
|
@ -0,0 +1 @@
|
|||||||
|
\Closure()
|
@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<callable type="closure"/>
|
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"name": "Symfony\\Bundle\\FrameworkBundle\\Tests\\Console\\Descriptor\\CallableClass"
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
- Type: `object`
|
||||||
|
- Name: `Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass`
|
||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass::__invoke()
|
@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<callable type="object" name="Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass"/>
|
@ -0,0 +1,9 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"name": "global_function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "closure"
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,10 @@
|
|||||||
|
# Registered listeners for event `event1` ordered by descending priority
|
||||||
|
|
||||||
|
## Listener 1
|
||||||
|
|
||||||
|
- Type: `function`
|
||||||
|
- Name: `global_function`
|
||||||
|
|
||||||
|
## Listener 2
|
||||||
|
|
||||||
|
- Type: `closure`
|
@ -0,0 +1,8 @@
|
|||||||
|
<info>[event_dispatcher]</info> Registered listeners for event <info>event1</info>
|
||||||
|
|
||||||
|
+-------+-------------------+
|
||||||
|
| Order | Callable |
|
||||||
|
+-------+-------------------+
|
||||||
|
| #1 | global_function() |
|
||||||
|
| #2 | \Closure() |
|
||||||
|
+-------+-------------------+
|
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<event-dispatcher>
|
||||||
|
<callable type="function" name="global_function"/>
|
||||||
|
<callable type="closure"/>
|
||||||
|
</event-dispatcher>
|
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"event1": [
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"name": "global_function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "closure"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"event2": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"name": "Symfony\\Bundle\\FrameworkBundle\\Tests\\Console\\Descriptor\\CallableClass"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -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`
|
@ -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() |
|
||||||
|
+-------+-----------------------------------------------------------------------------------+
|
@ -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>
|
Reference in New Issue
Block a user