N°6934 - Symfony 6.4 - upgrade Symfony bundles to 6.4 (#580)

* Update Symfony lib to version ~6.4.0
* Update code missing return type
* Add an iTop general configuration entry to store application secret (Symfony mandatory parameter)
* Use dependency injection in ExceptionListener & UserProvider classes
This commit is contained in:
bdalsass
2023-12-05 13:56:56 +01:00
committed by GitHub
parent 863ab4560c
commit 27ce51ab07
1392 changed files with 44869 additions and 27799 deletions

View File

@@ -15,9 +15,12 @@ use Symfony\Component\Config\Resource\ClassExistenceResource;
use Symfony\Component\Console\Descriptor\DescriptorInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass;
use Symfony\Component\DependencyInjection\Compiler\ServiceReferenceGraphEdge;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Routing\Route;
@@ -30,60 +33,40 @@ use Symfony\Component\Routing\RouteCollection;
*/
abstract class Descriptor implements DescriptorInterface
{
/**
* @var OutputInterface
*/
protected $output;
protected OutputInterface $output;
/**
* {@inheritdoc}
*/
public function describe(OutputInterface $output, $object, array $options = [])
public function describe(OutputInterface $output, mixed $object, array $options = []): void
{
$this->output = $output;
switch (true) {
case $object instanceof RouteCollection:
$this->describeRouteCollection($object, $options);
break;
case $object instanceof Route:
$this->describeRoute($object, $options);
break;
case $object instanceof ParameterBag:
$this->describeContainerParameters($object, $options);
break;
case $object instanceof ContainerBuilder && !empty($options['env-vars']):
$this->describeContainerEnvVars($this->getContainerEnvVars($object), $options);
break;
case $object instanceof ContainerBuilder && isset($options['group_by']) && 'tags' === $options['group_by']:
$this->describeContainerTags($object, $options);
break;
case $object instanceof ContainerBuilder && isset($options['id']):
$this->describeContainerService($this->resolveServiceDefinition($object, $options['id']), $options, $object);
break;
case $object instanceof ContainerBuilder && isset($options['parameter']):
$this->describeContainerParameter($object->resolveEnvPlaceholders($object->getParameter($options['parameter'])), $options);
break;
case $object instanceof ContainerBuilder && isset($options['deprecations']):
$this->describeContainerDeprecations($object, $options);
break;
case $object instanceof ContainerBuilder:
$this->describeContainerServices($object, $options);
break;
case $object instanceof Definition:
$this->describeContainerDefinition($object, $options);
break;
case $object instanceof Alias:
$this->describeContainerAlias($object, $options);
break;
case $object instanceof EventDispatcherInterface:
$this->describeEventDispatcherListeners($object, $options);
break;
case \is_callable($object):
$this->describeCallable($object, $options);
break;
default:
throw new \InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_debug_type($object)));
if ($object instanceof ContainerBuilder) {
(new AnalyzeServiceReferencesPass(false, false))->process($object);
}
$deprecatedParameters = [];
if ($object instanceof ContainerBuilder && isset($options['parameter']) && ($parameterBag = $object->getParameterBag()) instanceof ParameterBag) {
$deprecatedParameters = $parameterBag->allDeprecated();
}
match (true) {
$object instanceof RouteCollection => $this->describeRouteCollection($object, $options),
$object instanceof Route => $this->describeRoute($object, $options),
$object instanceof ParameterBag => $this->describeContainerParameters($object, $options),
$object instanceof ContainerBuilder && !empty($options['env-vars']) => $this->describeContainerEnvVars($this->getContainerEnvVars($object), $options),
$object instanceof ContainerBuilder && isset($options['group_by']) && 'tags' === $options['group_by'] => $this->describeContainerTags($object, $options),
$object instanceof ContainerBuilder && isset($options['id']) => $this->describeContainerService($this->resolveServiceDefinition($object, $options['id']), $options, $object),
$object instanceof ContainerBuilder && isset($options['parameter']) => $this->describeContainerParameter($object->resolveEnvPlaceholders($object->getParameter($options['parameter'])), $deprecatedParameters[$options['parameter']] ?? null, $options),
$object instanceof ContainerBuilder && isset($options['deprecations']) => $this->describeContainerDeprecations($object, $options),
$object instanceof ContainerBuilder => $this->describeContainerServices($object, $options),
$object instanceof Definition => $this->describeContainerDefinition($object, $options),
$object instanceof Alias => $this->describeContainerAlias($object, $options),
$object instanceof EventDispatcherInterface => $this->describeEventDispatcherListeners($object, $options),
\is_callable($object) => $this->describeCallable($object, $options),
default => throw new \InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_debug_type($object))),
};
if ($object instanceof ContainerBuilder) {
$object->getCompiler()->getServiceReferenceGraph()->clear();
}
}
@@ -92,18 +75,18 @@ abstract class Descriptor implements DescriptorInterface
return $this->output;
}
protected function write(string $content, bool $decorated = false)
protected function write(string $content, bool $decorated = false): void
{
$this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW);
}
abstract protected function describeRouteCollection(RouteCollection $routes, array $options = []);
abstract protected function describeRouteCollection(RouteCollection $routes, array $options = []): void;
abstract protected function describeRoute(Route $route, array $options = []);
abstract protected function describeRoute(Route $route, array $options = []): void;
abstract protected function describeContainerParameters(ParameterBag $parameters, array $options = []);
abstract protected function describeContainerParameters(ParameterBag $parameters, array $options = []): void;
abstract protected function describeContainerTags(ContainerBuilder $builder, array $options = []);
abstract protected function describeContainerTags(ContainerBuilder $container, array $options = []): void;
/**
* Describes a container service by its name.
@@ -113,7 +96,7 @@ abstract class Descriptor implements DescriptorInterface
*
* @param Definition|Alias|object $service
*/
abstract protected function describeContainerService(object $service, array $options = [], ContainerBuilder $builder = null);
abstract protected function describeContainerService(object $service, array $options = [], ContainerBuilder $container = null): void;
/**
* Describes container services.
@@ -121,17 +104,17 @@ abstract class Descriptor implements DescriptorInterface
* Common options are:
* * tag: filters described services by given tag
*/
abstract protected function describeContainerServices(ContainerBuilder $builder, array $options = []);
abstract protected function describeContainerServices(ContainerBuilder $container, array $options = []): void;
abstract protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void;
abstract protected function describeContainerDeprecations(ContainerBuilder $container, array $options = []): void;
abstract protected function describeContainerDefinition(Definition $definition, array $options = []);
abstract protected function describeContainerDefinition(Definition $definition, array $options = [], ContainerBuilder $container = null): void;
abstract protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $builder = null);
abstract protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $container = null): void;
abstract protected function describeContainerParameter($parameter, array $options = []);
abstract protected function describeContainerParameter(mixed $parameter, ?array $deprecation, array $options = []): void;
abstract protected function describeContainerEnvVars(array $envs, array $options = []);
abstract protected function describeContainerEnvVars(array $envs, array $options = []): void;
/**
* Describes event dispatcher listeners.
@@ -139,28 +122,18 @@ abstract class Descriptor implements DescriptorInterface
* Common options are:
* * name: name of listened event
*/
abstract protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = []);
abstract protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = []): void;
/**
* Describes a callable.
*
* @param mixed $callable
*/
abstract protected function describeCallable($callable, array $options = []);
abstract protected function describeCallable(mixed $callable, array $options = []): void;
/**
* Formats a value as string.
*
* @param mixed $value
*/
protected function formatValue($value): string
protected function formatValue(mixed $value): string
{
if ($value instanceof \UnitEnum) {
return ltrim(var_export($value, true), '\\');
}
if (\is_object($value)) {
return sprintf('object(%s)', \get_class($value));
return sprintf('object(%s)', $value::class);
}
if (\is_string($value)) {
@@ -170,12 +143,7 @@ abstract class Descriptor implements DescriptorInterface
return preg_replace("/\n\s*/s", '', var_export($value, true));
}
/**
* Formats a parameter.
*
* @param mixed $value
*/
protected function formatParameter($value): string
protected function formatParameter(mixed $value): string
{
if ($value instanceof \UnitEnum) {
return ltrim(var_export($value, true), '\\');
@@ -204,18 +172,15 @@ abstract class Descriptor implements DescriptorInterface
return (string) $value;
}
/**
* @return mixed
*/
protected function resolveServiceDefinition(ContainerBuilder $builder, string $serviceId)
protected function resolveServiceDefinition(ContainerBuilder $container, string $serviceId): mixed
{
if ($builder->hasDefinition($serviceId)) {
return $builder->getDefinition($serviceId);
if ($container->hasDefinition($serviceId)) {
return $container->getDefinition($serviceId);
}
// Some service IDs don't have a Definition, they're aliases
if ($builder->hasAlias($serviceId)) {
return $builder->getAlias($serviceId);
if ($container->hasAlias($serviceId)) {
return $container->getAlias($serviceId);
}
if ('service_container' === $serviceId) {
@@ -223,18 +188,18 @@ abstract class Descriptor implements DescriptorInterface
}
// the service has been injected in some special way, just return the service
return $builder->get($serviceId);
return $container->get($serviceId);
}
protected function findDefinitionsByTag(ContainerBuilder $builder, bool $showHidden): array
protected function findDefinitionsByTag(ContainerBuilder $container, bool $showHidden): array
{
$definitions = [];
$tags = $builder->findTags();
$tags = $container->findTags();
asort($tags);
foreach ($tags as $tag) {
foreach ($builder->findTaggedServiceIds($tag) as $serviceId => $attributes) {
$definition = $this->resolveServiceDefinition($builder, $serviceId);
foreach ($container->findTaggedServiceIds($tag) as $serviceId => $attributes) {
$definition = $this->resolveServiceDefinition($container, $serviceId);
if ($showHidden xor '.' === ($serviceId[0] ?? null)) {
continue;
@@ -251,7 +216,7 @@ abstract class Descriptor implements DescriptorInterface
return $definitions;
}
protected function sortParameters(ParameterBag $parameters)
protected function sortParameters(ParameterBag $parameters): array
{
$parameters = $parameters->all();
ksort($parameters);
@@ -259,7 +224,7 @@ abstract class Descriptor implements DescriptorInterface
return $parameters;
}
protected function sortServiceIds(array $serviceIds)
protected function sortServiceIds(array $serviceIds): array
{
asort($serviceIds);
@@ -278,9 +243,7 @@ abstract class Descriptor implements DescriptorInterface
}
}
}
uasort($maxPriority, function ($a, $b) {
return $b <=> $a;
});
uasort($maxPriority, fn ($a, $b) => $b <=> $a);
return array_keys($maxPriority);
}
@@ -297,13 +260,24 @@ abstract class Descriptor implements DescriptorInterface
protected function sortByPriority(array $tag): array
{
usort($tag, function ($a, $b) {
return ($b['priority'] ?? 0) <=> ($a['priority'] ?? 0);
});
usort($tag, fn ($a, $b) => ($b['priority'] ?? 0) <=> ($a['priority'] ?? 0));
return $tag;
}
/**
* @return array<string, string[]>
*/
protected function getReverseAliases(RouteCollection $routes): array
{
$reverseAliases = [];
foreach ($routes->getAliases() as $name => $alias) {
$reverseAliases[$alias->getId()][] = $name;
}
return $reverseAliases;
}
public static function getClassDescription(string $class, string &$resolvedClass = null): string
{
$resolvedClass = $class;
@@ -321,7 +295,7 @@ abstract class Descriptor implements DescriptorInterface
return trim(preg_replace('#\s*\n\s*\*\s*#', ' ', $docComment));
}
} catch (\ReflectionException $e) {
} catch (\ReflectionException) {
}
return '';
@@ -333,7 +307,7 @@ abstract class Descriptor implements DescriptorInterface
return [];
}
if (!is_file($container->getParameter('debug.container.dump'))) {
if (!$container->getParameter('debug.container.dump') || !is_file($container->getParameter('debug.container.dump'))) {
return [];
}
@@ -342,13 +316,10 @@ abstract class Descriptor implements DescriptorInterface
$envVars = array_unique($envVars[1]);
$bag = $container->getParameterBag();
$getDefaultParameter = function (string $name) {
return parent::get($name);
};
$getDefaultParameter = $getDefaultParameter->bindTo($bag, \get_class($bag));
$getDefaultParameter = fn (string $name) => parent::get($name);
$getDefaultParameter = $getDefaultParameter->bindTo($bag, $bag::class);
$getEnvReflection = new \ReflectionMethod($container, 'getEnv');
$getEnvReflection->setAccessible(true);
$envs = [];
@@ -377,4 +348,16 @@ abstract class Descriptor implements DescriptorInterface
return array_values($envs);
}
protected function getServiceEdges(ContainerBuilder $container, string $serviceId): array
{
try {
return array_values(array_unique(array_map(
fn (ServiceReferenceGraphEdge $edge) => $edge->getSourceNode()->getId(),
$container->getCompiler()->getServiceReferenceGraph()->getNode($serviceId)->getInEdges()
)));
} catch (InvalidArgumentException $exception) {
return [];
}
}
}

View File

@@ -32,61 +32,64 @@ use Symfony\Component\Routing\RouteCollection;
*/
class JsonDescriptor extends Descriptor
{
protected function describeRouteCollection(RouteCollection $routes, array $options = [])
protected function describeRouteCollection(RouteCollection $routes, array $options = []): void
{
$data = [];
foreach ($routes->all() as $name => $route) {
$data[$name] = $this->getRouteData($route);
}
$this->writeData($data, $options);
}
protected function describeRoute(Route $route, array $options = [])
{
$this->writeData($this->getRouteData($route), $options);
}
protected function describeContainerParameters(ParameterBag $parameters, array $options = [])
{
$this->writeData($this->sortParameters($parameters), $options);
}
protected function describeContainerTags(ContainerBuilder $builder, array $options = [])
{
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
$data = [];
foreach ($this->findDefinitionsByTag($builder, $showHidden) as $tag => $definitions) {
$data[$tag] = [];
foreach ($definitions as $definition) {
$data[$tag][] = $this->getContainerDefinitionData($definition, true);
if (($showAliases ??= $options['show_aliases'] ?? false) && $aliases = ($reverseAliases ??= $this->getReverseAliases($routes))[$name] ?? []) {
$data[$name]['aliases'] = $aliases;
}
}
$this->writeData($data, $options);
}
protected function describeContainerService(object $service, array $options = [], ContainerBuilder $builder = null)
protected function describeRoute(Route $route, array $options = []): void
{
$this->writeData($this->getRouteData($route), $options);
}
protected function describeContainerParameters(ParameterBag $parameters, array $options = []): void
{
$this->writeData($this->sortParameters($parameters), $options);
}
protected function describeContainerTags(ContainerBuilder $container, array $options = []): void
{
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
$data = [];
foreach ($this->findDefinitionsByTag($container, $showHidden) as $tag => $definitions) {
$data[$tag] = [];
foreach ($definitions as $definition) {
$data[$tag][] = $this->getContainerDefinitionData($definition, true, false, $container, $options['id'] ?? null);
}
}
$this->writeData($data, $options);
}
protected function describeContainerService(object $service, array $options = [], ContainerBuilder $container = null): void
{
if (!isset($options['id'])) {
throw new \InvalidArgumentException('An "id" option must be provided.');
}
if ($service instanceof Alias) {
$this->describeContainerAlias($service, $options, $builder);
$this->describeContainerAlias($service, $options, $container);
} elseif ($service instanceof Definition) {
$this->writeData($this->getContainerDefinitionData($service, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments']), $options);
$this->writeData($this->getContainerDefinitionData($service, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $container, $options['id']), $options);
} else {
$this->writeData(\get_class($service), $options);
$this->writeData($service::class, $options);
}
}
protected function describeContainerServices(ContainerBuilder $builder, array $options = [])
protected function describeContainerServices(ContainerBuilder $container, array $options = []): void
{
$serviceIds = isset($options['tag']) && $options['tag']
? $this->sortTaggedServicesByPriority($builder->findTaggedServiceIds($options['tag']))
: $this->sortServiceIds($builder->getServiceIds());
? $this->sortTaggedServicesByPriority($container->findTaggedServiceIds($options['tag']))
: $this->sortServiceIds($container->getServiceIds());
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
$omitTags = isset($options['omit_tags']) && $options['omit_tags'];
$showArguments = isset($options['show_arguments']) && $options['show_arguments'];
@@ -97,7 +100,7 @@ class JsonDescriptor extends Descriptor
}
foreach ($serviceIds as $serviceId) {
$service = $this->resolveServiceDefinition($builder, $serviceId);
$service = $this->resolveServiceDefinition($container, $serviceId);
if ($showHidden xor '.' === ($serviceId[0] ?? null)) {
continue;
@@ -106,59 +109,67 @@ class JsonDescriptor extends Descriptor
if ($service instanceof Alias) {
$data['aliases'][$serviceId] = $this->getContainerAliasData($service);
} elseif ($service instanceof Definition) {
$data['definitions'][$serviceId] = $this->getContainerDefinitionData($service, $omitTags, $showArguments);
if ($service->hasTag('container.excluded')) {
continue;
}
$data['definitions'][$serviceId] = $this->getContainerDefinitionData($service, $omitTags, $showArguments, $container, $serviceId);
} else {
$data['services'][$serviceId] = \get_class($service);
$data['services'][$serviceId] = $service::class;
}
}
$this->writeData($data, $options);
}
protected function describeContainerDefinition(Definition $definition, array $options = [])
protected function describeContainerDefinition(Definition $definition, array $options = [], ContainerBuilder $container = null): void
{
$this->writeData($this->getContainerDefinitionData($definition, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments']), $options);
$this->writeData($this->getContainerDefinitionData($definition, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $container, $options['id'] ?? null), $options);
}
protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $builder = null)
protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $container = null): void
{
if (!$builder) {
if (!$container) {
$this->writeData($this->getContainerAliasData($alias), $options);
return;
}
$this->writeData(
[$this->getContainerAliasData($alias), $this->getContainerDefinitionData($builder->getDefinition((string) $alias), isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'])],
[$this->getContainerAliasData($alias), $this->getContainerDefinitionData($container->getDefinition((string) $alias), isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $container, (string) $alias)],
array_merge($options, ['id' => (string) $alias])
);
}
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = [])
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = []): void
{
$this->writeData($this->getEventDispatcherListenersData($eventDispatcher, $options), $options);
}
protected function describeCallable($callable, array $options = [])
protected function describeCallable(mixed $callable, array $options = []): void
{
$this->writeData($this->getCallableData($callable), $options);
}
protected function describeContainerParameter($parameter, array $options = [])
protected function describeContainerParameter(mixed $parameter, ?array $deprecation, array $options = []): void
{
$key = $options['parameter'] ?? '';
$data = [$key => $parameter];
$this->writeData([$key => $parameter], $options);
if ($deprecation) {
$data['_deprecation'] = sprintf('Since %s %s: %s', $deprecation[0], $deprecation[1], sprintf(...\array_slice($deprecation, 2)));
}
$this->writeData($data, $options);
}
protected function describeContainerEnvVars(array $envs, array $options = [])
protected function describeContainerEnvVars(array $envs, array $options = []): void
{
throw new LogicException('Using the JSON format to debug environment variables is not supported.');
}
protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void
protected function describeContainerDeprecations(ContainerBuilder $container, array $options = []): void
{
$containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.build_dir'), $builder->getParameter('kernel.container_class'));
$containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $container->getParameter('kernel.build_dir'), $container->getParameter('kernel.container_class'));
if (!file_exists($containerDeprecationFilePath)) {
throw new RuntimeException('The deprecation file does not exist, please try warming the cache first.');
}
@@ -180,7 +191,7 @@ class JsonDescriptor extends Descriptor
$this->writeData(['remainingCount' => $remainingCount, 'deprecations' => $formattedLogs], $options);
}
private function writeData(array $data, array $options)
private function writeData(array $data, array $options): void
{
$flags = $options['json_encoding'] ?? 0;
@@ -204,7 +215,7 @@ class JsonDescriptor extends Descriptor
'hostRegex' => '' !== $route->getHost() ? $route->compile()->getHostRegex() : '',
'scheme' => $route->getSchemes() ? implode('|', $route->getSchemes()) : 'ANY',
'method' => $route->getMethods() ? implode('|', $route->getMethods()) : 'ANY',
'class' => \get_class($route),
'class' => $route::class,
'defaults' => $route->getDefaults(),
'requirements' => $route->getRequirements() ?: 'NO CUSTOM',
'options' => $route->getOptions(),
@@ -217,7 +228,24 @@ class JsonDescriptor extends Descriptor
return $data;
}
private function getContainerDefinitionData(Definition $definition, bool $omitTags = false, bool $showArguments = false): array
protected function sortParameters(ParameterBag $parameters): array
{
$sortedParameters = parent::sortParameters($parameters);
if ($deprecated = $parameters->allDeprecated()) {
$deprecations = [];
foreach ($deprecated as $parameter => $deprecation) {
$deprecations[$parameter] = sprintf('Since %s %s: %s', $deprecation[0], $deprecation[1], sprintf(...\array_slice($deprecation, 2)));
}
$sortedParameters['_deprecations'] = $deprecations;
}
return $sortedParameters;
}
private function getContainerDefinitionData(Definition $definition, bool $omitTags = false, bool $showArguments = false, ContainerBuilder $container = null, string $id = null): array
{
$data = [
'class' => (string) $definition->getClass(),
@@ -230,12 +258,19 @@ class JsonDescriptor extends Descriptor
'autoconfigure' => $definition->isAutoconfigured(),
];
if ($definition->isDeprecated()) {
$data['deprecated'] = true;
$data['deprecation_message'] = $definition->getDeprecation($id)['message'];
} else {
$data['deprecated'] = false;
}
if ('' !== $classDescription = $this->getClassDescription((string) $definition->getClass())) {
$data['description'] = $classDescription;
}
if ($showArguments) {
$data['arguments'] = $this->describeValue($definition->getArguments(), $omitTags, $showArguments);
$data['arguments'] = $this->describeValue($definition->getArguments(), $omitTags, $showArguments, $container, $id);
}
$data['file'] = $definition->getFile();
@@ -272,6 +307,8 @@ class JsonDescriptor extends Descriptor
}
}
$data['usages'] = null !== $container && null !== $id ? $this->getServiceEdges($container, $id) : [];
return $data;
}
@@ -295,7 +332,7 @@ class JsonDescriptor extends Descriptor
$data[] = $l;
}
} else {
$registeredListeners = \array_key_exists('events', $options) ? array_combine($options['events'], array_map(function ($event) use ($eventDispatcher) { return $eventDispatcher->getListeners($event); }, $options['events'])) : $eventDispatcher->getListeners();
$registeredListeners = \array_key_exists('events', $options) ? array_combine($options['events'], array_map(fn ($event) => $eventDispatcher->getListeners($event), $options['events'])) : $eventDispatcher->getListeners();
ksort($registeredListeners);
foreach ($registeredListeners as $eventListened => $eventListeners) {
@@ -310,7 +347,7 @@ class JsonDescriptor extends Descriptor
return $data;
}
private function getCallableData($callable): array
private function getCallableData(mixed $callable): array
{
$data = [];
@@ -319,7 +356,7 @@ class JsonDescriptor extends Descriptor
if (\is_object($callable[0])) {
$data['name'] = $callable[1];
$data['class'] = \get_class($callable[0]);
$data['class'] = $callable[0]::class;
} else {
if (!str_starts_with($callable[1], 'parent::')) {
$data['name'] = $callable[1];
@@ -373,7 +410,7 @@ class JsonDescriptor extends Descriptor
if (method_exists($callable, '__invoke')) {
$data['type'] = 'object';
$data['name'] = \get_class($callable);
$data['name'] = $callable::class;
return $data;
}
@@ -381,12 +418,12 @@ class JsonDescriptor extends Descriptor
throw new \InvalidArgumentException('Callable is not describable.');
}
private function describeValue($value, bool $omitTags, bool $showArguments)
private function describeValue($value, bool $omitTags, bool $showArguments, ContainerBuilder $container = null, string $id = null): mixed
{
if (\is_array($value)) {
$data = [];
foreach ($value as $k => $v) {
$data[$k] = $this->describeValue($v, $omitTags, $showArguments);
$data[$k] = $this->describeValue($v, $omitTags, $showArguments, $container, $id);
}
return $data;
@@ -408,11 +445,11 @@ class JsonDescriptor extends Descriptor
}
if ($value instanceof ArgumentInterface) {
return $this->describeValue($value->getValues(), $omitTags, $showArguments);
return $this->describeValue($value->getValues(), $omitTags, $showArguments, $container, $id);
}
if ($value instanceof Definition) {
return $this->getContainerDefinitionData($value, $omitTags, $showArguments);
return $this->getContainerDefinitionData($value, $omitTags, $showArguments, $container, $id);
}
return $value;

View File

@@ -29,7 +29,7 @@ use Symfony\Component\Routing\RouteCollection;
*/
class MarkdownDescriptor extends Descriptor
{
protected function describeRouteCollection(RouteCollection $routes, array $options = [])
protected function describeRouteCollection(RouteCollection $routes, array $options = []): void
{
$first = true;
foreach ($routes->all() as $name => $route) {
@@ -39,11 +39,14 @@ class MarkdownDescriptor extends Descriptor
$this->write("\n\n");
}
$this->describeRoute($route, ['name' => $name]);
if (($showAliases ??= $options['show_aliases'] ?? false) && $aliases = ($reverseAliases ??= $this->getReverseAliases($routes))[$name] ?? []) {
$this->write(sprintf("- Aliases: \n%s", implode("\n", array_map(static fn (string $alias): string => sprintf(' - %s', $alias), $aliases))));
}
}
$this->write("\n");
}
protected function describeRoute(Route $route, array $options = [])
protected function describeRoute(Route $route, array $options = []): void
{
$output = '- Path: '.$route->getPath()
."\n".'- Path Regex: '.$route->compile()->getRegex()
@@ -51,7 +54,7 @@ class MarkdownDescriptor extends Descriptor
."\n".'- Host Regex: '.('' !== $route->getHost() ? $route->compile()->getHostRegex() : '')
."\n".'- Scheme: '.($route->getSchemes() ? implode('|', $route->getSchemes()) : 'ANY')
."\n".'- Method: '.($route->getMethods() ? implode('|', $route->getMethods()) : 'ANY')
."\n".'- Class: '.\get_class($route)
."\n".'- Class: '.$route::class
."\n".'- Defaults: '.$this->formatRouterConfig($route->getDefaults())
."\n".'- Requirements: '.($route->getRequirements() ? $this->formatRouterConfig($route->getRequirements()) : 'NO CUSTOM')
."\n".'- Options: '.$this->formatRouterConfig($route->getOptions());
@@ -66,29 +69,36 @@ class MarkdownDescriptor extends Descriptor
$this->write("\n");
}
protected function describeContainerParameters(ParameterBag $parameters, array $options = [])
protected function describeContainerParameters(ParameterBag $parameters, array $options = []): void
{
$deprecatedParameters = $parameters->allDeprecated();
$this->write("Container parameters\n====================\n");
foreach ($this->sortParameters($parameters) as $key => $value) {
$this->write(sprintf("\n- `%s`: `%s`", $key, $this->formatParameter($value)));
$this->write(sprintf(
"\n- `%s`: `%s`%s",
$key,
$this->formatParameter($value),
isset($deprecatedParameters[$key]) ? sprintf(' *Since %s %s: %s*', $deprecatedParameters[$key][0], $deprecatedParameters[$key][1], sprintf(...\array_slice($deprecatedParameters[$key], 2))) : ''
));
}
}
protected function describeContainerTags(ContainerBuilder $builder, array $options = [])
protected function describeContainerTags(ContainerBuilder $container, array $options = []): void
{
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
$this->write("Container tags\n==============");
foreach ($this->findDefinitionsByTag($builder, $showHidden) as $tag => $definitions) {
foreach ($this->findDefinitionsByTag($container, $showHidden) as $tag => $definitions) {
$this->write("\n\n".$tag."\n".str_repeat('-', \strlen($tag)));
foreach ($definitions as $serviceId => $definition) {
$this->write("\n\n");
$this->describeContainerDefinition($definition, ['omit_tags' => true, 'id' => $serviceId]);
$this->describeContainerDefinition($definition, ['omit_tags' => true, 'id' => $serviceId], $container);
}
}
}
protected function describeContainerService(object $service, array $options = [], ContainerBuilder $builder = null)
protected function describeContainerService(object $service, array $options = [], ContainerBuilder $container = null): void
{
if (!isset($options['id'])) {
throw new \InvalidArgumentException('An "id" option must be provided.');
@@ -97,17 +107,17 @@ class MarkdownDescriptor extends Descriptor
$childOptions = array_merge($options, ['id' => $options['id'], 'as_array' => true]);
if ($service instanceof Alias) {
$this->describeContainerAlias($service, $childOptions, $builder);
$this->describeContainerAlias($service, $childOptions, $container);
} elseif ($service instanceof Definition) {
$this->describeContainerDefinition($service, $childOptions);
$this->describeContainerDefinition($service, $childOptions, $container);
} else {
$this->write(sprintf('**`%s`:** `%s`', $options['id'], \get_class($service)));
$this->write(sprintf('**`%s`:** `%s`', $options['id'], $service::class));
}
}
protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void
protected function describeContainerDeprecations(ContainerBuilder $container, array $options = []): void
{
$containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.build_dir'), $builder->getParameter('kernel.container_class'));
$containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $container->getParameter('kernel.build_dir'), $container->getParameter('kernel.container_class'));
if (!file_exists($containerDeprecationFilePath)) {
throw new RuntimeException('The deprecation file does not exist, please try warming the cache first.');
}
@@ -132,7 +142,7 @@ class MarkdownDescriptor extends Descriptor
}
}
protected function describeContainerServices(ContainerBuilder $builder, array $options = [])
protected function describeContainerServices(ContainerBuilder $container, array $options = []): void
{
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
@@ -143,8 +153,8 @@ class MarkdownDescriptor extends Descriptor
$this->write($title."\n".str_repeat('=', \strlen($title)));
$serviceIds = isset($options['tag']) && $options['tag']
? $this->sortTaggedServicesByPriority($builder->findTaggedServiceIds($options['tag']))
: $this->sortServiceIds($builder->getServiceIds());
? $this->sortTaggedServicesByPriority($container->findTaggedServiceIds($options['tag']))
: $this->sortServiceIds($container->getServiceIds());
$showArguments = isset($options['show_arguments']) && $options['show_arguments'];
$services = ['definitions' => [], 'aliases' => [], 'services' => []];
@@ -153,7 +163,7 @@ class MarkdownDescriptor extends Descriptor
}
foreach ($serviceIds as $serviceId) {
$service = $this->resolveServiceDefinition($builder, $serviceId);
$service = $this->resolveServiceDefinition($container, $serviceId);
if ($showHidden xor '.' === ($serviceId[0] ?? null)) {
continue;
@@ -162,6 +172,9 @@ class MarkdownDescriptor extends Descriptor
if ($service instanceof Alias) {
$services['aliases'][$serviceId] = $service;
} elseif ($service instanceof Definition) {
if ($service->hasTag('container.excluded')) {
continue;
}
$services['definitions'][$serviceId] = $service;
} else {
$services['services'][$serviceId] = $service;
@@ -172,7 +185,7 @@ class MarkdownDescriptor extends Descriptor
$this->write("\n\nDefinitions\n-----------\n");
foreach ($services['definitions'] as $id => $service) {
$this->write("\n");
$this->describeContainerDefinition($service, ['id' => $id, 'show_arguments' => $showArguments]);
$this->describeContainerDefinition($service, ['id' => $id, 'show_arguments' => $showArguments], $container);
}
}
@@ -188,12 +201,12 @@ class MarkdownDescriptor extends Descriptor
$this->write("\n\nServices\n--------\n");
foreach ($services['services'] as $id => $service) {
$this->write("\n");
$this->write(sprintf('- `%s`: `%s`', $id, \get_class($service)));
$this->write(sprintf('- `%s`: `%s`', $id, $service::class));
}
}
}
protected function describeContainerDefinition(Definition $definition, array $options = [])
protected function describeContainerDefinition(Definition $definition, array $options = [], ContainerBuilder $container = null): void
{
$output = '';
@@ -211,6 +224,13 @@ class MarkdownDescriptor extends Descriptor
."\n".'- Autoconfigured: '.($definition->isAutoconfigured() ? 'yes' : 'no')
;
if ($definition->isDeprecated()) {
$output .= "\n".'- Deprecated: yes';
$output .= "\n".'- Deprecation message: '.$definition->getDeprecation($options['id'])['message'];
} else {
$output .= "\n".'- Deprecated: no';
}
if (isset($options['show_arguments']) && $options['show_arguments']) {
$output .= "\n".'- Arguments: '.($definition->getArguments() ? 'yes' : 'no');
}
@@ -244,16 +264,19 @@ class MarkdownDescriptor extends Descriptor
foreach ($tagData as $parameters) {
$output .= "\n".'- Tag: `'.$tagName.'`';
foreach ($parameters as $name => $value) {
$output .= "\n".' - '.ucfirst($name).': '.$value;
$output .= "\n".' - '.ucfirst($name).': '.(\is_array($value) ? $this->formatParameter($value) : $value);
}
}
}
}
$inEdges = null !== $container && isset($options['id']) ? $this->getServiceEdges($container, $options['id']) : [];
$output .= "\n".'- Usages: '.($inEdges ? implode(', ', $inEdges) : 'none');
$this->write(isset($options['id']) ? sprintf("### %s\n\n%s\n", $options['id'], $output) : $output);
}
protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $builder = null)
protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $container = null): void
{
$output = '- Service: `'.$alias.'`'
."\n".'- Public: '.($alias->isPublic() && !$alias->isPrivate() ? 'yes' : 'no');
@@ -266,25 +289,29 @@ class MarkdownDescriptor extends Descriptor
$this->write(sprintf("### %s\n\n%s\n", $options['id'], $output));
if (!$builder) {
if (!$container) {
return;
}
$this->write("\n");
$this->describeContainerDefinition($builder->getDefinition((string) $alias), array_merge($options, ['id' => (string) $alias]));
$this->describeContainerDefinition($container->getDefinition((string) $alias), array_merge($options, ['id' => (string) $alias]), $container);
}
protected function describeContainerParameter($parameter, array $options = [])
protected function describeContainerParameter(mixed $parameter, ?array $deprecation, array $options = []): void
{
$this->write(isset($options['parameter']) ? sprintf("%s\n%s\n\n%s", $options['parameter'], str_repeat('=', \strlen($options['parameter'])), $this->formatParameter($parameter)) : $parameter);
if (isset($options['parameter'])) {
$this->write(sprintf("%s\n%s\n\n%s%s", $options['parameter'], str_repeat('=', \strlen($options['parameter'])), $this->formatParameter($parameter), $deprecation ? sprintf("\n\n*Since %s %s: %s*", $deprecation[0], $deprecation[1], sprintf(...\array_slice($deprecation, 2))) : ''));
} else {
$this->write($parameter);
}
}
protected function describeContainerEnvVars(array $envs, array $options = [])
protected function describeContainerEnvVars(array $envs, array $options = []): void
{
throw new LogicException('Using the markdown format to debug environment variables is not supported.');
}
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = [])
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = []): void
{
$event = $options['event'] ?? null;
$dispatcherServiceName = $options['dispatcher_service_name'] ?? null;
@@ -300,7 +327,7 @@ class MarkdownDescriptor extends Descriptor
$registeredListeners = $eventDispatcher->getListeners($event);
} else {
// Try to see if "events" exists
$registeredListeners = \array_key_exists('events', $options) ? array_combine($options['events'], array_map(function ($event) use ($eventDispatcher) { return $eventDispatcher->getListeners($event); }, $options['events'])) : $eventDispatcher->getListeners();
$registeredListeners = \array_key_exists('events', $options) ? array_combine($options['events'], array_map(fn ($event) => $eventDispatcher->getListeners($event), $options['events'])) : $eventDispatcher->getListeners();
}
$this->write(sprintf('# %s', $title)."\n");
@@ -326,7 +353,7 @@ class MarkdownDescriptor extends Descriptor
}
}
protected function describeCallable($callable, array $options = [])
protected function describeCallable(mixed $callable, array $options = []): void
{
$string = '';
@@ -335,7 +362,7 @@ class MarkdownDescriptor extends Descriptor
if (\is_object($callable[0])) {
$string .= "\n".sprintf('- Name: `%s`', $callable[1]);
$string .= "\n".sprintf('- Class: `%s`', \get_class($callable[0]));
$string .= "\n".sprintf('- Class: `%s`', $callable[0]::class);
} else {
if (!str_starts_with($callable[1], 'parent::')) {
$string .= "\n".sprintf('- Name: `%s`', $callable[1]);
@@ -349,7 +376,9 @@ class MarkdownDescriptor extends Descriptor
}
}
return $this->write($string."\n");
$this->write($string."\n");
return;
}
if (\is_string($callable)) {
@@ -365,7 +394,9 @@ class MarkdownDescriptor extends Descriptor
$string .= "\n- Static: yes";
}
return $this->write($string."\n");
$this->write($string."\n");
return;
}
if ($callable instanceof \Closure) {
@@ -373,7 +404,9 @@ class MarkdownDescriptor extends Descriptor
$r = new \ReflectionFunction($callable);
if (str_contains($r->name, '{closure}')) {
return $this->write($string."\n");
$this->write($string."\n");
return;
}
$string .= "\n".sprintf('- Name: `%s`', $r->name);
@@ -384,14 +417,18 @@ class MarkdownDescriptor extends Descriptor
}
}
return $this->write($string."\n");
$this->write($string."\n");
return;
}
if (method_exists($callable, '__invoke')) {
$string .= "\n- Type: `object`";
$string .= "\n".sprintf('- Name: `%s`', \get_class($callable));
$string .= "\n".sprintf('- Name: `%s`', $callable::class);
return $this->write($string."\n");
$this->write($string."\n");
return;
}
throw new \InvalidArgumentException('Callable is not describable.');

