使用 ArrayNodeDefinition::addDefaultChildrenIfNoneSet() 的奇怪行为

weird behaviour using ArrayNodeDefinition::addDefaultChildrenIfNoneSet()

我在 Silex 框架中使用 Symfony 配置组件,我需要一个包含版本数组的数据数组:

some_data:
    # some config...
    versions:
        - 1.1
        - 1.2-beta
        ...

下面是配置树生成器的一瞥:

$node = $treeBuilder->root('some_data');

$node
    ->children()
        // some nodes...
        ->arrayNode('versions')
            ->addDefaultChildrenIfNoneSet()
            ->validate()
                ->ifTrue(function ($v) {
                    return !empty($v);
                })
                ->then(function ($v) {
                    $array = array_values(array_unique($v));
                    sort($array, SORT_NATURAL | SORT_FLAG_CASE);

                    return $array;
                })
            ->end()
            ->prototype('scalar')->defaultValue('1')->end()
        ->end()
    ->end()
->end()

当没有设置 versions 时,我得到默认的 1,好的。 但是当我添加一些其他版本然后尝试删除默认值 1 时,它总是在处理配置后返回。

有人明白我做错了什么吗? 这是预期的行为吗?

似乎 addDefaultChildrenIfNoneSet() 作为验证,在处理配置时 addDefaultChildrenIfNoneSet()->validate() 结果被合并。

要避免这种行为,只需将 performNoDeepMerging() 添加到节点 :

$node = $treeBuilder->root('some_data');

$node
    ->children()
        // some nodes...
        ->arrayNode('versions')
            ->addDefaultChildrenIfNoneSet()
            ->performNoDeepMerging() // This is the fix
            ->validate()
                ->ifTrue(function ($v) {
                    return !empty($v);
                })
                ->then(function ($v) {
                    $array = array_values(array_unique($v));
                    sort($array, SORT_NATURAL | SORT_FLAG_CASE);

                    return $array;
                })
            ->end()
            ->prototype('scalar')->defaultValue('1')->end()
        ->end()
    ->end()
->end()

http://symfony.com/doc/current/components/config/definition.html#optional-sections

另一种方法:

// add a default value on the array, not on the prototype :
$node
    ->children()
        // some nodes...
        ->arrayNode('versions')
            ->validate()
                ->ifTrue(function ($v) {
                    return !empty($v);
                })
                ->then(function ($v) {
                    $array = array_values(array_unique($v));
                    sort($array, SORT_NATURAL | SORT_FLAG_CASE);

                    return $array;
                })
            ->end()
            ->prototype('scalar')->end()
            ->defaultValue(['1']) // this is a fix
        ->end()
    ->end()
->end()

// or just use one validation rule
$node
    ->children()
        // some nodes...
        ->arrayNode('versions')
            ->validate()
                ->always(function ($v) { // another fix
                    if (empty($v)) {
                        return ['1'];
                    }

                    $array = array_values(array_unique($v));
                    sort($array, SORT_NATURAL | SORT_FLAG_CASE);

                    return $array;
                })
            ->end()
            ->prototype('scalar')->end()
        ->end()
    ->end()
->end()