具有Symfony2Treebuilder的yaml中的递归结构
-
21-12-2019 - |
题
Symfony中的配置等于验证配置。我想用treebuilder验证我的配置。在yml示例中,我给出了一个配置树的样子的例子(将来,树会比现在更大)。但要做到这一点,我需要一个创建一个结构。
现在你能帮我,创建树构建器吗?我已经尝试了arrayNode和原型的所有内容,但它不起作用。我得到例外,如
"FatalErrorException:错误:调用/var/www/menu_bundle/src/my/MenuBundle/DependencyInjection/Configuration中的未定义方法Symfony\Component\Config\Definition\Builder odeBuilder::prototype()。php第29行"
基本理念:
我想生成一个Symfony2-bundle,它在HTML中创建了一个menuStructure。为了生成HTML代码,我需要将yaml配置拉入对象结构,这可以工作,但使用symfony进行验证不起作用。..
这是一个关于如何菜单的快速示例。yml应该看起来像:
my_menu_structure:
menu:
name: test
cssClass: blubb
children:
child:
name: item1
route: route1
position: 0
child:
name: item11
route: route11
position: 0
child:
name: item2
route: route2
position: 1
现在我想在Symfony2中配置Treebuilder,但它不起作用。.
经过几次尝试,这是我的最后一个版本:
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('my_menu');
$rootNode
->children()
->arrayNode('menu')
->scalarNode('cssClass')
->defaultValue(array())
->prototype('array')
->scalarNode('name')
->scalarNode('route')
->scalarNode('Position')
->prototype('array')
->end()
->end()
->end();
我已经构建了Menu和MenuItems的对象。到目前为止一切正常,但我无法配置treebuilder。我正在寻找的是一种重用零件的方法(menuItem-:名字,路线和孩子)在树屋里,但到目前为止我发现的所有东西都帮不了我。..其他一切都有效,我唯一的问题是,我无法配置Treebuilder,并且我无法使用$this->container->get('menu.name')。这会引发异常:您已经请求了一项不存在的服务"menu.name"。
到目前为止,我已经尝试了prototype('array')的一些配置,但是phpStorm每次都说,它无法找到一个scalarNode作为prototype或->prototype()->children()->scalarNode()的子项。.
解决方案
我知道这个问题是从2014年1月开始的,但是当寻找错误消息"Call to undefined method Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition::arrayNode()"的解决方案时,这个StackOverflow问题出现在搜索结果中。
接受的答案实际上并没有提到错误消息的原因。
原海报给出的例子如下:
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('my_menu');
$rootNode
->children()
->arrayNode('menu')
->scalarNode('cssClass')
->defaultValue(array())
->prototype('array')
->scalarNode('name')
->scalarNode('route')
->scalarNode('Position')
->prototype('array')
->end()
->end()
->end();
这是不正确的,因为每个节点必须以 end()
打电话。正如[文件][1]所述:
一般说来:定义节点后,调用end()将使您在层次结构中提升一步。
在我自己的情况下,我不清楚的是,在arrayNode中,两者都是 arrayNode()
定义为基础 children()
定义必须结束。
所以上面的例子将是正确的,如下所示:
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('my_menu');
$rootNode
->children()
->scalarNode('cssClass')->end()
->arrayNode('menu')
->prototype('array')
->scalarNode('name')->end()
->scalarNode('route')->end()
->scalarNode('Position')->end()
->end()
->end()
->end()
->end();
希望这能帮助其他人比我更快地解决问题。
其他提示
what you can do is to configure your rootNode this way:
$rootNode
->children()
->arrayNode('menu')
->isRequired()
->prototype('array')
->children()
->scalarNode('label')->isRequired()->end()
->scalarNode('class')->end() // I added an optional class parameter
//others parameters
->arrayNode('sub_menu')
->prototype('array')
->children()
->scalarNode('label')->isRequired()->end()
->scalarNode('route')->end()
->scalarNode('class')->end()
// add as many parameters as you want for your children
->end()
->end()
->end()
->end()
->end()
->end();
Then you want to pass this variable to a service. Very simple class :
class AdminMenu
{
protected $menu;
public function setMenu($menu)
{
$this->menu = $menu;
}
public function getMenu()
{
return $this->menu;
}
}
In you services.xml
<parameter key="wf.admin_menu.class">Acme\AdminBundle\Library\AdminMenu</parameter>
<service id="wf.admin_menu" class="%wf.admin_menu.class%">
</service>
In your bundleAdminExtension class
$myServiceDefintion = $container->getDefinition('wf.admin_menu');
$myServiceDefintion->addMethodCall('setMenu', array($config['menu']));
Finally, in any controller you want:
$menu = $this->container->get('wf.admin_menu');
That's all :)
Edit : Here's what my config looks like
my_bundle_admin:
menu:
unique_key:
label : 'Level1-1'
class : ''
sub_menu:
sub_unique_key1:
label: 'Level2-1'
route: 'my_route'
sub_unique_key2:
label: 'Level2-2'
route: 'my_route'
unique_key_2:
label : 'Level1-2'
sub_menu :
sub_unique_key1:
label : 'Level2-1'
route : 'my_route'
sub_unique_key2:
label : 'Level2-2'
route : 'my_route'