Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 50c62d7

Browse files
committed
feature #31287 [Config] Introduce find method in ArrayNodeDefinition to ease configuration tree manipulation (jschaedl)
This PR was squashed before being merged into the 4.4 branch (closes #31287). Discussion ---------- [Config] Introduce find method in ArrayNodeDefinition to ease configuration tree manipulation | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no <!-- don't forget to update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | #27534 <!-- #-prefixed issue number(s), if any --> | License | MIT | Doc PR | tbd. ### Description This PR introduces a new `find(string $nodePath)`method in the `ArrayNodeDefinition` class, which helps you finding the right node to prepend configuration to ease configuration tree manipulation. ### How to use it ```php class Configuration implements ConfigurationInterface { public function getConfigTreeBuilder() { ... $rootNode ->children() ->arrayNode('social_media_channels') ->children() ->booleanNode('enable')->end() ->arrayNode('twitter')->end() ->arrayNode('facebook')->end() ->arrayNode('instagram')->end() ->end() ->end() ->end() ; $this->changeSocialMediaChannelConfiguration($rootNode->find('social_media_channels.enable')); $this->addTwitterConfiguration($rootNode->find('social_media_channels.twitter')); $this->addFacebookConfiguration($rootNode->find('social_media_channels.facebook')); $this->addInstagramConfiguration($rootNode->find('social_media_channels.instagram')); return $treeBuilder; } private function changeSocialMediaChannelConfiguration(NodeDefinition $node) { $node ->defaultTrue() ; } private function addTwitterConfiguration(NodeDefinition $node) { $node ->children() ->integerNode('client_id')->end() ->scalarNode('client_secret')->end() ->end() ; } private function addFacebookConfiguration(NodeDefinition $node) { $node ->children() ->integerNode('client_id')->end() ->scalarNode('client_secret')->end() ->end() ; } private function addInstagramConfiguration(NodeDefinition $node) { $node ->children() ->integerNode('client_id')->end() ->scalarNode('client_secret')->end() ->end() ; } } ``` Commits ------- e3b248a [Config] Introduce find method in ArrayNodeDefinition to ease configuration tree manipulation
2 parents f06a35b + e3b248a commit 50c62d7

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed

src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,4 +523,26 @@ public function getChildNodeDefinitions()
523523
{
524524
return $this->children;
525525
}
526+
527+
/**
528+
* Finds a node defined by the given $nodePath.
529+
*
530+
* @param string $nodePath The path of the node to find. e.g "doctrine.orm.mappings"
531+
*/
532+
public function find(string $nodePath): NodeDefinition
533+
{
534+
$firstPathSegment = (false === $pathSeparatorPos = strpos($nodePath, $this->pathSeparator))
535+
? $nodePath
536+
: substr($nodePath, 0, $pathSeparatorPos);
537+
538+
if (null === $node = ($this->children[$firstPathSegment] ?? null)) {
539+
throw new \RuntimeException(sprintf('Node with name "%s" does not exist in the current node "%s".', $firstPathSegment, $this->name));
540+
}
541+
542+
if (false === $pathSeparatorPos) {
543+
return $node;
544+
}
545+
546+
return $node->find(substr($nodePath, $pathSeparatorPos + \strlen($this->pathSeparator)));
547+
}
526548
}

src/Symfony/Component/Config/Tests/Definition/Builder/ArrayNodeDefinitionTest.php

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
16+
use Symfony\Component\Config\Definition\Builder\BooleanNodeDefinition;
17+
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
1618
use Symfony\Component\Config\Definition\Builder\ScalarNodeDefinition;
1719
use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException;
1820
use Symfony\Component\Config\Definition\Processor;
@@ -357,6 +359,85 @@ public function testCannotBeEmptyOnConcreteNode()
357359
$node->getNode()->finalize([]);
358360
}
359361

362+
public function testFindShouldThrowExceptionIfNodeDoesNotExistInRootNode()
363+
{
364+
$this->expectException(\RuntimeException::class);
365+
$this->expectExceptionMessage('Node with name "child" does not exist in the current node "root".');
366+
367+
$rootNode = new ArrayNodeDefinition('root');
368+
$rootNode
369+
->children()
370+
->arrayNode('social_media_channels')->end()
371+
->end()
372+
;
373+
374+
$rootNode->find('child');
375+
}
376+
377+
public function testFindShouldHandleComplexConfigurationProperly()
378+
{
379+
$rootNode = new ArrayNodeDefinition('root');
380+
$rootNode
381+
->children()
382+
->arrayNode('social_media_channels')
383+
->children()
384+
->booleanNode('enable')->end()
385+
->arrayNode('twitter')->end()
386+
->arrayNode('facebook')->end()
387+
->arrayNode('instagram')
388+
->children()
389+
->booleanNode('enable')->end()
390+
->arrayNode('accounts')->end()
391+
->end()
392+
->end()
393+
->end()
394+
->append(
395+
$mailerNode = (new ArrayNodeDefinition('mailer'))
396+
->children()
397+
->booleanNode('enable')->end()
398+
->arrayNode('transports')->end()
399+
->end()
400+
)
401+
->end()
402+
;
403+
404+
$this->assertNode('social_media_channels', ArrayNodeDefinition::class, $rootNode->find('social_media_channels'));
405+
$this->assertNode('enable', BooleanNodeDefinition::class, $rootNode->find('social_media_channels.enable'));
406+
$this->assertNode('twitter', ArrayNodeDefinition::class, $rootNode->find('social_media_channels.twitter'));
407+
$this->assertNode('facebook', ArrayNodeDefinition::class, $rootNode->find('social_media_channels.facebook'));
408+
$this->assertNode('instagram', ArrayNodeDefinition::class, $rootNode->find('social_media_channels.instagram'));
409+
$this->assertNode('enable', BooleanNodeDefinition::class, $rootNode->find('social_media_channels.instagram.enable'));
410+
$this->assertNode('accounts', ArrayNodeDefinition::class, $rootNode->find('social_media_channels.instagram.accounts'));
411+
412+
$this->assertNode('enable', BooleanNodeDefinition::class, $mailerNode->find('enable'));
413+
$this->assertNode('transports', ArrayNodeDefinition::class, $mailerNode->find('transports'));
414+
}
415+
416+
public function testFindShouldWorkProperlyForNonDefaultPathSeparator()
417+
{
418+
$rootNode = new ArrayNodeDefinition('root');
419+
$rootNode
420+
->setPathSeparator('.|')
421+
->children()
422+
->arrayNode('mailer.configuration')
423+
->children()
424+
->booleanNode('enable')->end()
425+
->arrayNode('transports')->end()
426+
->end()
427+
->end()
428+
;
429+
430+
$this->assertNode('mailer.configuration', ArrayNodeDefinition::class, $rootNode->find('mailer.configuration'));
431+
$this->assertNode('enable', BooleanNodeDefinition::class, $rootNode->find('mailer.configuration.|enable'));
432+
$this->assertNode('transports', ArrayNodeDefinition::class, $rootNode->find('mailer.configuration.|transports'));
433+
}
434+
435+
protected function assertNode(string $expectedName, string $expectedType, NodeDefinition $actualNode): void
436+
{
437+
$this->assertInstanceOf($expectedType, $actualNode);
438+
$this->assertSame($expectedName, $this->getField($actualNode, 'name'));
439+
}
440+
360441
protected function getField($object, $field)
361442
{
362443
$reflection = new \ReflectionProperty($object, $field);

0 commit comments

Comments
 (0)