Symfony - 如何针对另一个节点值验证配置节点?

问题描述 投票:3回答:2

在我的Configuration.php中,我有如下结构:

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

  $rootNode
    ->children()
      ->scalarNode('class')->cannotBeEmpty()->end()
      ->arrayNode('social_network')
        ->children()
          ->arrayNode('facebook')
            ->validate()
              ->ifTrue(function($node) {

                // my logic to validate if the 'class' specified implements my trait

              })
              ->thenInvalid('You must use XXXXXX trait in your class.')
            ->end()
            ->children()
              ->scalarNode('app_id')->isRequired()->cannotBeEmpty()->end()
              ->scalarNode('secret')->isRequired()->cannotBeEmpty()->end()
            ->end()
          ->end()
        ->end()
      ->end()
    ->end();

    return $treeBuilder;
}

我需要检查指定的类是否实现了我的bundle的特定trait部分。

如何在class中读取function($node)的值?

validation symfony configuration traits
2个回答
2
投票

这是一个有趣的问题,所以我决定试验一下,看看它是如何完成的。通常,人们只会进行更一般的验证,这就是为什么我猜你不能在getConfigTreeBuilder函数中直接进行验证。或者至少我找不到方法。你可以尝试做function($node) use($rootNode),但你不能得到node的价值。因此,即使您尝试在匿名函数范围内执行$rootNode->getNode('class'),您也无法获得实际值。

另一方面,你可以做的是去你的Extension班(位于DependencyInjection dir)并在那里进行验证。这样的事情应该做的工作:

public function load(array $configs, ContainerBuilder $container)
{
    $configuration = new Configuration();
    $config = $this->processConfiguration($configuration, $configs);

    $class = $config['class'];

    // Apply your logic here...
    if(!$this->checkForTrait($class, 'myTrait')) {
        throw new \ErrorException("The class ".$class." should implement myTrait!");
    }

    $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
    $loader->load('services.yml');
}

private function checkForTrait($class, $trait)
{
    $class = new \ReflectionClass($class);
    $traits = $class->getTraitNames(); // returns an array of all trait names being currently used in that class.
    return in_array($trait, $traits);
}

我不知道这是否被视为“最佳实践”,所以如果有人有更好的解决方案,请指出:)


0
投票

您所要做的就是在validate()节点内调用scalarNode('class')方法。看一看:

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

    $rootNode
        ->children()
            ->scalarNode('class')
                ->cannotBeEmpty()
                ->validate()
                    ->ifTrue(function ($value) {
                        // my logic to validate if the 'class' specified implements my trait

                        $reflection = new \ReflectionClass($value);
                        $traitsNames = $reflection->getTraitNames();

                        return false === \in_array('myTrait', $traitsNames, true);
                    })
                    ->thenInvalid('You must use XXXXXX trait in your class.')
                ->end()
            ->end()
            ->arrayNode('social_network')
                ->children()
                    ->arrayNode('facebook')
                        ->children()
                            ->scalarNode('app_id')->isRequired()->cannotBeEmpty()->end()
                            ->scalarNode('secret')->isRequired()->cannotBeEmpty()->end()
                        ->end()
                    ->end()
                ->end()
            ->end()
        ->end()
    ;

    return $treeBuilder;
}

以这种方式,验证是根据标量class节点完成的。 $valueclass节点的值,所以它是你的类的名字。

其余的部分:

$reflection = new \ReflectionClass($value);
$traitsNames = $reflection->getTraitNames();

return false === \in_array('myTrait', $traitsNames, true);

它只是一段PHP代码,用于验证特征是否已实现。

© www.soinside.com 2019 - 2024. All rights reserved.