View File

@@ -14,6 +14,7 @@ namespace Symfony\Bundle\FrameworkBundle\Console\Descriptor;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Helper\Dumper;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableCell;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
@@ -25,8 +26,8 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
@@ -37,14 +38,14 @@ use Symfony\Component\Routing\RouteCollection;
*/
class TextDescriptor extends Descriptor
{
private $fileLinkFormatter;
private ?FileLinkFormatter $fileLinkFormatter;
public function __construct(FileLinkFormatter $fileLinkFormatter = null)
{
$this->fileLinkFormatter = $fileLinkFormatter;
}
protected function describeRouteCollection(RouteCollection $routes, array $options = [])
protected function describeRouteCollection(RouteCollection $routes, array $options = []): void
{
$showControllers = isset($options['show_controllers']) && $options['show_controllers'];
@@ -53,6 +54,10 @@ class TextDescriptor extends Descriptor
$tableHeaders[] = 'Controller';
}
if ($showAliases = $options['show_aliases'] ?? false) {
$tableHeaders[] = 'Aliases';
}
$tableRows = [];
foreach ($routes->all() as $name => $route) {
$controller = $route->getDefault('_controller');
@@ -69,6 +74,10 @@ class TextDescriptor extends Descriptor
$row[] = $controller ? $this->formatControllerLink($controller, $this->formatCallable($controller), $options['container'] ?? null) : '';
}
if ($showAliases) {
$row[] = implode('|', ($reverseAliases ??= $this->getReverseAliases($routes))[$name] ?? []);
}
$tableRows[] = $row;
}
@@ -81,7 +90,7 @@ class TextDescriptor extends Descriptor
}
}
protected function describeRoute(Route $route, array $options = [])
protected function describeRoute(Route $route, array $options = []): void
{
$defaults = $route->getDefaults();
if (isset($defaults['_controller'])) {
@@ -98,7 +107,7 @@ class TextDescriptor extends Descriptor
['Scheme', $route->getSchemes() ? implode('|', $route->getSchemes()) : 'ANY'],
['Method', $route->getMethods() ? implode('|', $route->getMethods()) : 'ANY'],
['Requirements', $route->getRequirements() ? $this->formatRouterConfig($route->getRequirements()) : 'NO CUSTOM'],
['Class', \get_class($route)],
['Class', $route::class],
['Defaults', $this->formatRouterConfig($defaults)],
['Options', $this->formatRouterConfig($route->getOptions())],
];
@@ -112,20 +121,29 @@ class TextDescriptor extends Descriptor
$table->render();
}
protected function describeContainerParameters(ParameterBag $parameters, array $options = [])
protected function describeContainerParameters(ParameterBag $parameters, array $options = []): void
{
$tableHeaders = ['Parameter', 'Value'];
$deprecatedParameters = $parameters->allDeprecated();
$tableRows = [];
foreach ($this->sortParameters($parameters) as $parameter => $value) {
$tableRows[] = [$parameter, $this->formatParameter($value)];
if (isset($deprecatedParameters[$parameter])) {
$tableRows[] = [new TableCell(
sprintf('<comment>(Since %s %s: %s)</comment>', $deprecatedParameters[$parameter][0], $deprecatedParameters[$parameter][1], sprintf(...\array_slice($deprecatedParameters[$parameter], 2))),
['colspan' => 2]
)];
}
}
$options['output']->title('Symfony Container Parameters');
$options['output']->table($tableHeaders, $tableRows);
}
protected function describeContainerTags(ContainerBuilder $builder, array $options = [])
protected function describeContainerTags(ContainerBuilder $container, array $options = []): void
{
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
@@ -135,34 +153,34 @@ class TextDescriptor extends Descriptor
$options['output']->title('Symfony Container Tags');
}
foreach ($this->findDefinitionsByTag($builder, $showHidden) as $tag => $definitions) {
foreach ($this->findDefinitionsByTag($container, $showHidden) as $tag => $definitions) {
$options['output']->section(sprintf('"%s" tag', $tag));
$options['output']->listing(array_keys($definitions));
}
}
protected function describeContainerService(object $service, array $options = [], ContainerBuilder $builder = null)
protected function describeContainerService(object $service, array $options = [], ContainerBuilder $container = null): void
{
if (!isset($options['id'])) {
throw new \InvalidArgumentException('An "id" option must be provided.');
}
if ($service instanceof Alias) {
$this->describeContainerAlias($service, $options, $builder);
$this->describeContainerAlias($service, $options, $container);
} elseif ($service instanceof Definition) {
$this->describeContainerDefinition($service, $options);
$this->describeContainerDefinition($service, $options, $container);
} else {
$options['output']->title(sprintf('Information for Service "<info>%s</info>"', $options['id']));
$options['output']->table(
['Service ID', 'Class'],
[
[$options['id'] ?? '-', \get_class($service)],
[$options['id'] ?? '-', $service::class],
]
);
}
}
protected function describeContainerServices(ContainerBuilder $builder, array $options = [])
protected function describeContainerServices(ContainerBuilder $container, array $options = []): void
{
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
$showTag = $options['tag'] ?? null;
@@ -180,8 +198,8 @@ class TextDescriptor extends Descriptor
$options['output']->title($title);
$serviceIds = isset($options['tag']) && $options['tag']
? $this->sortTaggedServicesByPriority($builder->findTaggedServiceIds($options['tag']))
: $this->sortServiceIds($builder->getServiceIds());
? $this->sortTaggedServicesByPriority($container->findTaggedServiceIds($options['tag']))
: $this->sortServiceIds($container->getServiceIds());
$maxTags = [];
if (isset($options['filter'])) {
@@ -189,7 +207,7 @@ class TextDescriptor extends Descriptor
}
foreach ($serviceIds as $key => $serviceId) {
$definition = $this->resolveServiceDefinition($builder, $serviceId);
$definition = $this->resolveServiceDefinition($container, $serviceId);
// filter out hidden services unless shown explicitly
if ($showHidden xor '.' === ($serviceId[0] ?? null)) {
@@ -198,6 +216,10 @@ class TextDescriptor extends Descriptor
}
if ($definition instanceof Definition) {
if ($definition->hasTag('container.excluded')) {
unset($serviceIds[$key]);
continue;
}
if ($showTag) {
$tags = $definition->getTag($showTag);
foreach ($tags as $tag) {
@@ -205,6 +227,10 @@ class TextDescriptor extends Descriptor
if (!isset($maxTags[$key])) {
$maxTags[$key] = \strlen($key);
}
if (\is_array($value)) {
$value = $this->formatParameter($value);
}
if (\strlen($value) > $maxTags[$key]) {
$maxTags[$key] = \strlen($value);
}
@@ -221,7 +247,7 @@ class TextDescriptor extends Descriptor
$tableRows = [];
$rawOutput = isset($options['raw_text']) && $options['raw_text'];
foreach ($serviceIds as $serviceId) {
$definition = $this->resolveServiceDefinition($builder, $serviceId);
$definition = $this->resolveServiceDefinition($container, $serviceId);
$styledServiceId = $rawOutput ? $serviceId : sprintf('<fg=cyan>%s</fg=cyan>', OutputFormatter::escape($serviceId));
if ($definition instanceof Definition) {
@@ -229,7 +255,11 @@ class TextDescriptor extends Descriptor
foreach ($this->sortByPriority($definition->getTag($showTag)) as $key => $tag) {
$tagValues = [];
foreach ($tagsNames as $tagName) {
$tagValues[] = $tag[$tagName] ?? '';
if (\is_array($tagValue = $tag[$tagName] ?? '')) {
$tagValue = $this->formatParameter($tagValue);
}
$tagValues[] = $tagValue;
}
if (0 === $key) {
$tableRows[] = array_merge([$serviceId], $tagValues, [$definition->getClass()]);
@@ -244,14 +274,14 @@ class TextDescriptor extends Descriptor
$alias = $definition;
$tableRows[] = array_merge([$styledServiceId, sprintf('alias for "%s"', $alias)], $tagsCount ? array_fill(0, $tagsCount, '') : []);
} else {
$tableRows[] = array_merge([$styledServiceId, \get_class($definition)], $tagsCount ? array_fill(0, $tagsCount, '') : []);
$tableRows[] = array_merge([$styledServiceId, $definition::class], $tagsCount ? array_fill(0, $tagsCount, '') : []);
}
}
$options['output']->table($tableHeaders, $tableRows);
}
protected function describeContainerDefinition(Definition $definition, array $options = [])
protected function describeContainerDefinition(Definition $definition, array $options = [], ContainerBuilder $container = null): void
{
if (isset($options['id'])) {
$options['output']->title(sprintf('Information for Service "<info>%s</info>"', $options['id']));
@@ -271,9 +301,7 @@ class TextDescriptor extends Descriptor
$tagInformation = [];
foreach ($tags as $tagName => $tagData) {
foreach ($tagData as $tagParameters) {
$parameters = array_map(function ($key, $value) {
return sprintf('<info>%s</info>: %s', $key, $value);
}, array_keys($tagParameters), array_values($tagParameters));
$parameters = array_map(fn ($key, $value) => sprintf('<info>%s</info>: %s', $key, \is_array($value) ? $this->formatParameter($value) : $value), array_keys($tagParameters), array_values($tagParameters));
$parameters = implode(', ', $parameters);
if ('' === $parameters) {
@@ -360,12 +388,15 @@ class TextDescriptor extends Descriptor
$tableRows[] = ['Arguments', implode("\n", $argumentsInformation)];
}
$inEdges = null !== $container && isset($options['id']) ? $this->getServiceEdges($container, $options['id']) : [];
$tableRows[] = ['Usages', $inEdges ? implode(\PHP_EOL, $inEdges) : 'none'];
$options['output']->table($tableHeaders, $tableRows);
}
protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void
protected function describeContainerDeprecations(ContainerBuilder $container, array $options = []): void
{
$containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.build_dir'), $builder->getParameter('kernel.container_class'));
$containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $container->getParameter('kernel.build_dir'), $container->getParameter('kernel.container_class'));
if (!file_exists($containerDeprecationFilePath)) {
$options['output']->warning('The deprecation file does not exist, please try warming the cache first.');
@@ -389,7 +420,7 @@ class TextDescriptor extends Descriptor
$options['output']->listing($formattedLogs);
}
protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $builder = null)
protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $container = null): void
{
if ($alias->isPublic() && !$alias->isPrivate()) {
$options['output']->comment(sprintf('This service is a <info>public</info> alias for the service <info>%s</info>', (string) $alias));
@@ -397,24 +428,31 @@ class TextDescriptor extends Descriptor
$options['output']->comment(sprintf('This service is a <comment>private</comment> alias for the service <info>%s</info>', (string) $alias));
}
if (!$builder) {
if (!$container) {
return;
}
$this->describeContainerDefinition($builder->getDefinition((string) $alias), array_merge($options, ['id' => (string) $alias]));
$this->describeContainerDefinition($container->getDefinition((string) $alias), array_merge($options, ['id' => (string) $alias]), $container);
}
protected function describeContainerParameter($parameter, array $options = [])
protected function describeContainerParameter(mixed $parameter, ?array $deprecation, array $options = []): void
{
$options['output']->table(
['Parameter', 'Value'],
[
[$options['parameter'], $this->formatParameter($parameter),
],
]);
$parameterName = $options['parameter'];
$rows = [
[$parameterName, $this->formatParameter($parameter)],
];
if ($deprecation) {
$rows[] = [new TableCell(
sprintf('<comment>(Since %s %s: %s)</comment>', $deprecation[0], $deprecation[1], sprintf(...\array_slice($deprecation, 2))),
['colspan' => 2]
)];
}
$options['output']->table(['Parameter', 'Value'], $rows);
}
protected function describeContainerEnvVars(array $envs, array $options = [])
protected function describeContainerEnvVars(array $envs, array $options = []): void
{
$dump = new Dumper($this->output);
$options['output']->title('Symfony Container Environment Variables');
@@ -476,7 +514,7 @@ class TextDescriptor extends Descriptor
}
}
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = [])
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = []): void
{
$event = $options['event'] ?? null;
$dispatcherServiceName = $options['dispatcher_service_name'] ?? null;
@@ -493,7 +531,7 @@ class TextDescriptor extends Descriptor
} else {
$title .= ' Grouped by Event';
// Try to see if "events" exists
$registeredListeners = \array_key_exists('events', $options) ? array_combine($options['events'], array_map(function ($event) use ($eventDispatcher) { return $eventDispatcher->getListeners($event); }, $options['events'])) : $eventDispatcher->getListeners();
$registeredListeners = \array_key_exists('events', $options) ? array_combine($options['events'], array_map(fn ($event) => $eventDispatcher->getListeners($event), $options['events'])) : $eventDispatcher->getListeners();
}
$options['output']->title($title);
@@ -508,12 +546,12 @@ class TextDescriptor extends Descriptor
}
}
protected function describeCallable($callable, array $options = [])
protected function describeCallable(mixed $callable, array $options = []): void
{
$this->writeText($this->formatCallable($callable), $options);
}
private function renderEventListenerTable(EventDispatcherInterface $eventDispatcher, string $event, array $eventListeners, SymfonyStyle $io)
private function renderEventListenerTable(EventDispatcherInterface $eventDispatcher, string $event, array $eventListeners, SymfonyStyle $io): void
{
$tableHeaders = ['Order', 'Callable', 'Priority'];
$tableRows = [];
@@ -527,7 +565,7 @@ class TextDescriptor extends Descriptor
private function formatRouterConfig(array $config): string
{
if (empty($config)) {
if (!$config) {
return 'NONE';
}
@@ -541,7 +579,7 @@ class TextDescriptor extends Descriptor
return trim($configAsString);
}
private function formatControllerLink($controller, string $anchorText, callable $getContainer = null): string
private function formatControllerLink(mixed $controller, string $anchorText, callable $getContainer = null): string
{
if (null === $this->fileLinkFormatter) {
return $anchorText;
@@ -563,7 +601,7 @@ class TextDescriptor extends Descriptor
} else {
$r = new \ReflectionFunction($controller);
}
} catch (\ReflectionException $e) {
} catch (\ReflectionException) {
if (\is_array($controller)) {
$controller = implode('::', $controller);
}
@@ -582,7 +620,7 @@ class TextDescriptor extends Descriptor
try {
$r = new \ReflectionMethod($container->findDefinition($id)->getClass(), $method);
} catch (\ReflectionException $e) {
} catch (\ReflectionException) {
return $anchorText;
}
}
@@ -595,11 +633,11 @@ class TextDescriptor extends Descriptor
return $anchorText;
}
private function formatCallable($callable): string
private function formatCallable(mixed $callable): string
{
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]::class, $callable[1]);
}
return sprintf('%s::%s()', $callable[0], $callable[1]);
@@ -622,13 +660,13 @@ class TextDescriptor extends Descriptor
}
if (method_exists($callable, '__invoke')) {
return sprintf('%s::__invoke()', \get_class($callable));
return sprintf('%s::__invoke()', $callable::class);
}
throw new \InvalidArgumentException('Callable is not describable.');
}
private function writeText(string $content, array $options = [])
private function writeText(string $content, array $options = []): void
{
$this->write(
isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content,

View File

@@ -33,84 +33,84 @@ use Symfony\Component\Routing\RouteCollection;
*/
class XmlDescriptor extends Descriptor
{
protected function describeRouteCollection(RouteCollection $routes, array $options = [])
protected function describeRouteCollection(RouteCollection $routes, array $options = []): void
{
$this->writeDocument($this->getRouteCollectionDocument($routes));
$this->writeDocument($this->getRouteCollectionDocument($routes, $options));
}
protected function describeRoute(Route $route, array $options = [])
protected function describeRoute(Route $route, array $options = []): void
{
$this->writeDocument($this->getRouteDocument($route, $options['name'] ?? null));
}
protected function describeContainerParameters(ParameterBag $parameters, array $options = [])
protected function describeContainerParameters(ParameterBag $parameters, array $options = []): void
{
$this->writeDocument($this->getContainerParametersDocument($parameters));
}
protected function describeContainerTags(ContainerBuilder $builder, array $options = [])
protected function describeContainerTags(ContainerBuilder $container, array $options = []): void
{
$this->writeDocument($this->getContainerTagsDocument($builder, isset($options['show_hidden']) && $options['show_hidden']));
$this->writeDocument($this->getContainerTagsDocument($container, isset($options['show_hidden']) && $options['show_hidden']));
}
protected function describeContainerService(object $service, array $options = [], ContainerBuilder $builder = null)
protected function describeContainerService(object $service, array $options = [], ContainerBuilder $container = null): void
{
if (!isset($options['id'])) {
throw new \InvalidArgumentException('An "id" option must be provided.');
}
$this->writeDocument($this->getContainerServiceDocument($service, $options['id'], $builder, isset($options['show_arguments']) && $options['show_arguments']));
$this->writeDocument($this->getContainerServiceDocument($service, $options['id'], $container, isset($options['show_arguments']) && $options['show_arguments']));
}
protected function describeContainerServices(ContainerBuilder $builder, array $options = [])
protected function describeContainerServices(ContainerBuilder $container, array $options = []): void
{
$this->writeDocument($this->getContainerServicesDocument($builder, $options['tag'] ?? null, isset($options['show_hidden']) && $options['show_hidden'], isset($options['show_arguments']) && $options['show_arguments'], $options['filter'] ?? null));
$this->writeDocument($this->getContainerServicesDocument($container, $options['tag'] ?? null, isset($options['show_hidden']) && $options['show_hidden'], isset($options['show_arguments']) && $options['show_arguments'], $options['filter'] ?? null, $options['id'] ?? null));
}
protected function describeContainerDefinition(Definition $definition, array $options = [])
protected function describeContainerDefinition(Definition $definition, array $options = [], ContainerBuilder $container = null): void
{
$this->writeDocument($this->getContainerDefinitionDocument($definition, $options['id'] ?? null, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments']));
$this->writeDocument($this->getContainerDefinitionDocument($definition, $options['id'] ?? null, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $container));
}
protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $builder = null)
protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $container = null): void
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($dom->importNode($this->getContainerAliasDocument($alias, $options['id'] ?? null)->childNodes->item(0), true));
if (!$builder) {
if (!$container) {
$this->writeDocument($dom);
return;
}
$dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($builder->getDefinition((string) $alias), (string) $alias)->childNodes->item(0), true));
$dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($container->getDefinition((string) $alias), (string) $alias, false, false, $container)->childNodes->item(0), true));
$this->writeDocument($dom);
}
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = [])
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = []): void
{
$this->writeDocument($this->getEventDispatcherListenersDocument($eventDispatcher, $options));
}
protected function describeCallable($callable, array $options = [])
protected function describeCallable(mixed $callable, array $options = []): void
{
$this->writeDocument($this->getCallableDocument($callable));
}
protected function describeContainerParameter($parameter, array $options = [])
protected function describeContainerParameter(mixed $parameter, ?array $deprecation, array $options = []): void
{
$this->writeDocument($this->getContainerParameterDocument($parameter, $options));
$this->writeDocument($this->getContainerParameterDocument($parameter, $deprecation, $options));
}
protected function describeContainerEnvVars(array $envs, array $options = [])
protected function describeContainerEnvVars(array $envs, array $options = []): void
{
throw new LogicException('Using the XML format to debug environment variables is not supported.');
}
protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void
protected function describeContainerDeprecations(ContainerBuilder $container, array $options = []): void
{
$containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.build_dir'), $builder->getParameter('kernel.container_class'));
$containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $container->getParameter('kernel.build_dir'), $container->getParameter('kernel.container_class'));
if (!file_exists($containerDeprecationFilePath)) {
throw new RuntimeException('The deprecation file does not exist, please try warming the cache first.');
}
@@ -120,7 +120,6 @@ class XmlDescriptor extends Descriptor
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($deprecationsXML = $dom->createElement('deprecations'));
$formattedLogs = [];
$remainingCount = 0;
foreach ($logs as $log) {
$deprecationsXML->appendChild($deprecationXML = $dom->createElement('deprecation'));
@@ -136,19 +135,27 @@ class XmlDescriptor extends Descriptor
$this->writeDocument($dom);
}
private function writeDocument(\DOMDocument $dom)
private function writeDocument(\DOMDocument $dom): void
{
$dom->formatOutput = true;
$this->write($dom->saveXML());
}
private function getRouteCollectionDocument(RouteCollection $routes): \DOMDocument
private function getRouteCollectionDocument(RouteCollection $routes, array $options): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($routesXML = $dom->createElement('routes'));
foreach ($routes->all() as $name => $route) {
$routeXML = $this->getRouteDocument($route, $name);
if (($showAliases ??= $options['show_aliases'] ?? false) && $aliases = ($reverseAliases ??= $this->getReverseAliases($routes))[$name] ?? []) {
$routeXML->firstChild->appendChild($aliasesXML = $routeXML->createElement('aliases'));
foreach ($aliases as $alias) {
$aliasesXML->appendChild($aliasXML = $routeXML->createElement('alias'));
$aliasXML->appendChild(new \DOMText($alias));
}
}
$routesXML->appendChild($routesXML->ownerDocument->importNode($routeXML->childNodes->item(0), true));
}
@@ -164,7 +171,7 @@ class XmlDescriptor extends Descriptor
$routeXML->setAttribute('name', $name);
}
$routeXML->setAttribute('class', \get_class($route));
$routeXML->setAttribute('class', $route::class);
$routeXML->appendChild($pathXML = $dom->createElement('path'));
$pathXML->setAttribute('regex', $route->compile()->getRegex());
@@ -228,26 +235,32 @@ class XmlDescriptor extends Descriptor
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($parametersXML = $dom->createElement('parameters'));
$deprecatedParameters = $parameters->allDeprecated();
foreach ($this->sortParameters($parameters) as $key => $value) {
$parametersXML->appendChild($parameterXML = $dom->createElement('parameter'));
$parameterXML->setAttribute('key', $key);
$parameterXML->appendChild(new \DOMText($this->formatParameter($value)));
if (isset($deprecatedParameters[$key])) {
$parameterXML->setAttribute('deprecated', sprintf('Since %s %s: %s', $deprecatedParameters[$key][0], $deprecatedParameters[$key][1], sprintf(...\array_slice($deprecatedParameters[$key], 2))));
}
}
return $dom;
}
private function getContainerTagsDocument(ContainerBuilder $builder, bool $showHidden = false): \DOMDocument
private function getContainerTagsDocument(ContainerBuilder $container, bool $showHidden = false): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($containerXML = $dom->createElement('container'));
foreach ($this->findDefinitionsByTag($builder, $showHidden) as $tag => $definitions) {
foreach ($this->findDefinitionsByTag($container, $showHidden) as $tag => $definitions) {
$containerXML->appendChild($tagXML = $dom->createElement('tag'));
$tagXML->setAttribute('name', $tag);
foreach ($definitions as $serviceId => $definition) {
$definitionXML = $this->getContainerDefinitionDocument($definition, $serviceId, true);
$definitionXML = $this->getContainerDefinitionDocument($definition, $serviceId, true, false, $container);
$tagXML->appendChild($dom->importNode($definitionXML->childNodes->item(0), true));
}
}
@@ -255,45 +268,49 @@ class XmlDescriptor extends Descriptor
return $dom;
}
private function getContainerServiceDocument(object $service, string $id, ContainerBuilder $builder = null, bool $showArguments = false): \DOMDocument
private function getContainerServiceDocument(object $service, string $id, ContainerBuilder $container = null, bool $showArguments = false): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
if ($service instanceof Alias) {
$dom->appendChild($dom->importNode($this->getContainerAliasDocument($service, $id)->childNodes->item(0), true));
if ($builder) {
$dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($builder->getDefinition((string) $service), (string) $service, false, $showArguments)->childNodes->item(0), true));
if ($container) {
$dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($container->getDefinition((string) $service), (string) $service, false, $showArguments, $container)->childNodes->item(0), true));
}
} elseif ($service instanceof Definition) {
$dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($service, $id, false, $showArguments)->childNodes->item(0), true));
$dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($service, $id, false, $showArguments, $container)->childNodes->item(0), true));
} else {
$dom->appendChild($serviceXML = $dom->createElement('service'));
$serviceXML->setAttribute('id', $id);
$serviceXML->setAttribute('class', \get_class($service));
$serviceXML->setAttribute('class', $service::class);
}
return $dom;
}
private function getContainerServicesDocument(ContainerBuilder $builder, string $tag = null, bool $showHidden = false, bool $showArguments = false, callable $filter = null): \DOMDocument
private function getContainerServicesDocument(ContainerBuilder $container, string $tag = null, bool $showHidden = false, bool $showArguments = false, callable $filter = null, string $id = null): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($containerXML = $dom->createElement('container'));
$serviceIds = $tag
? $this->sortTaggedServicesByPriority($builder->findTaggedServiceIds($tag))
: $this->sortServiceIds($builder->getServiceIds());
? $this->sortTaggedServicesByPriority($container->findTaggedServiceIds($tag))
: $this->sortServiceIds($container->getServiceIds());
if ($filter) {
$serviceIds = array_filter($serviceIds, $filter);
}
foreach ($serviceIds as $serviceId) {
$service = $this->resolveServiceDefinition($builder, $serviceId);
$service = $this->resolveServiceDefinition($container, $serviceId);
if ($showHidden xor '.' === ($serviceId[0] ?? null)) {
continue;
}
if ($service instanceof Definition && $service->hasTag('container.excluded')) {
continue;
}
$serviceXML = $this->getContainerServiceDocument($service, $serviceId, null, $showArguments);
$containerXML->appendChild($containerXML->ownerDocument->importNode($serviceXML->childNodes->item(0), true));
}
@@ -301,7 +318,7 @@ class XmlDescriptor extends Descriptor
return $dom;
}
private function getContainerDefinitionDocument(Definition $definition, string $id = null, bool $omitTags = false, bool $showArguments = false): \DOMDocument
private function getContainerDefinitionDocument(Definition $definition, string $id = null, bool $omitTags = false, bool $showArguments = false, ContainerBuilder $container = null): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($serviceXML = $dom->createElement('definition'));
@@ -341,6 +358,12 @@ class XmlDescriptor extends Descriptor
$serviceXML->setAttribute('abstract', $definition->isAbstract() ? 'true' : 'false');
$serviceXML->setAttribute('autowired', $definition->isAutowired() ? 'true' : 'false');
$serviceXML->setAttribute('autoconfigured', $definition->isAutoconfigured() ? 'true' : 'false');
if ($definition->isDeprecated()) {
$serviceXML->setAttribute('deprecated', 'true');
$serviceXML->setAttribute('deprecation_message', $definition->getDeprecation($id)['message']);
} else {
$serviceXML->setAttribute('deprecated', 'false');
}
$serviceXML->setAttribute('file', $definition->getFile() ?? '');
$calls = $definition->getMethodCalls();
@@ -356,7 +379,7 @@ class XmlDescriptor extends Descriptor
}
if ($showArguments) {
foreach ($this->getArgumentNodes($definition->getArguments(), $dom) as $node) {
foreach ($this->getArgumentNodes($definition->getArguments(), $dom, $container) as $node) {
$serviceXML->appendChild($node);
}
}
@@ -378,13 +401,24 @@ class XmlDescriptor extends Descriptor
}
}
if (null !== $container && null !== $id) {
$edges = $this->getServiceEdges($container, $id);
if ($edges) {
$serviceXML->appendChild($usagesXML = $dom->createElement('usages'));
foreach ($edges as $edge) {
$usagesXML->appendChild($usageXML = $dom->createElement('usage'));
$usageXML->appendChild(new \DOMText($edge));
}
}
}
return $dom;
}
/**
* @return \DOMNode[]
*/
private function getArgumentNodes(array $arguments, \DOMDocument $dom): array
private function getArgumentNodes(array $arguments, \DOMDocument $dom, ContainerBuilder $container = null): array
{
$nodes = [];
@@ -405,18 +439,18 @@ class XmlDescriptor extends Descriptor
} elseif ($argument instanceof IteratorArgument || $argument instanceof ServiceLocatorArgument) {
$argumentXML->setAttribute('type', $argument instanceof IteratorArgument ? 'iterator' : 'service_locator');
foreach ($this->getArgumentNodes($argument->getValues(), $dom) as $childArgumentXML) {
foreach ($this->getArgumentNodes($argument->getValues(), $dom, $container) as $childArgumentXML) {
$argumentXML->appendChild($childArgumentXML);
}
} elseif ($argument instanceof Definition) {
$argumentXML->appendChild($dom->importNode($this->getContainerDefinitionDocument($argument, null, false, true)->childNodes->item(0), true));
$argumentXML->appendChild($dom->importNode($this->getContainerDefinitionDocument($argument, null, false, true, $container)->childNodes->item(0), true));
} elseif ($argument instanceof AbstractArgument) {
$argumentXML->setAttribute('type', 'abstract');
$argumentXML->appendChild(new \DOMText($argument->getText()));
} elseif (\is_array($argument)) {
$argumentXML->setAttribute('type', 'collection');
foreach ($this->getArgumentNodes($argument, $dom) as $childArgumentXML) {
foreach ($this->getArgumentNodes($argument, $dom, $container) as $childArgumentXML) {
$argumentXML->appendChild($childArgumentXML);
}
} elseif ($argument instanceof \UnitEnum) {
@@ -447,13 +481,17 @@ class XmlDescriptor extends Descriptor
return $dom;
}
private function getContainerParameterDocument($parameter, array $options = []): \DOMDocument
private function getContainerParameterDocument(mixed $parameter, ?array $deprecation, array $options = []): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($parameterXML = $dom->createElement('parameter'));
if (isset($options['parameter'])) {
$parameterXML->setAttribute('key', $options['parameter']);
if ($deprecation) {
$parameterXML->setAttribute('deprecated', sprintf('Since %s %s: %s', $deprecation[0], $deprecation[1], sprintf(...\array_slice($deprecation, 2))));
}
}
$parameterXML->appendChild(new \DOMText($this->formatParameter($parameter)));
@@ -472,7 +510,7 @@ class XmlDescriptor extends Descriptor
$this->appendEventListenerDocument($eventDispatcher, $event, $eventDispatcherXML, $registeredListeners);
} else {
// Try to see if "events" exists
$registeredListeners = \array_key_exists('events', $options) ? array_combine($options['events'], array_map(function ($event) use ($eventDispatcher) { return $eventDispatcher->getListeners($event); }, $options['events'])) : $eventDispatcher->getListeners();
$registeredListeners = \array_key_exists('events', $options) ? array_combine($options['events'], array_map(fn ($event) => $eventDispatcher->getListeners($event), $options['events'])) : $eventDispatcher->getListeners();
ksort($registeredListeners);
foreach ($registeredListeners as $eventListened => $eventListeners) {
@@ -486,7 +524,7 @@ class XmlDescriptor extends Descriptor
return $dom;
}
private function appendEventListenerDocument(EventDispatcherInterface $eventDispatcher, string $event, \DOMElement $element, array $eventListeners)
private function appendEventListenerDocument(EventDispatcherInterface $eventDispatcher, string $event, \DOMElement $element, array $eventListeners): void
{
foreach ($eventListeners as $listener) {
$callableXML = $this->getCallableDocument($listener);
@@ -496,7 +534,7 @@ class XmlDescriptor extends Descriptor
}
}
private function getCallableDocument($callable): \DOMDocument
private function getCallableDocument(mixed $callable): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($callableXML = $dom->createElement('callable'));
@@ -506,7 +544,7 @@ class XmlDescriptor extends Descriptor
if (\is_object($callable[0])) {
$callableXML->setAttribute('name', $callable[1]);
$callableXML->setAttribute('class', \get_class($callable[0]));
$callableXML->setAttribute('class', $callable[0]::class);
} else {
if (!str_starts_with($callable[1], 'parent::')) {
$callableXML->setAttribute('name', $callable[1]);
@@ -560,7 +598,7 @@ class XmlDescriptor extends Descriptor
if (method_exists($callable, '__invoke')) {
$callableXML->setAttribute('type', 'object');
$callableXML->setAttribute('name', \get_class($callable));
$callableXML->setAttribute('name', $callable::class);
return $dom;
}