Symfony - 如何根据另一个节点值验证配置节点?
Symfony - How to validate configuration node against another node value?
在我的 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;
}
我需要检查指定的 class 是否实现了我的包的特定特征部分。
如何读取 function($node)
中 class
的值?
这是一个有趣的问题,所以我决定试验一下,看看如何解决。通常,人们只会进行更一般的验证,这就是为什么我猜你不能直接在 getConfigTreeBuilder
函数中进行验证。或者至少我找不到办法。您可以尝试执行 function($node) use($rootNode)
但您无法获取 node
的值。因此,即使您尝试在匿名函数范围内执行 $rootNode->getNode('class')
,您也无法获得实际值。
另一方面,您可以转到 Extension
class(位于 DependencyInjection
目录)并在那里进行验证。像这样的东西应该可以完成工作:
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);
}
不知道这样算不算"best practice",如果大家有更好的解决办法,请指出:)
您所要做的就是在 scalarNode('class')
节点中调用 validate()
方法。看看:
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
节点都完成了验证。 $value
是 class
节点的值,所以它是您的 class.
的名称
其余:
$reflection = new \ReflectionClass($value);
$traitsNames = $reflection->getTraitNames();
return false === \in_array('myTrait', $traitsNames, true);
它只是一段 php 验证特征是否被实现的代码。
在我的 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;
}
我需要检查指定的 class 是否实现了我的包的特定特征部分。
如何读取 function($node)
中 class
的值?
这是一个有趣的问题,所以我决定试验一下,看看如何解决。通常,人们只会进行更一般的验证,这就是为什么我猜你不能直接在 getConfigTreeBuilder
函数中进行验证。或者至少我找不到办法。您可以尝试执行 function($node) use($rootNode)
但您无法获取 node
的值。因此,即使您尝试在匿名函数范围内执行 $rootNode->getNode('class')
,您也无法获得实际值。
另一方面,您可以转到 Extension
class(位于 DependencyInjection
目录)并在那里进行验证。像这样的东西应该可以完成工作:
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);
}
不知道这样算不算"best practice",如果大家有更好的解决办法,请指出:)
您所要做的就是在 scalarNode('class')
节点中调用 validate()
方法。看看:
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
节点都完成了验证。 $value
是 class
节点的值,所以它是您的 class.
其余:
$reflection = new \ReflectionClass($value);
$traitsNames = $reflection->getTraitNames();
return false === \in_array('myTrait', $traitsNames, true);
它只是一段 php 验证特征是否被实现的代码。