使用Symfony2 Treebuilder进行yaml中的递归结构

时间:2014-02-25 09:20:13

标签: php symfony yaml config symfony-2.4

Symfony中的配置等于验证配置。 我想用treebuilder验证我的配置。在yml-example中,我给出了一个很好的例子,说明配置树的外观(将来,树将比现在更大)。但要做到这一点,我需要一个创建一个结构。
你能帮助我,创建一个树木建造者吗?我已尝试使用arrayNode和原型,但它无法正常工作。我得到像

这样的例外

“FatalErrorException:Error:在/var/www/menu_bundle/src/my/MenuBundle/DependencyInjection/Configuration.php第29行调用未定义的方法Symfony \ Component \ Config \ Definition \ Builder \ NodeBuilder :: prototype()”


基本理念:

我想生成一个Symfony2-bundle,它以HTML格式创建一个menuStructure。为了生成HTML代码,我需要将yaml-configuration拉入对象结构,这是有效的,但是使用symfony进行验证不起作用...


这是一个关于menu.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。 我正在寻找的是一种在treebuilder中重用一个部分(menuItem-:name,route和children)的方法,但到目前为止我发现的一切都无法帮助我...... 其他所有工作,我唯一的问题是,我无法配置Treebuilder,我无法使用$ this-> container-> get('menu.name')从yml中获取配置。这会引发异常:您已请求不存在的服务“menu.name”。

到目前为止,我已尝试使用原型('array')进行一些配置,但phpStorm每次都说,它找不到scalarNode作为原型的子项或 - > prototype() - > children( ) - > scalarNode()..

2 个答案:

答案 0 :(得分:1)

您可以做的是以这种方式配置rootNode:

    $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();

然后,您希望将此变量传递给服务。 非常简单的课程:

class AdminMenu
{

    protected $menu;

    public function setMenu($menu)
    {
        $this->menu = $menu;
    }

    public function getMenu()
    {
        return $this->menu;
    }


}

在你的services.xml

    <parameter key="wf.admin_menu.class">Acme\AdminBundle\Library\AdminMenu</parameter>

    <service id="wf.admin_menu" class="%wf.admin_menu.class%">
    </service>

在您的bundleAdminExtension类

    $myServiceDefintion = $container->getDefinition('wf.admin_menu');
    $myServiceDefintion->addMethodCall('setMenu', array($config['menu']));

最后,在您想要的任何控制器中:

 $menu = $this->container->get('wf.admin_menu');

全部:)

编辑:这是我的配置的样子

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'

答案 1 :(得分:0)

我知道这个问题可以追溯到januari 2014,但是在寻找错误消息的解决方案“调用未定义的方法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();

希望这有助于其他人比我更快地解决问题。