Symfony2配置组件 - 树构建器如何验证提供的单个选项?

时间:2014-08-24 15:58:31

标签: php symfony symfony-components

我的路由配置提供了两个选项:模板和选项。我想验证用户的配置必须只提供一个选项,而不是两个选项,但我不知道如何执行此操作:

routes:
  hello:
    title: Hello world
    template: %my_module/templates/hello.html.twig

  hello/%name:
    title: Hello again
    content: 'Hello {{name}}!'

1 个答案:

答案 0 :(得分:0)

默认情况下,ArrayNode不提供此功能,但我们可以扩展该功能。

<?php

namespace AndyTruong\Config\Definition;

use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;

class RadioArrayNodeDefinition extends ArrayNodeDefinition
{

    private $radioOptions = [];

    public function mustFillOnlyOneOfTheseKeys(array $keys)
    {
        $this->radioOptions[] = $keys;
    }

    protected function createNode()
    {
        $node = parent::createNode();
        $node->setFinalValidationClosures([
            [$this, 'validateRadioOptions']
        ]);
        return $node;
    }

    public function validateRadioOptions($value)
    {
        foreach ($this->radioOptions as $radioOptions) {
            $count = 0;
            foreach ($radioOptions as $radioKey) {
                if (!is_null($value[$radioKey])) {
                    $count++;
                }
            }

            switch ($count) {
                case 1:
                    return $value;

                case 0:
                    throw new InvalidConfigurationException('One of these keys is required but none given: ' . implode(', ', $radioOptions));

                default:
                    throw new InvalidConfigurationException('Only one of these keys is allowed: ' . implode(', ', $radioOptions));
            }
        }
    }
}

然后,我们可以使用以下新定义:

<?php

use Symfony\Component\Config\Definition\Builder\NodeBuilder;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;

$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('routing');

/* @var $route_item NodeBuilder */
$route_item = $rootNode->children()
  ->setNodeClass('radioArray', 'AndyTruong\Config\Definition\RadioArrayNodeDefinition')
  ->arrayNode('routes')
  ->prototype('radioArray');
$route_item->mustFillOnlyOneOfTheseKeys(['content', 'template']);