我的Symfony2项目中有以下配置:
<?php
namespace Acme\CommonBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* This is the class that validates and merges configuration from your app/config files
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
*/
class Configuration implements ConfigurationInterface
{
/**
* {@inheritDoc}
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('acme_common');
$rootNode
->children()
->arrayNode('controller')
->children()
->arrayNode('controllers') // overwrite defaults declared above for specific controllers
->prototype('array')
->children()
->scalarNode('title')->end()
->append($this->addActionsNode())
->append($this->addViewsNode())
->end()
->end()
->end()
->end()
->end()
->end();
return $treeBuilder;
}
/**
* Add the actions node, e.g.:
* actions:
* edit:
* name: Edit
* path: edit
* icon: icon-edit
* width: 45
* archive:
* name: Archive
* path: archive
* icon: icon-thrash
* width: 75
*
* These are the actions that will be shown in the index view
*
* @return ArrayNodeDefinition|NodeDefinition
*/
protected function addActionsNode()
{
$node = $this->getNode('actions');
$node
->useAttributeAsKey('key')
->prototype('array')
->children()
->scalarNode('name')->end()
->scalarNode('path')->end()
->scalarNode('icon')->end()
->integerNode('width')->end()
->end()
->end();
return $node;
}
/**
* Configure the templates used, e.g.:
* views:
* index: :AcmeCommon:Crud/list.html.twig
* edit: :AcmeCommon:Crud/edit.html.twig
*
* @return ArrayNodeDefinition|NodeDefinition
*/
protected function addViewsNode()
{
$node = $this->getNode('views');
$node
->children()
->scalarNode('index')->end()
->scalarNode('edit')->end()
->end();
return $node;
}
/**
* Helper function to build a node
*
* @param string $name
*
* @return \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition|NodeDefinition
*/
protected function getNode($name)
{
$builder = new TreeBuilder();
$node = $builder->root($name);
return $node;
}
}
我的想法是,我可以为我正在编写的一堆CRUD控制器配置一些东西。 actions和views节点是可选的。只有在要覆盖某些默认值时才应使用它们。配置可能如下所示:
acme_common:
controller:
controllers:
acme_foo_controller:
title: Foo
actions:
edit:
name: Edit
path: edit
icon: icon-edit
width: 45
views:
index: :AcmeCommon:Foo/list.html.twig
edit: :AcmeCommon:Foo/edit.html.twig
acme_bar_controller:
title: Bar
views:
index: :AcmeCommon:Bar/list.html.twig
acme_baz_controller:
title: Baz
这会产生一个如下所示的数组:
Array
(
[controller] => Array
(
[controllers] => Array
(
[acme_foo_controller] => Array
(
[title] => Foo
[actions] => Array
(
[edit] => Array
(
[name] => Edit
[path] => edit
[icon] => icon-edit
[width] => 45
)
)
[views] => Array
(
[index] => :AcmeCommon:Foo/list.html.twig
[edit] => :AcmeCommon:Foo/edit.html.twig
)
)
[acme_bar_controller] => Array
(
[title] => Bar
[views] => Array
(
[index] => :AcmeCommon:Bar/list.html.twig
)
[actions] => Array
(
)
)
[acme_baz_controller] => Array
(
[title] => Baz
[actions] => Array
(
)
)
)
)
)
正如您所看到的,当未声明actions
时,它仍然作为空数组添加。我希望它能简单地省略actions
并使结果数组看起来像:
Array
(
[controller] => Array
(
[controllers] => Array
(
[acme_foo_controller] => Array
(
[title] => Foo
[actions] => Array
(
[edit] => Array
(
[name] => Edit
[path] => edit
[icon] => icon-edit
[width] => 45
)
)
[views] => Array
(
[index] => :AcmeCommon:Foo/list.html.twig
[edit] => :AcmeCommon:Foo/edit.html.twig
)
)
[acme_bar_controller] => Array
(
[title] => Bar
[views] => Array
(
[index] => :AcmeCommon:Bar/list.html.twig
)
)
[acme_baz_controller] => Array
(
[title] => Baz
)
)
)
)
这可能吗?
答案 0 :(得分:1)
我通过使用xdebug逐步执行代码来解决这个问题。看起来PrototypeNode
总是有一个默认值,这是一个空数组。进一步探测显示在最终确定阶段应用该空阵列。但是,这个阶段的最后一步是应用终结闭包,这也恰好是规范化闭包。要删除不需要的空数组,需要向父节点添加normalize()->always()
,并为其提供一个返回修改后的数组的闭包。
您修改过的示例:
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('acme_common');
$rootNode
->children()
->arrayNode('controller')
->children()
->arrayNode('controllers') // overwrite defaults declared above for specific controllers
->prototype('array')
->validate()
->always(function($v){
if ( empty($v['action']) )
unset($v['action']);
return $v;
})
->end()
->children()
->scalarNode('title')->end()
->append($this->addActionsNode())
->append($this->addViewsNode())
->end()
->end()
->end()
->end()
->end()
->end();
return $treeBuilder;
}
答案 1 :(得分:0)
您可以使用前置界面进行配置:http://symfony.com/doc/current/cookbook/bundles/prepend_extension.html 在那里你可以删除空数组并在容器中再次获取它。