diff --git a/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php b/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php index 4717e5e2dd..28c93d49ce 100644 --- a/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php +++ b/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php @@ -103,7 +103,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition /** * Adds children with a default value when none are defined. * - * @param integer|string|array $children The number of children|The child name|The children names to be added + * @param integer|string|array|null $children The number of children|The child name|The children names to be added * * This method is applicable to prototype nodes only. * @@ -111,7 +111,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition */ public function addDefaultChildrenIfNoneSet($children = null) { - $this->addDefaultChildren = null === $children ? 'defaults' : $children; + $this->addDefaultChildren = $children; return $this; } @@ -394,10 +394,24 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition ); } - if ($this->default && false !== $this->addDefaultChildren) { - throw new InvalidDefinitionException( - sprintf('A default value and default children might not be used together at path "%s"', $path) - ); + if (false !== $this->addDefaultChildren) { + if ($this->default) { + throw new InvalidDefinitionException( + sprintf('A default value and default children might not be used together at path "%s"', $path) + ); + } + + if (null !== $this->key && (null === $this->addDefaultChildren || is_integer($this->addDefaultChildren) && $this->addDefaultChildren > 0)) { + throw new InvalidDefinitionException( + sprintf('->addDefaultChildrenIfNoneSet() should set default children names as ->useAttributeAsKey() is used at path "%s"', $path) + ); + } + + if (null === $this->key && (is_string($this->addDefaultChildren) || is_array($this->addDefaultChildren))) { + throw new InvalidDefinitionException( + sprintf('->addDefaultChildrenIfNoneSet() might not set default children names as ->useAttributeAsKey() is not used at path "%s"', $path) + ); + } } } } diff --git a/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php b/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php index e8a52376ea..f800a3f8f5 100644 --- a/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php +++ b/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php @@ -124,11 +124,15 @@ class PrototypedArrayNode extends ArrayNode /** * Adds default children when none are set. * - * @param integer|string|array $children The number of children|The child name|The children names to be added + * @param integer|string|array|null $children The number of children|The child name|The children names to be added */ public function setAddChildrenIfNoneSet($children = array('defaults')) { - $this->defaultChildren = is_integer($children) && $children > 0 ? range(1, $children) : (array) $children; + if (null === $children) { + $this->defaultChildren = array('defaults'); + } else { + $this->defaultChildren = is_integer($children) && $children > 0 ? range(1, $children) : (array) $children; + } } /** diff --git a/tests/Symfony/Tests/Component/Config/Definition/Builder/ArrayNodeDefinitionTest.php b/tests/Symfony/Tests/Component/Config/Definition/Builder/ArrayNodeDefinitionTest.php index 93903c6302..b3495d4e44 100644 --- a/tests/Symfony/Tests/Component/Config/Definition/Builder/ArrayNodeDefinitionTest.php +++ b/tests/Symfony/Tests/Component/Config/Definition/Builder/ArrayNodeDefinitionTest.php @@ -13,6 +13,7 @@ namespace Symfony\Tests\Component\Config\Definition\Builder; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\Config\Definition\Builder\ScalarNodeDefinition; +use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException; class ArrayNodeDefinitionTest extends \PHPUnit_Framework_TestCase { @@ -21,7 +22,7 @@ class ArrayNodeDefinitionTest extends \PHPUnit_Framework_TestCase $parent = new ArrayNodeDefinition('root'); $child = new ScalarNodeDefinition('child'); - $node = $parent + $parent ->children() ->scalarNode('foo')->end() ->scalarNode('bar')->end() @@ -79,7 +80,7 @@ class ArrayNodeDefinitionTest extends \PHPUnit_Framework_TestCase $node->getNode(); } - public function testArrayNodeDefaultWhenUsingDefaultChildren() + public function testPrototypedArrayNodeDefaultWhenUsingDefaultChildren() { $node = new ArrayNodeDefinition('root'); $node @@ -90,6 +91,53 @@ class ArrayNodeDefinitionTest extends \PHPUnit_Framework_TestCase $this->assertEquals(array(array()), $tree->getDefaultValue()); } + /** + * @dataProvider providePrototypedArrayNodeDefaults + */ + public function testPrototypedArrayNodeDefault($args, $shouldThrowWhenUsingAttrAsKey, $shouldThrowWhenNotUsingAttrAsKey, $defaults) + { + $node = new ArrayNodeDefinition('root'); + $node + ->addDefaultChildrenIfNoneSet($args) + ->prototype('array') + ; + + try { + $tree = $node->getNode(); + $this->assertFalse($shouldThrowWhenNotUsingAttrAsKey); + $this->assertEquals($defaults, $tree->getDefaultValue()); + } catch (InvalidDefinitionException $e) { + $this->assertTrue($shouldThrowWhenNotUsingAttrAsKey); + } + + $node = new ArrayNodeDefinition('root'); + $node + ->useAttributeAsKey('attr') + ->addDefaultChildrenIfNoneSet($args) + ->prototype('array') + ; + + try { + $tree = $node->getNode(); + $this->assertFalse($shouldThrowWhenUsingAttrAsKey); + $this->assertEquals($defaults, $tree->getDefaultValue()); + } catch (InvalidDefinitionException $e) { + $this->assertTrue($shouldThrowWhenUsingAttrAsKey); + } + } + + public function providePrototypedArrayNodeDefaults() + { + return array( + array(null, true, false, array(array())), + array(2, true, false, array(array(), array())), + array('2', false, true, array('2' => array())), + array('foo', false, true, array('foo' => array())), + array(array('foo'), false, true, array('foo' => array())), + array(array('foo', 'bar'), false, true, array('foo' => array(), 'bar' => array())), + ); + } + public function testNestedPrototypedArrayNodes() { $node = new ArrayNodeDefinition('root'); @@ -98,7 +146,7 @@ class ArrayNodeDefinitionTest extends \PHPUnit_Framework_TestCase ->prototype('array') ->prototype('array') ; - $tree = $node->getNode(); + $node->getNode(); } protected function getField($object, $field)