4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Config\Definition\Dumper;
14 use Symfony\Component\Config\Definition\ArrayNode;
15 use Symfony\Component\Config\Definition\ConfigurationInterface;
16 use Symfony\Component\Config\Definition\EnumNode;
17 use Symfony\Component\Config\Definition\NodeInterface;
18 use Symfony\Component\Config\Definition\PrototypedArrayNode;
19 use Symfony\Component\Config\Definition\ScalarNode;
20 use Symfony\Component\Yaml\Inline;
23 * Dumps a Yaml reference configuration for the given configuration/node instance.
25 * @author Kevin Bond <kevinbond@gmail.com>
27 class YamlReferenceDumper
31 public function dump(ConfigurationInterface $configuration)
33 return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree());
36 public function dumpAtPath(ConfigurationInterface $configuration, $path)
38 $rootNode = $node = $configuration->getConfigTreeBuilder()->buildTree();
40 foreach (explode('.', $path) as $step) {
41 if (!$node instanceof ArrayNode) {
42 throw new \UnexpectedValueException(sprintf('Unable to find node at path "%s.%s"', $rootNode->getName(), $path));
45 /** @var NodeInterface[] $children */
46 $children = $node instanceof PrototypedArrayNode ? $this->getPrototypeChildren($node) : $node->getChildren();
48 foreach ($children as $child) {
49 if ($child->getName() === $step) {
56 throw new \UnexpectedValueException(sprintf('Unable to find node at path "%s.%s"', $rootNode->getName(), $path));
59 return $this->dumpNode($node);
62 public function dumpNode(NodeInterface $node)
64 $this->reference = '';
65 $this->writeNode($node);
66 $ref = $this->reference;
67 $this->reference = null;
73 * @param NodeInterface $node
74 * @param NodeInterface|null $parentNode
76 * @param bool $prototypedArray
78 private function writeNode(NodeInterface $node, NodeInterface $parentNode = null, $depth = 0, $prototypedArray = false)
84 $example = $node->getExample();
87 if ($node instanceof ArrayNode) {
88 $children = $node->getChildren();
90 if ($node instanceof PrototypedArrayNode) {
91 $children = $this->getPrototypeChildren($node);
95 if ($node->hasDefaultValue() && \count($defaultArray = $node->getDefaultValue())) {
97 } elseif (!\is_array($example)) {
101 } elseif ($node instanceof EnumNode) {
102 $comments[] = 'One of '.implode('; ', array_map('json_encode', $node->getValues()));
103 $default = $node->hasDefaultValue() ? Inline::dump($node->getDefaultValue()) : '~';
107 if ($node->hasDefaultValue()) {
108 $default = $node->getDefaultValue();
110 if (\is_array($default)) {
111 if (\count($defaultArray = $node->getDefaultValue())) {
113 } elseif (!\is_array($example)) {
117 $default = Inline::dump($default);
123 if ($node->isRequired()) {
124 $comments[] = 'Required';
128 if ($node->isDeprecated()) {
129 $comments[] = sprintf('Deprecated (%s)', $node->getDeprecationMessage($node->getName(), $parentNode ? $parentNode->getPath() : $node->getPath()));
133 if ($example && !\is_array($example)) {
134 $comments[] = 'Example: '.$example;
137 $default = '' != (string) $default ? ' '.$default : '';
138 $comments = \count($comments) ? '# '.implode(', ', $comments) : '';
140 $key = $prototypedArray ? '-' : $node->getName().':';
141 $text = rtrim(sprintf('%-21s%s %s', $key, $default, $comments), ' ');
143 if ($info = $node->getInfo()) {
144 $this->writeLine('');
145 // indenting multi-line info
146 $info = str_replace("\n", sprintf("\n%".($depth * 4).'s# ', ' '), $info);
147 $this->writeLine('# '.$info, $depth * 4);
150 $this->writeLine($text, $depth * 4);
154 $this->writeLine('');
156 $message = \count($defaultArray) > 1 ? 'Defaults' : 'Default';
158 $this->writeLine('# '.$message.':', $depth * 4 + 4);
160 $this->writeArray($defaultArray, $depth + 1);
163 if (\is_array($example)) {
164 $this->writeLine('');
166 $message = \count($example) > 1 ? 'Examples' : 'Example';
168 $this->writeLine('# '.$message.':', $depth * 4 + 4);
170 $this->writeArray($example, $depth + 1);
174 foreach ($children as $childNode) {
175 $this->writeNode($childNode, $node, $depth + 1, $node instanceof PrototypedArrayNode && !$node->getKeyAttribute());
181 * Outputs a single config reference line.
183 * @param string $text
186 private function writeLine($text, $indent = 0)
188 $indent = \strlen($text) + $indent;
189 $format = '%'.$indent.'s';
191 $this->reference .= sprintf($format, $text)."\n";
194 private function writeArray(array $array, $depth)
196 $isIndexed = array_values($array) === $array;
198 foreach ($array as $key => $value) {
199 if (\is_array($value)) {
206 $this->writeLine('- '.$val, $depth * 4);
208 $this->writeLine(sprintf('%-20s %s', $key.':', $val), $depth * 4);
211 if (\is_array($value)) {
212 $this->writeArray($value, $depth + 1);
218 * @param PrototypedArrayNode $node
222 private function getPrototypeChildren(PrototypedArrayNode $node)
224 $prototype = $node->getPrototype();
225 $key = $node->getKeyAttribute();
227 // Do not expand prototype if it isn't an array node nor uses attribute as key
228 if (!$key && !$prototype instanceof ArrayNode) {
229 return $node->getChildren();
232 if ($prototype instanceof ArrayNode) {
233 $keyNode = new ArrayNode($key, $node);
234 $children = $prototype->getChildren();
236 if ($prototype instanceof PrototypedArrayNode && $prototype->getKeyAttribute()) {
237 $children = $this->getPrototypeChildren($prototype);
241 foreach ($children as $childNode) {
242 $keyNode->addChild($childNode);
245 $keyNode = new ScalarNode($key, $node);
249 if (null !== $prototype->getInfo()) {
250 $info .= ': '.$prototype->getInfo();
252 $keyNode->setInfo($info);
254 return array($key => $keyNode);