Skip to content

Commit

Permalink
[Config] Ability to add and override node types without having to sub…
Browse files Browse the repository at this point in the history
…class NodeBuilder
  • Loading branch information
vicb committed Mar 17, 2011
1 parent 2743abc commit 9fd7d05
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 11 deletions.
53 changes: 47 additions & 6 deletions src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php
Expand Up @@ -19,6 +19,21 @@
class NodeBuilder implements NodeParentInterface
{
protected $parent;
protected $nodeMapping;

/**
* Constructor
*
*/
public function __construct()
{
$this->nodeMapping = array(
'variable' => __NAMESPACE__.'\\VariableNodeDefinition',
'scalar' => __NAMESPACE__.'\\ScalarNodeDefinition',
'boolean' => __NAMESPACE__.'\\BooleanNodeDefinition',
'array' => __NAMESPACE__.'\\ArrayNodeDefinition',
);
}

/**
* Set the parent node
Expand Down Expand Up @@ -100,16 +115,13 @@ public function end()
*
* @return NodeDefinition The child node
*
* @throws \RuntimeException When the node type is not supported
* @throws \RuntimeException When the node type is not registered
* @throws \RuntimeException When the node class is not found
*/
public function node($name, $type)
{
$class = $this->getNodeClass($type);

if (!class_exists($class)) {
throw new \RuntimeException(sprintf('Unknown node type: "%s"', $type));
}

$node = new $class($name);

if ($node instanceof ParentNodeDefinitionInterface) {
Expand All @@ -127,15 +139,44 @@ public function node($name, $type)
return $node;
}

/**
* Add or override a node Type
*
* @param string $type The name of the type
* @param string $class The fully qualified name the node definition class
*/
public function setNodeClass($type, $class)
{
$this->nodeMapping[strtolower($type)] = $class;

return $this;
}

/**
* Returns the class name of the node definition
*
* @param string $type The node type
*
* @return string The node definition class name
*
* @throws \RuntimeException When the node type is not registered
* @throws \RuntimeException When the node class is not found
*/
protected function getNodeClass($type)
{
return $class = __NAMESPACE__.'\\'.ucfirst($type).'NodeDefinition';
$type = strtolower($type);

if (!isset($this->nodeMapping[$type])) {
throw new \RuntimeException(sprintf('The node type "%s" is not registered.', $type));
}

$class = $this->nodeMapping[$type];

if (!class_exists($class)) {
throw new \RuntimeException(sprintf('The node class "%s" does not exist.', $class));
}

return $class;
}

}
@@ -0,0 +1,74 @@
<?php

namespace Symfony\Tests\Component\Config\Definition\Builder;

use Symfony\Component\Config\Definition\Builder\NodeBuilder;
use Symfony\Component\Config\Definition\Builder\VariableNodeDefinition;

class NodeBuilderTest extends \PHPUnit_Framework_TestCase
{
/**
* @expectedException \RuntimeException
*/
public function testThrowsAnExceptionWhenTryingToCreateANonRegisteredNodeType()
{
$builder = new NodeBuilder();
$builder->node('', 'foobar');
}

/**
* @expectedException \RuntimeException
*/
public function testThrowsAnExceptionWhenTheNodeClassIsNotFound()
{
$builder = new NodeBuilder();
$builder
->setNodeClass('noclasstype', '\\foo\\bar\\noclass')
->node('', 'noclasstype');
}

public function testAddingANewNodeType()
{
$class = __NAMESPACE__.'\\SomeNodeDefinition';

$builder = new NodeBuilder();
$node = $builder
->setNodeClass('newtype', $class)
->node('', 'newtype');

$this->assertEquals(get_class($node), $class);
}

public function testOverridingAnExistingNodeType()
{
$class = __NAMESPACE__.'\\SomeNodeDefinition';

$builder = new NodeBuilder();
$node = $builder
->setNodeClass('variable', $class)
->node('', 'variable');

$this->assertEquals(get_class($node), $class);
}

public function testNodeTypesAreNotCaseSensitive()
{
$builder = new NodeBuilder();

$node1 = $builder->node('', 'VaRiAbLe');
$node2 = $builder->node('', 'variable');

$this->assertEquals(get_class($node1), get_class($node2));

$builder->setNodeClass('CuStOm', __NAMESPACE__.'\\SomeNodeDefinition');

$node1 = $builder->node('', 'CUSTOM');
$node2 = $builder->node('', 'custom');

$this->assertEquals(get_class($node1), get_class($node2));
}
}

class SomeNodeDefinition extends VariableNodeDefinition
{
}
Expand Up @@ -2,7 +2,9 @@

namespace Symfony\Tests\Component\Config\Definition\Builder;

use Symfony\Tests\Component\Config\Definition\Builder\NodeBuilder as CustomNodeBuilder;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\Builder\NodeBuilder;

require __DIR__.'/../../Fixtures/Builder/NodeBuilder.php';
require __DIR__.'/../../Fixtures/Builder/BarNodeDefinition.php';
Expand All @@ -13,7 +15,7 @@ class TreeBuilderTest extends \PHPUnit_Framework_TestCase
public function testUsingACustomNodeBuilder()
{
$builder = new TreeBuilder();
$root = $builder->root('custom', 'array', new NodeBuilder());
$root = $builder->root('custom', 'array', new CustomNodeBuilder());

$nodeBuilder = $root->children();

Expand All @@ -27,7 +29,7 @@ public function testUsingACustomNodeBuilder()
public function testOverrideABuiltInNodeType()
{
$builder = new TreeBuilder();
$root = $builder->root('override', 'array', new NodeBuilder());
$root = $builder->root('override', 'array', new CustomNodeBuilder());

$definition = $root->children()->variableNode('variable');

Expand All @@ -37,7 +39,7 @@ public function testOverrideABuiltInNodeType()
public function testAddANodeType()
{
$builder = new TreeBuilder();
$root = $builder->root('override', 'array', new NodeBuilder());
$root = $builder->root('override', 'array', new CustomNodeBuilder());

$definition = $root->children()->barNode('variable');

Expand All @@ -47,7 +49,7 @@ public function testAddANodeType()
public function testCreateABuiltInNodeTypeWithACustomNodeBuilder()
{
$builder = new TreeBuilder();
$root = $builder->root('builtin', 'array', new NodeBuilder());
$root = $builder->root('builtin', 'array', new CustomNodeBuilder());

$definition = $root->children()->booleanNode('boolean');

Expand All @@ -57,9 +59,25 @@ public function testCreateABuiltInNodeTypeWithACustomNodeBuilder()
public function testPrototypedArrayNodeUseTheCustomNodeBuilder()
{
$builder = new TreeBuilder();
$root = $builder->root('override', 'array', new NodeBuilder());
$root = $builder->root('override', 'array', new CustomNodeBuilder());

$root->prototype('bar')->end();
}

public function testAnExtendedNodeBuilderGetsPropagatedToTheChildren()
{
$builder = new TreeBuilder();

$builder->root('propagation')
->children()
->setNodeClass('extended', 'Symfony\Tests\Component\Config\Definition\Builder\VariableNodeDefinition')
->node('foo', 'extended')->end()
->arrayNode('child')
->children()
->node('foo', 'extended')
->end()
->end()
->end()
->end();
}
}

0 comments on commit 9fd7d05

Please sign in to comment.