Skip to content

Instantly share code, notes, and snippets.

@xphere
Last active September 17, 2022 15:58
Show Gist options
  • Save xphere/c7cd079dd4775410bad6 to your computer and use it in GitHub Desktop.
Save xphere/c7cd079dd4775410bad6 to your computer and use it in GitHub Desktop.
Recursive symfony/configuration
<?php
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* Helper function to create recursive nodes
*/
function recursiveNode(string $name, callable $callback)
{
$builder = new TreeBuilder();
$root = $builder->root($name, 'variable');
$root->defaultValue([]);
$root
->beforeNormalization()
->ifTrue(function ($v) { return !is_array($v); })
->thenInvalid("The {$name} element must be an array.")
;
$root
->beforeNormalization()
->always(function (iterable $children) use ($builder, $callback) {
$config = [];
foreach ($children as $name => $child) {
$node = $builder->root($name);
$callback($node, $callback);
$config[$name] = $node->getNode(true)->finalize($child);
}
return $config;
})
;
return $root;
}
/**
* Usage of recursiveNode
* This allows for configuration like:
*
* routing_bundle:
* routes:
* - name: route_1
* url: url_1
* children:
* - name: route_2
* url: url_2
* - name: route_3
* url: url_3
* children:
* - name: route_4
* - url: url_4
* - name: route_5
* url: url_5
*/
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$tree = new TreeBuilder();
$root = $tree->root('my_routing_bundle');
$root
->children()
->append(
recursiveNode('routes', function ($node, $recursive) {
return $this->routes($node, $recursive);
})
)
->end()
;
return $tree;
}
private function routes(ArrayNodeDefinition $node, callable $recursive)
{
$node
->addDefaultsIfNotSet()
->children()
->scalarNode('description')->end()
->scalarNode('name')
->isRequired()
->cannotBeEmpty()
->end()
->scalarNode('url')
->defaultNull()
->end()
->append(recursiveNode('children', $recursive))
;
}
}
@ephp
Copy link

ephp commented Sep 21, 2021

Works great with Symfony 3 & 4, bur doesn't work with Symfony 5. How can fix this recursive node builder?

@aesislabs
Copy link

@ephp Did you find a solution for sf 5 ? I tried for several hours without success

@xphere Any help ?

Thanks a lot !

@ephp
Copy link

ephp commented Sep 23, 2021

@aesislabs I solve!

    private function recursiveMenuNode(string $name, callable $callback)
    {
        $builder = new TreeBuilder($name, 'variable');
        $root = $builder->getRootNode();

        $root->defaultValue([]);

        $root
            ->beforeNormalization()
            ->ifTrue(function ($v) { return !is_array($v); })
            ->thenInvalid("The {$name} element must be an array.")
        ;

        $root
            ->beforeNormalization()
            ->always(function (iterable $children) use ($callback) {
                $config = [];
                foreach ($children as $name => $child) {
                    $builder = new TreeBuilder($name);
                    $node = $builder->getRootNode();
                    $callback($node, $callback);
                    $config[$name] = $node->getNode(true)->finalize($child);
                }
                return $config;
            })
        ;
        
        return $root;
    }

@aesislabs
Copy link

Works great, thanks a lot !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment