123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564 |
- <?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\Console\Descriptor;
- use Symfony\Component\Console\Exception\LogicException;
- use Symfony\Component\Console\Exception\RuntimeException;
- use Symfony\Component\DependencyInjection\Alias;
- use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
- use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
- use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
- use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
- use Symfony\Component\DependencyInjection\ContainerBuilder;
- use Symfony\Component\DependencyInjection\Definition;
- use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
- use Symfony\Component\DependencyInjection\Reference;
- use Symfony\Component\EventDispatcher\EventDispatcherInterface;
- use Symfony\Component\Routing\Route;
- use Symfony\Component\Routing\RouteCollection;
- /**
- * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
- *
- * @internal
- */
- class XmlDescriptor extends Descriptor
- {
- protected function describeRouteCollection(RouteCollection $routes, array $options = [])
- {
- $this->writeDocument($this->getRouteCollectionDocument($routes));
- }
- protected function describeRoute(Route $route, array $options = [])
- {
- $this->writeDocument($this->getRouteDocument($route, $options['name'] ?? null));
- }
- protected function describeContainerParameters(ParameterBag $parameters, array $options = [])
- {
- $this->writeDocument($this->getContainerParametersDocument($parameters));
- }
- protected function describeContainerTags(ContainerBuilder $builder, array $options = [])
- {
- $this->writeDocument($this->getContainerTagsDocument($builder, isset($options['show_hidden']) && $options['show_hidden']));
- }
- protected function describeContainerService($service, array $options = [], ContainerBuilder $builder = null)
- {
- 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']));
- }
- protected function describeContainerServices(ContainerBuilder $builder, array $options = [])
- {
- $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));
- }
- protected function describeContainerDefinition(Definition $definition, array $options = [])
- {
- $this->writeDocument($this->getContainerDefinitionDocument($definition, $options['id'] ?? null, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments']));
- }
- protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $builder = null)
- {
- $dom = new \DOMDocument('1.0', 'UTF-8');
- $dom->appendChild($dom->importNode($this->getContainerAliasDocument($alias, $options['id'] ?? null)->childNodes->item(0), true));
- if (!$builder) {
- $this->writeDocument($dom);
- return;
- }
- $dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($builder->getDefinition((string) $alias), (string) $alias)->childNodes->item(0), true));
- $this->writeDocument($dom);
- }
- protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = [])
- {
- $this->writeDocument($this->getEventDispatcherListenersDocument($eventDispatcher, \array_key_exists('event', $options) ? $options['event'] : null));
- }
- protected function describeCallable($callable, array $options = [])
- {
- $this->writeDocument($this->getCallableDocument($callable));
- }
- protected function describeContainerParameter($parameter, array $options = [])
- {
- $this->writeDocument($this->getContainerParameterDocument($parameter, $options));
- }
- protected function describeContainerEnvVars(array $envs, array $options = [])
- {
- throw new LogicException('Using the XML format to debug environment variables is not supported.');
- }
- protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void
- {
- $containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.build_dir'), $builder->getParameter('kernel.container_class'));
- if (!file_exists($containerDeprecationFilePath)) {
- throw new RuntimeException('The deprecation file does not exist, please try warming the cache first.');
- }
- $logs = unserialize(file_get_contents($containerDeprecationFilePath));
- $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'));
- $deprecationXML->setAttribute('count', $log['count']);
- $deprecationXML->appendChild($dom->createElement('message', $log['message']));
- $deprecationXML->appendChild($dom->createElement('file', $log['file']));
- $deprecationXML->appendChild($dom->createElement('line', $log['line']));
- $remainingCount += $log['count'];
- }
- $deprecationsXML->setAttribute('remainingCount', $remainingCount);
- $this->writeDocument($dom);
- }
- private function writeDocument(\DOMDocument $dom)
- {
- $dom->formatOutput = true;
- $this->write($dom->saveXML());
- }
- private function getRouteCollectionDocument(RouteCollection $routes): \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);
- $routesXML->appendChild($routesXML->ownerDocument->importNode($routeXML->childNodes->item(0), true));
- }
- return $dom;
- }
- private function getRouteDocument(Route $route, string $name = null): \DOMDocument
- {
- $dom = new \DOMDocument('1.0', 'UTF-8');
- $dom->appendChild($routeXML = $dom->createElement('route'));
- if ($name) {
- $routeXML->setAttribute('name', $name);
- }
- $routeXML->setAttribute('class', \get_class($route));
- $routeXML->appendChild($pathXML = $dom->createElement('path'));
- $pathXML->setAttribute('regex', $route->compile()->getRegex());
- $pathXML->appendChild(new \DOMText($route->getPath()));
- if ('' !== $route->getHost()) {
- $routeXML->appendChild($hostXML = $dom->createElement('host'));
- $hostXML->setAttribute('regex', $route->compile()->getHostRegex());
- $hostXML->appendChild(new \DOMText($route->getHost()));
- }
- foreach ($route->getSchemes() as $scheme) {
- $routeXML->appendChild($schemeXML = $dom->createElement('scheme'));
- $schemeXML->appendChild(new \DOMText($scheme));
- }
- foreach ($route->getMethods() as $method) {
- $routeXML->appendChild($methodXML = $dom->createElement('method'));
- $methodXML->appendChild(new \DOMText($method));
- }
- if ($route->getDefaults()) {
- $routeXML->appendChild($defaultsXML = $dom->createElement('defaults'));
- foreach ($route->getDefaults() as $attribute => $value) {
- $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
- $defaultXML->setAttribute('key', $attribute);
- $defaultXML->appendChild(new \DOMText($this->formatValue($value)));
- }
- }
- $originRequirements = $requirements = $route->getRequirements();
- unset($requirements['_scheme'], $requirements['_method']);
- if ($requirements) {
- $routeXML->appendChild($requirementsXML = $dom->createElement('requirements'));
- foreach ($originRequirements as $attribute => $pattern) {
- $requirementsXML->appendChild($requirementXML = $dom->createElement('requirement'));
- $requirementXML->setAttribute('key', $attribute);
- $requirementXML->appendChild(new \DOMText($pattern));
- }
- }
- if ($route->getOptions()) {
- $routeXML->appendChild($optionsXML = $dom->createElement('options'));
- foreach ($route->getOptions() as $name => $value) {
- $optionsXML->appendChild($optionXML = $dom->createElement('option'));
- $optionXML->setAttribute('key', $name);
- $optionXML->appendChild(new \DOMText($this->formatValue($value)));
- }
- }
- if ('' !== $route->getCondition()) {
- $routeXML->appendChild($conditionXML = $dom->createElement('condition'));
- $conditionXML->appendChild(new \DOMText($route->getCondition()));
- }
- return $dom;
- }
- private function getContainerParametersDocument(ParameterBag $parameters): \DOMDocument
- {
- $dom = new \DOMDocument('1.0', 'UTF-8');
- $dom->appendChild($parametersXML = $dom->createElement('parameters'));
- foreach ($this->sortParameters($parameters) as $key => $value) {
- $parametersXML->appendChild($parameterXML = $dom->createElement('parameter'));
- $parameterXML->setAttribute('key', $key);
- $parameterXML->appendChild(new \DOMText($this->formatParameter($value)));
- }
- return $dom;
- }
- private function getContainerTagsDocument(ContainerBuilder $builder, 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) {
- $containerXML->appendChild($tagXML = $dom->createElement('tag'));
- $tagXML->setAttribute('name', $tag);
- foreach ($definitions as $serviceId => $definition) {
- $definitionXML = $this->getContainerDefinitionDocument($definition, $serviceId, true);
- $tagXML->appendChild($dom->importNode($definitionXML->childNodes->item(0), true));
- }
- }
- return $dom;
- }
- private function getContainerServiceDocument($service, string $id, ContainerBuilder $builder = 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));
- }
- } elseif ($service instanceof Definition) {
- $dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($service, $id, false, $showArguments)->childNodes->item(0), true));
- } else {
- $dom->appendChild($serviceXML = $dom->createElement('service'));
- $serviceXML->setAttribute('id', $id);
- $serviceXML->setAttribute('class', \get_class($service));
- }
- return $dom;
- }
- private function getContainerServicesDocument(ContainerBuilder $builder, string $tag = null, bool $showHidden = false, bool $showArguments = false, callable $filter = 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());
- if ($filter) {
- $serviceIds = array_filter($serviceIds, $filter);
- }
- foreach ($serviceIds as $serviceId) {
- $service = $this->resolveServiceDefinition($builder, $serviceId);
- if ($showHidden xor '.' === ($serviceId[0] ?? null)) {
- continue;
- }
- $serviceXML = $this->getContainerServiceDocument($service, $serviceId, null, $showArguments);
- $containerXML->appendChild($containerXML->ownerDocument->importNode($serviceXML->childNodes->item(0), true));
- }
- return $dom;
- }
- private function getContainerDefinitionDocument(Definition $definition, string $id = null, bool $omitTags = false, bool $showArguments = false): \DOMDocument
- {
- $dom = new \DOMDocument('1.0', 'UTF-8');
- $dom->appendChild($serviceXML = $dom->createElement('definition'));
- if ($id) {
- $serviceXML->setAttribute('id', $id);
- }
- if ('' !== $classDescription = $this->getClassDescription((string) $definition->getClass())) {
- $serviceXML->appendChild($descriptionXML = $dom->createElement('description'));
- $descriptionXML->appendChild($dom->createCDATASection($classDescription));
- }
- $serviceXML->setAttribute('class', $definition->getClass());
- if ($factory = $definition->getFactory()) {
- $serviceXML->appendChild($factoryXML = $dom->createElement('factory'));
- if (\is_array($factory)) {
- if ($factory[0] instanceof Reference) {
- $factoryXML->setAttribute('service', (string) $factory[0]);
- } elseif ($factory[0] instanceof Definition) {
- throw new \InvalidArgumentException('Factory is not describable.');
- } else {
- $factoryXML->setAttribute('class', $factory[0]);
- }
- $factoryXML->setAttribute('method', $factory[1]);
- } else {
- $factoryXML->setAttribute('function', $factory);
- }
- }
- $serviceXML->setAttribute('public', $definition->isPublic() && !$definition->isPrivate() ? 'true' : 'false');
- $serviceXML->setAttribute('synthetic', $definition->isSynthetic() ? 'true' : 'false');
- $serviceXML->setAttribute('lazy', $definition->isLazy() ? 'true' : 'false');
- $serviceXML->setAttribute('shared', $definition->isShared() ? 'true' : 'false');
- $serviceXML->setAttribute('abstract', $definition->isAbstract() ? 'true' : 'false');
- $serviceXML->setAttribute('autowired', $definition->isAutowired() ? 'true' : 'false');
- $serviceXML->setAttribute('autoconfigured', $definition->isAutoconfigured() ? 'true' : 'false');
- $serviceXML->setAttribute('file', $definition->getFile());
- $calls = $definition->getMethodCalls();
- if (\count($calls) > 0) {
- $serviceXML->appendChild($callsXML = $dom->createElement('calls'));
- foreach ($calls as $callData) {
- $callsXML->appendChild($callXML = $dom->createElement('call'));
- $callXML->setAttribute('method', $callData[0]);
- if ($callData[2] ?? false) {
- $callXML->setAttribute('returns-clone', 'true');
- }
- }
- }
- if ($showArguments) {
- foreach ($this->getArgumentNodes($definition->getArguments(), $dom) as $node) {
- $serviceXML->appendChild($node);
- }
- }
- if (!$omitTags) {
- if ($tags = $this->sortTagsByPriority($definition->getTags())) {
- $serviceXML->appendChild($tagsXML = $dom->createElement('tags'));
- foreach ($tags as $tagName => $tagData) {
- foreach ($tagData as $parameters) {
- $tagsXML->appendChild($tagXML = $dom->createElement('tag'));
- $tagXML->setAttribute('name', $tagName);
- foreach ($parameters as $name => $value) {
- $tagXML->appendChild($parameterXML = $dom->createElement('parameter'));
- $parameterXML->setAttribute('name', $name);
- $parameterXML->appendChild(new \DOMText($this->formatParameter($value)));
- }
- }
- }
- }
- }
- return $dom;
- }
- /**
- * @return \DOMNode[]
- */
- private function getArgumentNodes(array $arguments, \DOMDocument $dom): array
- {
- $nodes = [];
- foreach ($arguments as $argumentKey => $argument) {
- $argumentXML = $dom->createElement('argument');
- if (\is_string($argumentKey)) {
- $argumentXML->setAttribute('key', $argumentKey);
- }
- if ($argument instanceof ServiceClosureArgument) {
- $argument = $argument->getValues()[0];
- }
- if ($argument instanceof Reference) {
- $argumentXML->setAttribute('type', 'service');
- $argumentXML->setAttribute('id', (string) $argument);
- } elseif ($argument instanceof IteratorArgument || $argument instanceof ServiceLocatorArgument) {
- $argumentXML->setAttribute('type', $argument instanceof IteratorArgument ? 'iterator' : 'service_locator');
- foreach ($this->getArgumentNodes($argument->getValues(), $dom) as $childArgumentXML) {
- $argumentXML->appendChild($childArgumentXML);
- }
- } elseif ($argument instanceof Definition) {
- $argumentXML->appendChild($dom->importNode($this->getContainerDefinitionDocument($argument, null, false, true)->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) {
- $argumentXML->appendChild($childArgumentXML);
- }
- } else {
- $argumentXML->appendChild(new \DOMText($argument));
- }
- $nodes[] = $argumentXML;
- }
- return $nodes;
- }
- private function getContainerAliasDocument(Alias $alias, string $id = null): \DOMDocument
- {
- $dom = new \DOMDocument('1.0', 'UTF-8');
- $dom->appendChild($aliasXML = $dom->createElement('alias'));
- if ($id) {
- $aliasXML->setAttribute('id', $id);
- }
- $aliasXML->setAttribute('service', (string) $alias);
- $aliasXML->setAttribute('public', $alias->isPublic() && !$alias->isPrivate() ? 'true' : 'false');
- return $dom;
- }
- private function getContainerParameterDocument($parameter, 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']);
- }
- $parameterXML->appendChild(new \DOMText($this->formatParameter($parameter)));
- return $dom;
- }
- private function getEventDispatcherListenersDocument(EventDispatcherInterface $eventDispatcher, string $event = null): \DOMDocument
- {
- $dom = new \DOMDocument('1.0', 'UTF-8');
- $dom->appendChild($eventDispatcherXML = $dom->createElement('event-dispatcher'));
- $registeredListeners = $eventDispatcher->getListeners($event);
- if (null !== $event) {
- $this->appendEventListenerDocument($eventDispatcher, $event, $eventDispatcherXML, $registeredListeners);
- } else {
- ksort($registeredListeners);
- foreach ($registeredListeners as $eventListened => $eventListeners) {
- $eventDispatcherXML->appendChild($eventXML = $dom->createElement('event'));
- $eventXML->setAttribute('name', $eventListened);
- $this->appendEventListenerDocument($eventDispatcher, $eventListened, $eventXML, $eventListeners);
- }
- }
- return $dom;
- }
- private function appendEventListenerDocument(EventDispatcherInterface $eventDispatcher, string $event, \DOMElement $element, array $eventListeners)
- {
- foreach ($eventListeners as $listener) {
- $callableXML = $this->getCallableDocument($listener);
- $callableXML->childNodes->item(0)->setAttribute('priority', $eventDispatcher->getListenerPriority($event, $listener));
- $element->appendChild($element->ownerDocument->importNode($callableXML->childNodes->item(0), true));
- }
- }
- private function getCallableDocument($callable): \DOMDocument
- {
- $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');
- $r = new \ReflectionFunction($callable);
- if (false !== strpos($r->name, '{closure}')) {
- return $dom;
- }
- $callableXML->setAttribute('name', $r->name);
- if ($class = $r->getClosureScopeClass()) {
- $callableXML->setAttribute('class', $class->name);
- if (!$r->getClosureThis()) {
- $callableXML->setAttribute('static', 'true');
- }
- }
- 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.');
- }
- }
|