Symfony 4:如何在包配置中允许数组节点的动态值?

Symfony 4: how to allow dynamic values for array nodes in bundle configuration?

在我的包的 Configuration 中,我定义了以下内容,例如:

$treeBuilder = new TreeBuilder('foo');
$treeBuilder
    ->getRootNode()
    ->children()
        ->arrayNode('foobar')
            ->scalarPrototype()->end()
            ->defaultValue([])
        ->end()
    ->end()
;

我。例如,捆绑包需要 foo.foobar 中的值数组。现在,就我的包而言,这些值取决于应用程序 运行 所在的环境。因此,通过环境变量提供此配置值是有意义的。 Since Symfony 3.4 可以处理环境变量的值。所以这个数组可以存储 JSON 编码在环境变量中,然后通过 %env(json:FOO)% 解码。所以不必写

foo:
    foobar:
        - Lorem
        - Ipsum
        - Dolor

可以改用

foo:
    foobar: '%env(json:FOO)%'

哪里

FOO=["Lorem","Ipsum","Dolor"]

然而,当 Symfony 试图这样做时抛出以下异常:

A dynamic value is not compatible with a "Symfony\Component\Config\Definition\PrototypedArrayNode" node type at path "foo.foobar".

允许数组节点使用此类动态值的正确方法是什么?例如,我是否需要在配置树中实现自己的规范化?

你需要在.env文件中定义JSON为string

这是正确的:FOO='["Lorem","Ipsum","Dolor"]'

静态yaml配置和'%env(json:FOO)%'有很大区别:env变量的内容在编译时不可用。见 docs:

You can reference environment variables using the special syntax %env(ENV_VAR_NAME)%. The values of these options are resolved at runtime (only once per request, to not impact performance).

在你的 BundleExtension 中(在编译时)你的配置值 foobar 将包含像 env_514deb50f3dcab34_json_FOO_ac251f2b9ef3c85f94a68df880763311 这样的字符串(而不是真正的数组)。

这意味着您不能有条件地在您的包中加载某些配置,例如。
但是,应该在编译时验证此节点。在 JSON 的情况下,它不能被验证为 scalarNode(...),因为包含 JSON env-processor。无法验证为 arrayNode(...),因为 ArrayNode 不支持动态值。 所以你可以跳过验证:

$treeBuilder
    ->getRootNode()
    ->children()
        ->variableNode('foobar')->end()
    ->end()
;

您还可以在 bundle 中添加两个不同的配置项:用于静态配置(作为 arrayNode)和用于动态配置(作为 variableNode),然后检查扩展,只定义了其中一个。

PS:看起来不方便。但这些都是很自然的限制,如果我们记得环境变量可以在运行时更改(即在编译容器之后)。