如何在Symfony 2配置中让配置节点同时支持字符串和数组?

15

我的配置节点source能够支持stringarray两种类型的值吗?

string中获取:

# Valid configuration 1
my_bundle:
    source: %kernel.root_dir%/../Resources/config/source.json

数组 获取数据:

# Valid configuration 2
my_bundle:
    source:
        operations: []
        commands: []
扩展类将能够区分它们:

扩展类将能够区分它们:

if (is_array($config['source']) {
    // Bootstrap from array
} else {
    // Bootstrap from file
}

我可能会使用类似这样的东西:

$rootNode->children()
    ->variableNode('source')
        ->validate()
            ->ifTrue(function ($v) { return !is_string($v) && !is_array($v); })
            ->thenInvalid('Configuration value must be either string or array.')
        ->end()
    ->end()
->end();

但是我如何对变量节点上的source结构(操作、命令等)添加约束条件(只有在其值为array类型时才应强制执行)?

2个回答

20

我认为你可以通过重构扩展来使用配置规范化。

在你的扩展中,更改代码以检查是否设置了路径。

if ($config['path'] !== null) {
    // Bootstrap from file.
} else {
    // Bootstrap from array.
}

允许用户使用字符串作为配置。

$rootNode
    ->children()
        ->arrayNode('source')
            ->beforeNormalization()
            ->ifString()
                ->then(function($value) { return array('path' => $value); })
            ->end()
            ->children()
                ->scalarNode('foo')
                // ...
            ->end()
        ->end()
    ->end()
;

这样,您可以允许用户使用一个字符串或一个数组,并对其进行验证。

请参阅Symfony文档中的规范化

希望有所帮助。 最好的祝愿。


不错。当pathoperationscommands被设置时,我应该处理这种情况。+1给我。 - gremo

7

如果结合一些自定义验证逻辑,可以使用变量节点类型:

<?php
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;

public function getConfigTreeBuilder()
{
    $treeBuilder = new TreeBuilder();
    $rootNode = $treeBuilder->root('my_bundle');

    $rootNode
        ->children()
            ->variableNode('source')
                ->validate()
                    ->ifTrue(function ($v) {
                        return false === is_string($v) && false === is_array($v);
                    })
                    ->thenInvalid('Here you message about why it is invalid')
                ->end()
            ->end()
        ->end();
    ;

    return $treeBuilder;
}

这将成功处理以下内容:
my_bundle:
    source: foo

# and

my_bundle:
    source: [foo, bar]

但它不会处理:
my_bundle:
    source: 1

# or

my_bundle
    source: ~

当然了,你将无法得到一般配置节点提供的良好验证规则,也无法在传递的数组(或字符串)上使用这些验证规则。但是,你可以在使用的闭包中验证传递的数据。


是的,我以前已经使用过类似的东西。但这次数组节点非常复杂。 - gremo
我不确定是否可能。你不能使用另一种结构,比如JMSDiExtraBundle使用的那种吗? - Ramon Kleiss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接