Конфигурация node поддерживает как строку, так и массив в конфигурации Symfony 2?

Может ли моя конфигурация node source поддерживать значения string и array?

Поиск из string:

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

Поиск из array:

# 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 (операции, команды и т.д.) на переменную node (ее следует применять только тогда, когда ее значение имеет тип array)?

Ответы

Ответ 1

Я думаю, вы можете использовать нормализацию конфигурации путем рефакторинга своего расширения.

В своем расширении измените свой код, чтобы проверить, установлен ли путь

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 для нормализации.

Надеюсь, это полезно. Наилучшее отношение.

Ответ 2

Можно использовать тип variable node в сочетании с некоторой пользовательской логикой проверки:

<?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: ~

Конечно, вы не получите правильные правила проверки, которые нормальная конфигурация node предоставит вам, и вы не сможете использовать эти правила проверки для массива (или строки), но вы сможете подтвердите переданные данные в используемом закрытии.