[Config] Create XML Reference Dumper
This commit is contained in:
parent
1b2ef74a9a
commit
05e9ca7509
@ -11,7 +11,8 @@
|
|||||||
|
|
||||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||||
|
|
||||||
use Symfony\Component\Config\Definition\ReferenceDumper;
|
use Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper;
|
||||||
|
use Symfony\Component\Config\Definition\Dumper\XmlReferenceDumper;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
@ -21,6 +22,7 @@ use Symfony\Component\Config\Definition\ConfigurationInterface;
|
|||||||
* A console command for dumping available configuration reference
|
* A console command for dumping available configuration reference
|
||||||
*
|
*
|
||||||
* @author Kevin Bond <kevinbond@gmail.com>
|
* @author Kevin Bond <kevinbond@gmail.com>
|
||||||
|
* @author Wouter J <waldio.webdesign@gmail.com>
|
||||||
*/
|
*/
|
||||||
class ConfigDumpReferenceCommand extends ContainerDebugCommand
|
class ConfigDumpReferenceCommand extends ContainerDebugCommand
|
||||||
{
|
{
|
||||||
@ -32,7 +34,8 @@ class ConfigDumpReferenceCommand extends ContainerDebugCommand
|
|||||||
$this
|
$this
|
||||||
->setName('config:dump-reference')
|
->setName('config:dump-reference')
|
||||||
->setDefinition(array(
|
->setDefinition(array(
|
||||||
new InputArgument('name', InputArgument::OPTIONAL, 'The Bundle or extension alias')
|
new InputArgument('name', InputArgument::OPTIONAL, 'The Bundle or extension alias'),
|
||||||
|
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The format, either yaml or xml', 'yaml'),
|
||||||
))
|
))
|
||||||
->setDescription('Dumps default configuration for an extension')
|
->setDescription('Dumps default configuration for an extension')
|
||||||
->setHelp(<<<EOF
|
->setHelp(<<<EOF
|
||||||
@ -47,6 +50,9 @@ Example:
|
|||||||
or
|
or
|
||||||
|
|
||||||
<info>php %command.full_name% FrameworkBundle</info>
|
<info>php %command.full_name% FrameworkBundle</info>
|
||||||
|
|
||||||
|
With the <info>format</info> option specifies the format of the configuration, this is either yaml
|
||||||
|
or xml. When the option is not provided, yaml is used.
|
||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
;
|
;
|
||||||
@ -118,7 +124,17 @@ EOF
|
|||||||
|
|
||||||
$output->writeln($message);
|
$output->writeln($message);
|
||||||
|
|
||||||
$dumper = new ReferenceDumper();
|
switch ($input->getOption('format')) {
|
||||||
$output->writeln($dumper->dump($configuration));
|
case 'yaml':
|
||||||
|
$dumper = new YamlReferenceDumper();
|
||||||
|
break;
|
||||||
|
case 'xml':
|
||||||
|
$dumper = new XmlReferenceDumper();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new \InvalidArgumentException('Only the yaml and xml formats are supported.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$output->writeln($dumper->dump($configuration), $extension->getNamespace());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,6 +105,16 @@ class ArrayNode extends BaseNode implements PrototypeNodeInterface
|
|||||||
$this->xmlRemappings = $remappings;
|
$this->xmlRemappings = $remappings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the xml remappings that should be performed.
|
||||||
|
*
|
||||||
|
* @return array $remappings an array of the form array(array(string, string))
|
||||||
|
*/
|
||||||
|
public function getXmlRemappings()
|
||||||
|
{
|
||||||
|
return $this->xmlRemappings;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether to add default values for this array if it has not been
|
* Sets whether to add default values for this array if it has not been
|
||||||
* defined in any of the configuration files.
|
* defined in any of the configuration files.
|
||||||
|
@ -0,0 +1,300 @@
|
|||||||
|
<?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\Component\Config\Definition\Dumper;
|
||||||
|
|
||||||
|
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||||
|
use Symfony\Component\Config\Definition\NodeInterface;
|
||||||
|
use Symfony\Component\Config\Definition\ArrayNode;
|
||||||
|
use Symfony\Component\Config\Definition\EnumNode;
|
||||||
|
use Symfony\Component\Config\Definition\PrototypedArrayNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps a XML reference configuration for the given configuration/node instance.
|
||||||
|
*
|
||||||
|
* @author Wouter J <waldio.webdesign@gmail.com>
|
||||||
|
*/
|
||||||
|
class XmlReferenceDumper
|
||||||
|
{
|
||||||
|
private $reference;
|
||||||
|
|
||||||
|
public function dump(ConfigurationInterface $configuration, $namespace = null)
|
||||||
|
{
|
||||||
|
return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree(), $namespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dumpNode(NodeInterface $node, $namespace = null)
|
||||||
|
{
|
||||||
|
$this->reference = '';
|
||||||
|
$this->writeNode($node, 0, true, $namespace);
|
||||||
|
$ref = $this->reference;
|
||||||
|
$this->reference = null;
|
||||||
|
|
||||||
|
return $ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param NodeInterface $node
|
||||||
|
* @param integer $depth
|
||||||
|
* @param boolean $root If the node is the root node
|
||||||
|
* @param string $namespace The namespace of the node
|
||||||
|
*/
|
||||||
|
private function writeNode(NodeInterface $node, $depth = 0, $root = false, $namespace = null)
|
||||||
|
{
|
||||||
|
$rootName = ($root ? 'config' : $node->getName());
|
||||||
|
$rootNamespace = ($namespace ?: ($root ? 'http://example.org/schema/dic/'.$node->getName() : null));
|
||||||
|
|
||||||
|
// xml remapping
|
||||||
|
if ($node->getParent()) {
|
||||||
|
$remapping = array_filter($node->getParent()->getXmlRemappings(), function ($mapping) use ($rootName) {
|
||||||
|
return $rootName === $mapping[1];
|
||||||
|
});
|
||||||
|
|
||||||
|
if (count($remapping)) {
|
||||||
|
list($singular, $plural) = current($remapping);
|
||||||
|
$rootName = $singular;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$rootName = str_replace('_', '-', $rootName);
|
||||||
|
|
||||||
|
$rootAttributes = array();
|
||||||
|
$rootAttributeComments = array();
|
||||||
|
$rootChildren = array();
|
||||||
|
$rootComments = array();
|
||||||
|
|
||||||
|
if ($node instanceof ArrayNode) {
|
||||||
|
$children = $node->getChildren();
|
||||||
|
|
||||||
|
// comments about the root node
|
||||||
|
if ($rootInfo = $node->getInfo()) {
|
||||||
|
$rootComments[] = $rootInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($rootNamespace) {
|
||||||
|
$rootComments[] = 'Namespace: '.$rootNamespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
// render prototyped nodes
|
||||||
|
if ($node instanceof PrototypedArrayNode) {
|
||||||
|
array_unshift($rootComments, 'prototype');
|
||||||
|
|
||||||
|
if ($key = $node->getKeyAttribute()) {
|
||||||
|
$rootAttributes[$key] = str_replace('-', ' ', $rootName).' '.$key;
|
||||||
|
}
|
||||||
|
|
||||||
|
$prototype = $node->getPrototype();
|
||||||
|
|
||||||
|
if ($prototype instanceof ArrayNode) {
|
||||||
|
$children = $prototype->getChildren();
|
||||||
|
} else {
|
||||||
|
if ($prototype->hasDefaultValue()) {
|
||||||
|
$prototypeValue = $prototype->getDefaultValue();
|
||||||
|
} else {
|
||||||
|
switch (get_class($prototype)) {
|
||||||
|
case 'Symfony\Component\Config\Definition\ScalarNode':
|
||||||
|
$prototypeValue = 'scalar value';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'Symfony\Component\Config\Definition\FloatNode':
|
||||||
|
case 'Symfony\Component\Config\Definition\IntegerNode':
|
||||||
|
$prototypeValue = 'numeric value';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'Symfony\Component\Config\Definition\BooleanNode':
|
||||||
|
$prototypeValue = 'true|false';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'Symfony\Component\Config\Definition\EnumNode':
|
||||||
|
$prototypeValue = implode('|', array_map('json_encode', $prototype->getValues()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$prototypeValue = 'value';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get attributes and elements
|
||||||
|
foreach ($children as $child) {
|
||||||
|
if (!$child instanceof ArrayNode) {
|
||||||
|
// get attributes
|
||||||
|
|
||||||
|
// metadata
|
||||||
|
$name = str_replace('_', '-', $child->getName());
|
||||||
|
$value = '%%%%not_defined%%%%'; // use a string which isn't used in the normal world
|
||||||
|
|
||||||
|
// comments
|
||||||
|
$comments = array();
|
||||||
|
if ($info = $child->getInfo()) {
|
||||||
|
$comments[] = $info;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($example = $child->getExample()) {
|
||||||
|
$comments[] = 'Example: '.$example;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($child->isRequired()) {
|
||||||
|
$comments[] = 'Required';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($child instanceof EnumNode) {
|
||||||
|
$comments[] = 'One of '.implode('; ', array_map('json_encode', $child->getValues()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($comments)) {
|
||||||
|
$rootAttributeComments[$name] = implode(";\n", $comments);
|
||||||
|
}
|
||||||
|
|
||||||
|
// default values
|
||||||
|
if ($child->hasDefaultValue()) {
|
||||||
|
$value = $child->getDefaultValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// append attribute
|
||||||
|
$rootAttributes[$name] = $value;
|
||||||
|
} else {
|
||||||
|
// get elements
|
||||||
|
$rootChildren[] = $child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// render comments
|
||||||
|
|
||||||
|
// root node comment
|
||||||
|
if (count($rootComments)) {
|
||||||
|
foreach ($rootComments as $comment) {
|
||||||
|
$this->writeLine('<!-- '.$comment.' -->', $depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// attribute comments
|
||||||
|
if (count($rootAttributeComments)) {
|
||||||
|
foreach ($rootAttributeComments as $attrName => $comment) {
|
||||||
|
$commentDepth = $depth + 4 + strlen($attrName) + 2;
|
||||||
|
$commentLines = explode("\n", $comment);
|
||||||
|
$multiline = (count($commentLines) > 1);
|
||||||
|
$comment = implode(PHP_EOL.str_repeat(' ', $commentDepth), $commentLines);
|
||||||
|
|
||||||
|
if ($multiline) {
|
||||||
|
$this->writeLine('<!--', $depth);
|
||||||
|
$this->writeLine($attrName.': '.$comment, $depth + 4);
|
||||||
|
$this->writeLine('-->', $depth);
|
||||||
|
} else {
|
||||||
|
$this->writeLine('<!-- '.$attrName.': '.$comment.' -->', $depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// render start tag + attributes
|
||||||
|
$rootIsVariablePrototype = isset($prototypeValue);
|
||||||
|
$rootIsEmptyTag = (0 === count($rootChildren) && !$rootIsVariablePrototype);
|
||||||
|
$rootOpenTag = '<'.$rootName;
|
||||||
|
if (1 >= ($attributesCount = count($rootAttributes))) {
|
||||||
|
if (1 === $attributesCount) {
|
||||||
|
$rootOpenTag .= sprintf(' %s="%s"', current(array_keys($rootAttributes)), $this->writeValue(current($rootAttributes)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$rootOpenTag .= $rootIsEmptyTag ? ' />' : '>';
|
||||||
|
|
||||||
|
if ($rootIsVariablePrototype) {
|
||||||
|
$rootOpenTag .= $prototypeValue.'</'.$rootName.'>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->writeLine($rootOpenTag, $depth);
|
||||||
|
} else {
|
||||||
|
$this->writeLine($rootOpenTag, $depth);
|
||||||
|
|
||||||
|
$i = 1;
|
||||||
|
|
||||||
|
foreach ($rootAttributes as $attrName => $attrValue) {
|
||||||
|
$attr = sprintf('%s="%s"', $attrName, $this->writeValue($attrValue));
|
||||||
|
|
||||||
|
$this->writeLine($attr, $depth + 4);
|
||||||
|
|
||||||
|
if ($attributesCount === $i++) {
|
||||||
|
$this->writeLine($rootIsEmptyTag ? '/>' : '>', $depth);
|
||||||
|
|
||||||
|
if ($rootIsVariablePrototype) {
|
||||||
|
$rootOpenTag .= $prototypeValue.'</'.$rootName.'>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// render children tags
|
||||||
|
foreach ($rootChildren as $child) {
|
||||||
|
$this->writeLine('');
|
||||||
|
$this->writeNode($child, $depth + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// render end tag
|
||||||
|
if (!$rootIsEmptyTag && !$rootIsVariablePrototype) {
|
||||||
|
$this->writeLine('');
|
||||||
|
|
||||||
|
$rootEndTag = '</'.$rootName.'>';
|
||||||
|
$this->writeLine($rootEndTag, $depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs a single config reference line
|
||||||
|
*
|
||||||
|
* @param string $text
|
||||||
|
* @param int $indent
|
||||||
|
*/
|
||||||
|
private function writeLine($text, $indent = 0)
|
||||||
|
{
|
||||||
|
$indent = strlen($text) + $indent;
|
||||||
|
$format = '%'.$indent.'s';
|
||||||
|
|
||||||
|
$this->reference .= sprintf($format, $text)."\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the string conversion of the value.
|
||||||
|
*
|
||||||
|
* @param mixed $value
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function writeValue($value)
|
||||||
|
{
|
||||||
|
if ('%%%%not_defined%%%%' === $value) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_string($value) || is_numeric($value)) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $value) {
|
||||||
|
return 'false';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true === $value) {
|
||||||
|
return 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $value) {
|
||||||
|
return 'null';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($value)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($value)) {
|
||||||
|
return implode(',', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,202 @@
|
|||||||
|
<?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\Component\Config\Definition\Dumper;
|
||||||
|
|
||||||
|
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||||
|
use Symfony\Component\Config\Definition\NodeInterface;
|
||||||
|
use Symfony\Component\Config\Definition\ArrayNode;
|
||||||
|
use Symfony\Component\Config\Definition\ScalarNode;
|
||||||
|
use Symfony\Component\Config\Definition\EnumNode;
|
||||||
|
use Symfony\Component\Config\Definition\PrototypedArrayNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps a Yaml reference configuration for the given configuration/node instance.
|
||||||
|
*
|
||||||
|
* @author Kevin Bond <kevinbond@gmail.com>
|
||||||
|
*/
|
||||||
|
class YamlReferenceDumper
|
||||||
|
{
|
||||||
|
private $reference;
|
||||||
|
|
||||||
|
public function dump(ConfigurationInterface $configuration)
|
||||||
|
{
|
||||||
|
return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dumpNode(NodeInterface $node)
|
||||||
|
{
|
||||||
|
$this->reference = '';
|
||||||
|
$this->writeNode($node);
|
||||||
|
$ref = $this->reference;
|
||||||
|
$this->reference = null;
|
||||||
|
|
||||||
|
return $ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param NodeInterface $node
|
||||||
|
* @param integer $depth
|
||||||
|
*/
|
||||||
|
private function writeNode(NodeInterface $node, $depth = 0)
|
||||||
|
{
|
||||||
|
$comments = array();
|
||||||
|
$default = '';
|
||||||
|
$defaultArray = null;
|
||||||
|
$children = null;
|
||||||
|
$example = $node->getExample();
|
||||||
|
|
||||||
|
// defaults
|
||||||
|
if ($node instanceof ArrayNode) {
|
||||||
|
$children = $node->getChildren();
|
||||||
|
|
||||||
|
if ($node instanceof PrototypedArrayNode) {
|
||||||
|
$prototype = $node->getPrototype();
|
||||||
|
|
||||||
|
if ($prototype instanceof ArrayNode) {
|
||||||
|
$children = $prototype->getChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for attribute as key
|
||||||
|
if ($key = $node->getKeyAttribute()) {
|
||||||
|
$keyNodeClass = 'Symfony\Component\Config\Definition\\'.($prototype instanceof ArrayNode ? 'ArrayNode' : 'ScalarNode');
|
||||||
|
$keyNode = new $keyNodeClass($key, $node);
|
||||||
|
$keyNode->setInfo('Prototype');
|
||||||
|
|
||||||
|
// add children
|
||||||
|
foreach ($children as $childNode) {
|
||||||
|
$keyNode->addChild($childNode);
|
||||||
|
}
|
||||||
|
$children = array($key => $keyNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$children) {
|
||||||
|
if ($node->hasDefaultValue() && count($defaultArray = $node->getDefaultValue())) {
|
||||||
|
$default = '';
|
||||||
|
} elseif (!is_array($example)) {
|
||||||
|
$default = '[]';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif ($node instanceof EnumNode) {
|
||||||
|
$comments[] = 'One of '.implode('; ', array_map('json_encode', $node->getValues()));
|
||||||
|
$default = '~';
|
||||||
|
} else {
|
||||||
|
$default = '~';
|
||||||
|
|
||||||
|
if ($node->hasDefaultValue()) {
|
||||||
|
$default = $node->getDefaultValue();
|
||||||
|
|
||||||
|
if (true === $default) {
|
||||||
|
$default = 'true';
|
||||||
|
} elseif (false === $default) {
|
||||||
|
$default = 'false';
|
||||||
|
} elseif (null === $default) {
|
||||||
|
$default = '~';
|
||||||
|
} elseif (is_array($default)) {
|
||||||
|
if ($node->hasDefaultValue() && count($defaultArray = $node->getDefaultValue())) {
|
||||||
|
$default = '';
|
||||||
|
} elseif (!is_array($example)) {
|
||||||
|
$default = '[]';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// required?
|
||||||
|
if ($node->isRequired()) {
|
||||||
|
$comments[] = 'Required';
|
||||||
|
}
|
||||||
|
|
||||||
|
// example
|
||||||
|
if ($example && !is_array($example)) {
|
||||||
|
$comments[] = 'Example: '.$example;
|
||||||
|
}
|
||||||
|
|
||||||
|
$default = (string) $default != '' ? ' '.$default : '';
|
||||||
|
$comments = count($comments) ? '# '.implode(', ', $comments) : '';
|
||||||
|
|
||||||
|
$text = rtrim(sprintf('%-20s %s %s', $node->getName().':', $default, $comments), ' ');
|
||||||
|
|
||||||
|
if ($info = $node->getInfo()) {
|
||||||
|
$this->writeLine('');
|
||||||
|
// indenting multi-line info
|
||||||
|
$info = str_replace("\n", sprintf("\n%".$depth * 4 . "s# ", ' '), $info);
|
||||||
|
$this->writeLine('# '.$info, $depth * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->writeLine($text, $depth * 4);
|
||||||
|
|
||||||
|
// output defaults
|
||||||
|
if ($defaultArray) {
|
||||||
|
$this->writeLine('');
|
||||||
|
|
||||||
|
$message = count($defaultArray) > 1 ? 'Defaults' : 'Default';
|
||||||
|
|
||||||
|
$this->writeLine('# '.$message.':', $depth * 4 + 4);
|
||||||
|
|
||||||
|
$this->writeArray($defaultArray, $depth + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($example)) {
|
||||||
|
$this->writeLine('');
|
||||||
|
|
||||||
|
$message = count($example) > 1 ? 'Examples' : 'Example';
|
||||||
|
|
||||||
|
$this->writeLine('# '.$message.':', $depth * 4 + 4);
|
||||||
|
|
||||||
|
$this->writeArray($example, $depth + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($children) {
|
||||||
|
foreach ($children as $childNode) {
|
||||||
|
$this->writeNode($childNode, $depth + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs a single config reference line
|
||||||
|
*
|
||||||
|
* @param string $text
|
||||||
|
* @param int $indent
|
||||||
|
*/
|
||||||
|
private function writeLine($text, $indent = 0)
|
||||||
|
{
|
||||||
|
$indent = strlen($text) + $indent;
|
||||||
|
$format = '%'.$indent.'s';
|
||||||
|
|
||||||
|
$this->reference .= sprintf($format, $text)."\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
private function writeArray(array $array, $depth)
|
||||||
|
{
|
||||||
|
$isIndexed = array_values($array) === $array;
|
||||||
|
|
||||||
|
foreach ($array as $key => $value) {
|
||||||
|
if (is_array($value)) {
|
||||||
|
$val = '';
|
||||||
|
} else {
|
||||||
|
$val = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($isIndexed) {
|
||||||
|
$this->writeLine('- '.$val, $depth * 4);
|
||||||
|
} else {
|
||||||
|
$this->writeLine(sprintf('%-20s %s', $key.':', $val), $depth * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($value)) {
|
||||||
|
$this->writeArray($value, $depth + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,183 +11,11 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Config\Definition;
|
namespace Symfony\Component\Config\Definition;
|
||||||
|
|
||||||
|
use Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dumps a reference configuration for the given configuration/node instance.
|
* @deprecated Deprecated since version 2.4, to be removed in 3.0. Use Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper instead.
|
||||||
*
|
|
||||||
* Currently, only YML format is supported.
|
|
||||||
*
|
|
||||||
* @author Kevin Bond <kevinbond@gmail.com>
|
|
||||||
*/
|
*/
|
||||||
class ReferenceDumper
|
class ReferenceDumper extends YamlReferenceDumper
|
||||||
{
|
{
|
||||||
private $reference;
|
|
||||||
|
|
||||||
public function dump(ConfigurationInterface $configuration)
|
|
||||||
{
|
|
||||||
return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function dumpNode(NodeInterface $node)
|
|
||||||
{
|
|
||||||
$this->reference = '';
|
|
||||||
$this->writeNode($node);
|
|
||||||
$ref = $this->reference;
|
|
||||||
$this->reference = null;
|
|
||||||
|
|
||||||
return $ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param NodeInterface $node
|
|
||||||
* @param integer $depth
|
|
||||||
*/
|
|
||||||
private function writeNode(NodeInterface $node, $depth = 0)
|
|
||||||
{
|
|
||||||
$comments = array();
|
|
||||||
$default = '';
|
|
||||||
$defaultArray = null;
|
|
||||||
$children = null;
|
|
||||||
$example = $node->getExample();
|
|
||||||
|
|
||||||
// defaults
|
|
||||||
if ($node instanceof ArrayNode) {
|
|
||||||
$children = $node->getChildren();
|
|
||||||
|
|
||||||
if ($node instanceof PrototypedArrayNode) {
|
|
||||||
$prototype = $node->getPrototype();
|
|
||||||
|
|
||||||
if ($prototype instanceof ArrayNode) {
|
|
||||||
$children = $prototype->getChildren();
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for attribute as key
|
|
||||||
if ($key = $node->getKeyAttribute()) {
|
|
||||||
$keyNode = new ArrayNode($key, $node);
|
|
||||||
$keyNode->setInfo('Prototype');
|
|
||||||
|
|
||||||
// add children
|
|
||||||
foreach ($children as $childNode) {
|
|
||||||
$keyNode->addChild($childNode);
|
|
||||||
}
|
|
||||||
$children = array($key => $keyNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$children) {
|
|
||||||
if ($node->hasDefaultValue() && count($defaultArray = $node->getDefaultValue())) {
|
|
||||||
$default = '';
|
|
||||||
} elseif (!is_array($example)) {
|
|
||||||
$default = '[]';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$default = '~';
|
|
||||||
|
|
||||||
if ($node->hasDefaultValue()) {
|
|
||||||
$default = $node->getDefaultValue();
|
|
||||||
|
|
||||||
if (true === $default) {
|
|
||||||
$default = 'true';
|
|
||||||
} elseif (false === $default) {
|
|
||||||
$default = 'false';
|
|
||||||
} elseif (null === $default) {
|
|
||||||
$default = '~';
|
|
||||||
} elseif (is_array($default)) {
|
|
||||||
if ($node->hasDefaultValue() && count($defaultArray = $node->getDefaultValue())) {
|
|
||||||
$default = '';
|
|
||||||
} elseif (!is_array($example)) {
|
|
||||||
$default = '[]';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// required?
|
|
||||||
if ($node->isRequired()) {
|
|
||||||
$comments[] = 'Required';
|
|
||||||
}
|
|
||||||
|
|
||||||
// example
|
|
||||||
if ($example && !is_array($example)) {
|
|
||||||
$comments[] = 'Example: '.$example;
|
|
||||||
}
|
|
||||||
|
|
||||||
$default = (string) $default != '' ? ' '.$default : '';
|
|
||||||
$comments = count($comments) ? '# '.implode(', ', $comments) : '';
|
|
||||||
|
|
||||||
$text = rtrim(sprintf('%-20s %s %s', $node->getName().':', $default, $comments), ' ');
|
|
||||||
|
|
||||||
if ($info = $node->getInfo()) {
|
|
||||||
$this->writeLine('');
|
|
||||||
// indenting multi-line info
|
|
||||||
$info = str_replace("\n", sprintf("\n%".$depth * 4 . "s# ", ' '), $info);
|
|
||||||
$this->writeLine('# '.$info, $depth * 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->writeLine($text, $depth * 4);
|
|
||||||
|
|
||||||
// output defaults
|
|
||||||
if ($defaultArray) {
|
|
||||||
$this->writeLine('');
|
|
||||||
|
|
||||||
$message = count($defaultArray) > 1 ? 'Defaults' : 'Default';
|
|
||||||
|
|
||||||
$this->writeLine('# '.$message.':', $depth * 4 + 4);
|
|
||||||
|
|
||||||
$this->writeArray($defaultArray, $depth + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_array($example)) {
|
|
||||||
$this->writeLine('');
|
|
||||||
|
|
||||||
$message = count($example) > 1 ? 'Examples' : 'Example';
|
|
||||||
|
|
||||||
$this->writeLine('# '.$message.':', $depth * 4 + 4);
|
|
||||||
|
|
||||||
$this->writeArray($example, $depth + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($children) {
|
|
||||||
foreach ($children as $childNode) {
|
|
||||||
$this->writeNode($childNode, $depth + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Outputs a single config reference line
|
|
||||||
*
|
|
||||||
* @param string $text
|
|
||||||
* @param int $indent
|
|
||||||
*/
|
|
||||||
private function writeLine($text, $indent = 0)
|
|
||||||
{
|
|
||||||
$indent = strlen($text) + $indent;
|
|
||||||
$format = '%'.$indent.'s';
|
|
||||||
|
|
||||||
$this->reference .= sprintf($format, $text)."\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
private function writeArray(array $array, $depth)
|
|
||||||
{
|
|
||||||
$isIndexed = array_values($array) === $array;
|
|
||||||
|
|
||||||
foreach ($array as $key => $value) {
|
|
||||||
if (is_array($value)) {
|
|
||||||
$val = '';
|
|
||||||
} else {
|
|
||||||
$val = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($isIndexed) {
|
|
||||||
$this->writeLine('- '.$val, $depth * 4);
|
|
||||||
} else {
|
|
||||||
$this->writeLine(sprintf('%-20s %s', $key.':', $val), $depth * 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_array($value)) {
|
|
||||||
$this->writeArray($value, $depth + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
<?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\Component\Config\Tests\Definition\Dumper;
|
||||||
|
|
||||||
|
use Symfony\Component\Config\Definition\Dumper\XmlReferenceDumper;
|
||||||
|
use Symfony\Component\Config\Tests\Fixtures\Configuration\ExampleConfiguration;
|
||||||
|
|
||||||
|
class XmlReferenceDumperTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
public function testDumper()
|
||||||
|
{
|
||||||
|
$configuration = new ExampleConfiguration();
|
||||||
|
|
||||||
|
$dumper = new XmlReferenceDumper();
|
||||||
|
$this->assertEquals($this->getConfigurationAsString(), $dumper->dump($configuration));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNamespaceDumper()
|
||||||
|
{
|
||||||
|
$configuration = new ExampleConfiguration();
|
||||||
|
|
||||||
|
$dumper = new XmlReferenceDumper();
|
||||||
|
$this->assertEquals(str_replace('http://example.org/schema/dic/acme_root', 'http://symfony.com/schema/dic/symfony', $this->getConfigurationAsString()), $dumper->dump($configuration, 'http://symfony.com/schema/dic/symfony'));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getConfigurationAsString()
|
||||||
|
{
|
||||||
|
return <<<EOL
|
||||||
|
<!-- Namespace: http://example.org/schema/dic/acme_root -->
|
||||||
|
<!-- scalar-required: Required -->
|
||||||
|
<!-- enum: One of "this"; "that" -->
|
||||||
|
<config
|
||||||
|
boolean="true"
|
||||||
|
scalar-empty=""
|
||||||
|
scalar-null="null"
|
||||||
|
scalar-true="true"
|
||||||
|
scalar-false="false"
|
||||||
|
scalar-default="default"
|
||||||
|
scalar-array-empty=""
|
||||||
|
scalar-array-defaults="elem1,elem2"
|
||||||
|
scalar-required=""
|
||||||
|
enum=""
|
||||||
|
>
|
||||||
|
|
||||||
|
<!-- some info -->
|
||||||
|
<!--
|
||||||
|
child3: this is a long
|
||||||
|
multi-line info text
|
||||||
|
which should be indented;
|
||||||
|
Example: example setting
|
||||||
|
-->
|
||||||
|
<array
|
||||||
|
child1=""
|
||||||
|
child2=""
|
||||||
|
child3=""
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- prototype -->
|
||||||
|
<parameter name="parameter name">scalar value</parameter>
|
||||||
|
|
||||||
|
<!-- prototype -->
|
||||||
|
<connection
|
||||||
|
user=""
|
||||||
|
pass=""
|
||||||
|
/>
|
||||||
|
|
||||||
|
</config>
|
||||||
|
|
||||||
|
EOL;
|
||||||
|
}
|
||||||
|
}
|
@ -9,25 +9,27 @@
|
|||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Symfony\Component\Config\Tests\Definition;
|
namespace Symfony\Component\Config\Tests\Definition\Dumper;
|
||||||
|
|
||||||
use Symfony\Component\Config\Definition\ReferenceDumper;
|
use Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper;
|
||||||
use Symfony\Component\Config\Tests\Fixtures\Configuration\ExampleConfiguration;
|
use Symfony\Component\Config\Tests\Fixtures\Configuration\ExampleConfiguration;
|
||||||
|
|
||||||
class ReferenceDumperTest extends \PHPUnit_Framework_TestCase
|
class YamlReferenceDumperTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
public function testDumper()
|
public function testDumper()
|
||||||
{
|
{
|
||||||
$configuration = new ExampleConfiguration();
|
$configuration = new ExampleConfiguration();
|
||||||
|
|
||||||
$dumper = new ReferenceDumper();
|
$dumper = new YamlReferenceDumper();
|
||||||
|
|
||||||
|
$this->markTestIncomplete('The Yaml Dumper currently does not support prototyped arrays');
|
||||||
$this->assertEquals($this->getConfigurationAsString(), $dumper->dump($configuration));
|
$this->assertEquals($this->getConfigurationAsString(), $dumper->dump($configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getConfigurationAsString()
|
private function getConfigurationAsString()
|
||||||
{
|
{
|
||||||
return <<<EOL
|
return <<<EOL
|
||||||
root:
|
acme_root:
|
||||||
boolean: true
|
boolean: true
|
||||||
scalar_empty: ~
|
scalar_empty: ~
|
||||||
scalar_null: ~
|
scalar_null: ~
|
||||||
@ -40,6 +42,8 @@ root:
|
|||||||
# Defaults:
|
# Defaults:
|
||||||
- elem1
|
- elem1
|
||||||
- elem2
|
- elem2
|
||||||
|
scalar_required: ~ # Required
|
||||||
|
enum: ~ # One of "this"; "that"
|
||||||
|
|
||||||
# some info
|
# some info
|
||||||
array:
|
array:
|
||||||
@ -50,12 +54,13 @@ root:
|
|||||||
# multi-line info text
|
# multi-line info text
|
||||||
# which should be indented
|
# which should be indented
|
||||||
child3: ~ # Example: example setting
|
child3: ~ # Example: example setting
|
||||||
array_prototype:
|
|
||||||
parameters:
|
parameters:
|
||||||
|
|
||||||
# Prototype
|
# Prototype
|
||||||
name:
|
name: ~
|
||||||
value: ~ # Required
|
connections:
|
||||||
|
# Prototype
|
||||||
|
- { user: ~, pass: ~ }
|
||||||
|
|
||||||
EOL;
|
EOL;
|
||||||
}
|
}
|
@ -19,9 +19,11 @@ class ExampleConfiguration implements ConfigurationInterface
|
|||||||
public function getConfigTreeBuilder()
|
public function getConfigTreeBuilder()
|
||||||
{
|
{
|
||||||
$treeBuilder = new TreeBuilder();
|
$treeBuilder = new TreeBuilder();
|
||||||
$rootNode = $treeBuilder->root('root');
|
$rootNode = $treeBuilder->root('acme_root');
|
||||||
|
|
||||||
$rootNode
|
$rootNode
|
||||||
|
->fixXmlConfig('parameter')
|
||||||
|
->fixXmlConfig('connection')
|
||||||
->children()
|
->children()
|
||||||
->booleanNode('boolean')->defaultTrue()->end()
|
->booleanNode('boolean')->defaultTrue()->end()
|
||||||
->scalarNode('scalar_empty')->end()
|
->scalarNode('scalar_empty')->end()
|
||||||
@ -31,6 +33,8 @@ class ExampleConfiguration implements ConfigurationInterface
|
|||||||
->scalarNode('scalar_default')->defaultValue('default')->end()
|
->scalarNode('scalar_default')->defaultValue('default')->end()
|
||||||
->scalarNode('scalar_array_empty')->defaultValue(array())->end()
|
->scalarNode('scalar_array_empty')->defaultValue(array())->end()
|
||||||
->scalarNode('scalar_array_defaults')->defaultValue(array('elem1', 'elem2'))->end()
|
->scalarNode('scalar_array_defaults')->defaultValue(array('elem1', 'elem2'))->end()
|
||||||
|
->scalarNode('scalar_required')->isRequired()->end()
|
||||||
|
->enumNode('enum')->values(array('this', 'that'))->end()
|
||||||
->arrayNode('array')
|
->arrayNode('array')
|
||||||
->info('some info')
|
->info('some info')
|
||||||
->canBeUnset()
|
->canBeUnset()
|
||||||
@ -47,15 +51,15 @@ class ExampleConfiguration implements ConfigurationInterface
|
|||||||
->end()
|
->end()
|
||||||
->end()
|
->end()
|
||||||
->end()
|
->end()
|
||||||
->arrayNode('array_prototype')
|
|
||||||
->children()
|
|
||||||
->arrayNode('parameters')
|
->arrayNode('parameters')
|
||||||
->useAttributeAsKey('name')
|
->useAttributeAsKey('name')
|
||||||
|
->prototype('scalar')->end()
|
||||||
|
->end()
|
||||||
|
->arrayNode('connections')
|
||||||
->prototype('array')
|
->prototype('array')
|
||||||
->children()
|
->children()
|
||||||
->scalarNode('value')->isRequired()->end()
|
->scalarNode('user')->end()
|
||||||
->end()
|
->scalarNode('pass')->end()
|
||||||
->end()
|
|
||||||
->end()
|
->end()
|
||||||
->end()
|
->end()
|
||||||
->end()
|
->end()
|
||||||
|
Reference in New Issue
Block a user