1<?php 2 3/* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Symfony\Component\Console\Descriptor; 13 14use Symfony\Component\Console\Application; 15use Symfony\Component\Console\Command\Command; 16use Symfony\Component\Console\Input\InputArgument; 17use Symfony\Component\Console\Input\InputDefinition; 18use Symfony\Component\Console\Input\InputOption; 19 20/** 21 * XML descriptor. 22 * 23 * @author Jean-François Simon <contact@jfsimon.fr> 24 * 25 * @internal 26 */ 27class XmlDescriptor extends Descriptor 28{ 29 public function getInputDefinitionDocument(InputDefinition $definition): \DOMDocument 30 { 31 $dom = new \DOMDocument('1.0', 'UTF-8'); 32 $dom->appendChild($definitionXML = $dom->createElement('definition')); 33 34 $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments')); 35 foreach ($definition->getArguments() as $argument) { 36 $this->appendDocument($argumentsXML, $this->getInputArgumentDocument($argument)); 37 } 38 39 $definitionXML->appendChild($optionsXML = $dom->createElement('options')); 40 foreach ($definition->getOptions() as $option) { 41 $this->appendDocument($optionsXML, $this->getInputOptionDocument($option)); 42 } 43 44 return $dom; 45 } 46 47 public function getCommandDocument(Command $command): \DOMDocument 48 { 49 $dom = new \DOMDocument('1.0', 'UTF-8'); 50 $dom->appendChild($commandXML = $dom->createElement('command')); 51 52 $command->getSynopsis(); 53 $command->mergeApplicationDefinition(false); 54 55 $commandXML->setAttribute('id', $command->getName()); 56 $commandXML->setAttribute('name', $command->getName()); 57 $commandXML->setAttribute('hidden', $command->isHidden() ? 1 : 0); 58 59 $commandXML->appendChild($usagesXML = $dom->createElement('usages')); 60 61 foreach (array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()) as $usage) { 62 $usagesXML->appendChild($dom->createElement('usage', $usage)); 63 } 64 65 $commandXML->appendChild($descriptionXML = $dom->createElement('description')); 66 $descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getDescription()))); 67 68 $commandXML->appendChild($helpXML = $dom->createElement('help')); 69 $helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getProcessedHelp()))); 70 71 $definitionXML = $this->getInputDefinitionDocument($command->getNativeDefinition()); 72 $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0)); 73 74 return $dom; 75 } 76 77 public function getApplicationDocument(Application $application, string $namespace = null): \DOMDocument 78 { 79 $dom = new \DOMDocument('1.0', 'UTF-8'); 80 $dom->appendChild($rootXml = $dom->createElement('symfony')); 81 82 if ('UNKNOWN' !== $application->getName()) { 83 $rootXml->setAttribute('name', $application->getName()); 84 if ('UNKNOWN' !== $application->getVersion()) { 85 $rootXml->setAttribute('version', $application->getVersion()); 86 } 87 } 88 89 $rootXml->appendChild($commandsXML = $dom->createElement('commands')); 90 91 $description = new ApplicationDescription($application, $namespace, true); 92 93 if ($namespace) { 94 $commandsXML->setAttribute('namespace', $namespace); 95 } 96 97 foreach ($description->getCommands() as $command) { 98 $this->appendDocument($commandsXML, $this->getCommandDocument($command)); 99 } 100 101 if (!$namespace) { 102 $rootXml->appendChild($namespacesXML = $dom->createElement('namespaces')); 103 104 foreach ($description->getNamespaces() as $namespaceDescription) { 105 $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace')); 106 $namespaceArrayXML->setAttribute('id', $namespaceDescription['id']); 107 108 foreach ($namespaceDescription['commands'] as $name) { 109 $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command')); 110 $commandXML->appendChild($dom->createTextNode($name)); 111 } 112 } 113 } 114 115 return $dom; 116 } 117 118 /** 119 * {@inheritdoc} 120 */ 121 protected function describeInputArgument(InputArgument $argument, array $options = []) 122 { 123 $this->writeDocument($this->getInputArgumentDocument($argument)); 124 } 125 126 /** 127 * {@inheritdoc} 128 */ 129 protected function describeInputOption(InputOption $option, array $options = []) 130 { 131 $this->writeDocument($this->getInputOptionDocument($option)); 132 } 133 134 /** 135 * {@inheritdoc} 136 */ 137 protected function describeInputDefinition(InputDefinition $definition, array $options = []) 138 { 139 $this->writeDocument($this->getInputDefinitionDocument($definition)); 140 } 141 142 /** 143 * {@inheritdoc} 144 */ 145 protected function describeCommand(Command $command, array $options = []) 146 { 147 $this->writeDocument($this->getCommandDocument($command)); 148 } 149 150 /** 151 * {@inheritdoc} 152 */ 153 protected function describeApplication(Application $application, array $options = []) 154 { 155 $this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null)); 156 } 157 158 /** 159 * Appends document children to parent node. 160 */ 161 private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent) 162 { 163 foreach ($importedParent->childNodes as $childNode) { 164 $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, true)); 165 } 166 } 167 168 /** 169 * Writes DOM document. 170 */ 171 private function writeDocument(\DOMDocument $dom) 172 { 173 $dom->formatOutput = true; 174 $this->write($dom->saveXML()); 175 } 176 177 private function getInputArgumentDocument(InputArgument $argument): \DOMDocument 178 { 179 $dom = new \DOMDocument('1.0', 'UTF-8'); 180 181 $dom->appendChild($objectXML = $dom->createElement('argument')); 182 $objectXML->setAttribute('name', $argument->getName()); 183 $objectXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0); 184 $objectXML->setAttribute('is_array', $argument->isArray() ? 1 : 0); 185 $objectXML->appendChild($descriptionXML = $dom->createElement('description')); 186 $descriptionXML->appendChild($dom->createTextNode($argument->getDescription())); 187 188 $objectXML->appendChild($defaultsXML = $dom->createElement('defaults')); 189 $defaults = \is_array($argument->getDefault()) ? $argument->getDefault() : (\is_bool($argument->getDefault()) ? [var_export($argument->getDefault(), true)] : ($argument->getDefault() ? [$argument->getDefault()] : [])); 190 foreach ($defaults as $default) { 191 $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); 192 $defaultXML->appendChild($dom->createTextNode($default)); 193 } 194 195 return $dom; 196 } 197 198 private function getInputOptionDocument(InputOption $option): \DOMDocument 199 { 200 $dom = new \DOMDocument('1.0', 'UTF-8'); 201 202 $dom->appendChild($objectXML = $dom->createElement('option')); 203 $objectXML->setAttribute('name', '--'.$option->getName()); 204 $pos = strpos($option->getShortcut() ?? '', '|'); 205 if (false !== $pos) { 206 $objectXML->setAttribute('shortcut', '-'.substr($option->getShortcut(), 0, $pos)); 207 $objectXML->setAttribute('shortcuts', '-'.str_replace('|', '|-', $option->getShortcut())); 208 } else { 209 $objectXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : ''); 210 } 211 $objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0); 212 $objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0); 213 $objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0); 214 $objectXML->appendChild($descriptionXML = $dom->createElement('description')); 215 $descriptionXML->appendChild($dom->createTextNode($option->getDescription())); 216 217 if ($option->acceptValue()) { 218 $defaults = \is_array($option->getDefault()) ? $option->getDefault() : (\is_bool($option->getDefault()) ? [var_export($option->getDefault(), true)] : ($option->getDefault() ? [$option->getDefault()] : [])); 219 $objectXML->appendChild($defaultsXML = $dom->createElement('defaults')); 220 221 if (!empty($defaults)) { 222 foreach ($defaults as $default) { 223 $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); 224 $defaultXML->appendChild($dom->createTextNode($default)); 225 } 226 } 227 } 228 229 return $dom; 230 } 231} 232