From e31d4f19d9fe33d4f848bcdfd344b6da268b419d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 15 Dec 2012 16:07:29 +0100 Subject: [PATCH] [Config] allowed the disabling of key normalization on some array nodes This reverts #6086 --- src/Symfony/Component/Config/CHANGELOG.md | 1 + .../Component/Config/Definition/ArrayNode.php | 36 +++++++++++++ .../Component/Config/Definition/BaseNode.php | 14 +++++ .../Builder/ArrayNodeDefinition.php | 15 ++++++ .../Component/Config/Definition/Processor.php | 41 ++------------- .../Config/Tests/Definition/ArrayNodeTest.php | 32 ++++++++++++ .../Config/Tests/Definition/ProcessorTest.php | 51 ------------------- .../Definition/PrototypedArrayNodeTest.php | 5 +- .../Extension/Extension.php | 4 +- 9 files changed, 105 insertions(+), 94 deletions(-) delete mode 100644 src/Symfony/Component/Config/Tests/Definition/ProcessorTest.php diff --git a/src/Symfony/Component/Config/CHANGELOG.md b/src/Symfony/Component/Config/CHANGELOG.md index 63c244078f..18065b26b4 100644 --- a/src/Symfony/Component/Config/CHANGELOG.md +++ b/src/Symfony/Component/Config/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 2.2.0 ----- + * added a `keepKeys()` method for array nodes (to avoid key normalization) * added numerical type handling for config definitions * added convenience methods for optional configuration sections to ArrayNodeDefinition * added a utils class for XML manipulations diff --git a/src/Symfony/Component/Config/Definition/ArrayNode.php b/src/Symfony/Component/Config/Definition/ArrayNode.php index 170a9033dd..1af4acf420 100644 --- a/src/Symfony/Component/Config/Definition/ArrayNode.php +++ b/src/Symfony/Component/Config/Definition/ArrayNode.php @@ -29,6 +29,7 @@ class ArrayNode extends BaseNode implements PrototypeNodeInterface protected $addIfNotSet; protected $performDeepMerging; protected $ignoreExtraKeys; + protected $normalizeKeys; /** * Constructor. @@ -47,6 +48,41 @@ class ArrayNode extends BaseNode implements PrototypeNodeInterface $this->addIfNotSet = false; $this->allowNewKeys = true; $this->performDeepMerging = true; + $this->normalizeKeys = true; + } + + public function setNormalizeKeys($normalizeKeys) + { + $this->normalizeKeys = (Boolean) $normalizeKeys; + } + + /** + * Normalizes keys between the different configuration formats. + * + * Namely, you mostly have foo_bar in YAML while you have foo-bar in XML. + * After running this method, all keys are normalized to foo_bar. + * + * If you have a mixed key like foo-bar_moo, it will not be altered. + * The key will also not be altered if the target key already exists. + * + * @param mixed $value + * + * @return array The value with normalized keys + */ + protected function preNormalize($value) + { + if (!$this->normalizeKeys || !is_array($value)) { + return $value; + } + + foreach ($value as $k => $v) { + if (false !== strpos($k, '-') && false === strpos($k, '_') && !array_key_exists($normalizedKey = str_replace('-', '_', $k), $value)) { + $value[$normalizedKey] = $v; + unset($value[$k]); + } + } + + return $value; } /** diff --git a/src/Symfony/Component/Config/Definition/BaseNode.php b/src/Symfony/Component/Config/Definition/BaseNode.php index 28e7da4a02..0a97a5203c 100644 --- a/src/Symfony/Component/Config/Definition/BaseNode.php +++ b/src/Symfony/Component/Config/Definition/BaseNode.php @@ -247,6 +247,8 @@ abstract class BaseNode implements NodeInterface */ final public function normalize($value) { + $value = $this->preNormalize($value); + // run custom normalization closures foreach ($this->normalizationClosures as $closure) { $value = $closure($value); @@ -266,6 +268,18 @@ abstract class BaseNode implements NodeInterface return $this->normalizeValue($value); } + /** + * Normalizes the value before any other normalization is applied. + * + * @param $value + * + * @return $value The normalized array value + */ + protected function preNormalize($value) + { + return $value; + } + /** * Finalizes a value, applying all finalization closures. * diff --git a/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php b/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php index ae7d73b10c..b6b976d255 100644 --- a/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php +++ b/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php @@ -34,6 +34,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition protected $addDefaults; protected $addDefaultChildren; protected $nodeBuilder; + protected $normalizeKeys; /** * {@inheritDoc} @@ -51,6 +52,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition $this->performDeepMerging = true; $this->nullEquivalent = array(); $this->trueEquivalent = array(); + $this->normalizeKeys = true; } /** @@ -281,6 +283,18 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition return $this; } + /** + * Disables key normalization. + * + * @return ArrayNodeDefinition + */ + public function keepKeys() + { + $this->normalizeKeys = false; + + return $this; + } + /** * Appends a node definition. * @@ -368,6 +382,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition $node->setPerformDeepMerging($this->performDeepMerging); $node->setRequired($this->required); $node->setIgnoreExtraKeys($this->ignoreExtraKeys); + $node->setNormalizeKeys($this->normalizeKeys); if (null !== $this->normalization) { $node->setNormalizationClosures($this->normalization->before); diff --git a/src/Symfony/Component/Config/Definition/Processor.php b/src/Symfony/Component/Config/Definition/Processor.php index 10aca917c5..058c3bed34 100644 --- a/src/Symfony/Component/Config/Definition/Processor.php +++ b/src/Symfony/Component/Config/Definition/Processor.php @@ -23,16 +23,11 @@ class Processor * * @param NodeInterface $configTree The node tree describing the configuration * @param array $configs An array of configuration items to process - * @param bool $normalizeKeys Flag indicating if config key normalization is needed. True by default. * * @return array The processed configuration */ - public function process(NodeInterface $configTree, array $configs, $normalizeKeys = true) + public function process(NodeInterface $configTree, array $configs) { - if ($normalizeKeys) { - $configs = self::normalizeKeys($configs); - } - $currentConfig = array(); foreach ($configs as $config) { $config = $configTree->normalize($config); @@ -47,42 +42,12 @@ class Processor * * @param ConfigurationInterface $configuration The configuration class * @param array $configs An array of configuration items to process - * @param bool $normalizeKeys Flag indicating if config key normalization is needed. True by default. * * @return array The processed configuration */ - public function processConfiguration(ConfigurationInterface $configuration, array $configs, $normalizeKeys = true) + public function processConfiguration(ConfigurationInterface $configuration, array $configs) { - return $this->process($configuration->getConfigTreeBuilder()->buildTree(), $configs, $normalizeKeys); - } - - /** - * This method normalizes keys between the different configuration formats - * - * Namely, you mostly have foo_bar in YAML while you have foo-bar in XML. - * After running this method, all keys are normalized to foo_bar. - * - * If you have a mixed key like foo-bar_moo, it will not be altered. - * The key will also not be altered if the target key already exists. - * - * @param array $config - * - * @return array the config with normalized keys - */ - public static function normalizeKeys(array $config) - { - foreach ($config as $key => $value) { - if (is_array($value)) { - $config[$key] = self::normalizeKeys($value); - } - - if (false !== strpos($key, '-') && false === strpos($key, '_') && !array_key_exists($normalizedKey = str_replace('-', '_', $key), $config)) { - $config[$normalizedKey] = $config[$key]; - unset($config[$key]); - } - } - - return $config; + return $this->process($configuration->getConfigTreeBuilder()->buildTree(), $configs); } /** diff --git a/src/Symfony/Component/Config/Tests/Definition/ArrayNodeTest.php b/src/Symfony/Component/Config/Tests/Definition/ArrayNodeTest.php index ef45ba8137..605bc69367 100644 --- a/src/Symfony/Component/Config/Tests/Definition/ArrayNodeTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/ArrayNodeTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Config\Tests\Definition; use Symfony\Component\Config\Definition\ArrayNode; +use Symfony\Component\Config\Definition\PrototypedArrayNode; class ArrayNodeTest extends \PHPUnit_Framework_TestCase { @@ -54,4 +55,35 @@ class ArrayNodeTest extends \PHPUnit_Framework_TestCase $node->normalize(array('foo' => 'bar')); $this->assertTrue(true, 'No exception was thrown when setIgnoreExtraKeys is true'); } + + /** + * @dataProvider getPreNormalizationTests + */ + public function testPreNormalize($denormalized, $normalized) + { + $node = new ArrayNode('foo'); + + $r = new \ReflectionMethod($node, 'preNormalize'); + $r->setAccessible(true); + + $this->assertSame($normalized, $r->invoke($node, $denormalized)); + } + + public function getPreNormalizationTests() + { + return array( + array( + array('foo-bar' => 'foo'), + array('foo_bar' => 'foo'), + ), + array( + array('foo-bar_moo' => 'foo'), + array('foo-bar_moo' => 'foo'), + ), + array( + array('foo-bar' => null, 'foo_bar' => 'foo'), + array('foo-bar' => null, 'foo_bar' => 'foo'), + ) + ); + } } diff --git a/src/Symfony/Component/Config/Tests/Definition/ProcessorTest.php b/src/Symfony/Component/Config/Tests/Definition/ProcessorTest.php deleted file mode 100644 index 56368ac8a2..0000000000 --- a/src/Symfony/Component/Config/Tests/Definition/ProcessorTest.php +++ /dev/null @@ -1,51 +0,0 @@ - - * - * 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; - -use Symfony\Component\Config\Definition\Processor; - -class ProcessorTest extends \PHPUnit_Framework_TestCase -{ - /** - * @dataProvider getKeyNormalizationTests - */ - public function testNormalizeKeys($denormalized, $normalized) - { - $this->assertSame($normalized, Processor::normalizeKeys($denormalized)); - } - - public function getKeyNormalizationTests() - { - return array( - array( - array('foo-bar' => 'foo'), - array('foo_bar' => 'foo'), - ), - array( - array('foo-bar_moo' => 'foo'), - array('foo-bar_moo' => 'foo'), - ), - array( - array('foo-bar' => null, 'foo_bar' => 'foo'), - array('foo-bar' => null, 'foo_bar' => 'foo'), - ), - array( - array('foo-bar' => array('foo-bar' => 'foo')), - array('foo_bar' => array('foo_bar' => 'foo')), - ), - array( - array('foo_bar' => array('foo-bar' => 'foo')), - array('foo_bar' => array('foo_bar' => 'foo')), - ) - ); - } -} diff --git a/src/Symfony/Component/Config/Tests/Definition/PrototypedArrayNodeTest.php b/src/Symfony/Component/Config/Tests/Definition/PrototypedArrayNodeTest.php index 31d3c89f5c..d200574ecd 100644 --- a/src/Symfony/Component/Config/Tests/Definition/PrototypedArrayNodeTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/PrototypedArrayNodeTest.php @@ -17,7 +17,6 @@ use Symfony\Component\Config\Definition\ScalarNode; class PrototypedArrayNodeTest extends \PHPUnit_Framework_TestCase { - public function testGetDefaultValueReturnsAnEmptyArrayForPrototypes() { $node = new PrototypedArrayNode('root'); @@ -31,8 +30,8 @@ class PrototypedArrayNodeTest extends \PHPUnit_Framework_TestCase $node = new PrototypedArrayNode('root'); $prototype = new ArrayNode(null, $node); $node->setPrototype($prototype); - $node->setDefaultValue(array ('test')); - $this->assertEquals(array ('test'), $node->getDefaultValue()); + $node->setDefaultValue(array('test')); + $this->assertEquals(array('test'), $node->getDefaultValue()); } // a remapped key (e.g. "mapping" -> "mappings") should be unset after being used diff --git a/src/Symfony/Component/DependencyInjection/Extension/Extension.php b/src/Symfony/Component/DependencyInjection/Extension/Extension.php index b821ea68db..e5c51a7b58 100644 --- a/src/Symfony/Component/DependencyInjection/Extension/Extension.php +++ b/src/Symfony/Component/DependencyInjection/Extension/Extension.php @@ -75,11 +75,11 @@ abstract class Extension implements ExtensionInterface, ConfigurationExtensionIn return Container::underscore($classBaseName); } - final protected function processConfiguration(ConfigurationInterface $configuration, array $configs, $normalizeKeys = true) + final protected function processConfiguration(ConfigurationInterface $configuration, array $configs) { $processor = new Processor(); - return $processor->processConfiguration($configuration, $configs, $normalizeKeys); + return $processor->processConfiguration($configuration, $configs); } /**