[Config] allowed the disabling of key normalization on some array nodes

This reverts #6086
This commit is contained in:
Fabien Potencier 2012-12-15 16:07:29 +01:00
parent 1de60c902c
commit e31d4f19d9
9 changed files with 105 additions and 94 deletions

View File

@ -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

View File

@ -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;
}
/**

View File

@ -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.
*

View File

@ -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);

View File

@ -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);
}
/**

View File

@ -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'),
)
);
}
}

View File

@ -1,51 +0,0 @@
<?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;
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')),
)
);
}
}

View File

@ -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

View File

@ -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);
}
/**