Symfony2:自定义配置根目录

5
我的应用程序由多个bundle组成,它们的名称类似于HelloWorldAdminBundleHelloWorldUserBundleHelloWorldDemoBundle。这会导致一个配置根目录,如hello_world_demohello_world_userhello_world_demo。我希望我的bundles的配置根是 helloworld_demo, helloworld_userhelloworld_admin。此时我必须提到,这不是一个技术上的问题,而更像是一个审美问题。
我尝试实现一个自定义扩展并在bundle中注册它:
public function build(ContainerBuilder $container)
{
    parent::build($container);

    $container->registerExtension(new HelloworldDemoExtension());
}

这个扩展:

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

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

    public function getAlias()
    {
        return 'hello_world_demo';
    }
}

最后是配置部分:
...
class Configuration implements ConfigurationInterface
{
    public function getConfigTreeBuilder()
    {
        $treeBuilder = new TreeBuilder();
        $rootNode = $treeBuilder->root('helloworld_demo');
        ...
        return $treeBuilder;
    }
}

我遵循了如何为Bundle公开一个语义化配置的指南,但是当我在config.yml中添加一个项目时,出现了以下错误:
There is no extension able to load the configuration for "helloworld_demo"
4个回答

3
我找到了解决问题的方法。它完全按照我的问题描述工作,但是默认扩展(名称为bundle)必须存在。
我现在有一个空的扩展,名为HelloWorldDemoExtension(别名为hello_world_demo),另外我添加了DemoExtension(别名为helloworld_demo),它可以正常工作。

3
我通过重写Symfony\Component\HttpKernel\Bundle\Bundle#getContainerExtension()方法解决了这个问题。
该方法会自动创建并返回ExtensionInterface的实例,并检查扩展的别名(您可以通过在扩展类中实现getAlias来指定,如Carlos Granados'答案所述)是否符合命名约定。
因此,通过重写您的bundle类中的getContainerExtension()方法,并简单地返回您的扩展类的实例,您可以绕过检查和LogicException
您的bundle类将如下所示:
<?php

namespace HelloWorld\Bundle\UserBundle;

use HelloWorld\Bundle\UserBundle\DependencyInjection\HelloWorldUserExtension;
use Symfony\Component\HttpKernel\Bundle\Bundle;

class HelloWorldUserBundle extends Bundle
{
    public function getContainerExtension()
    {
        if (null === $this->extension) {
            $this->extension = new HelloWorldUserExtension();
        }

        return $this->extension;
    }
}

当然,不要忘记将此内容添加到您的扩展类中:

/**
 * The extension alias
 *
 * @return string
 */
public function getAlias()
{
    return 'helloworld_user';
}

警告:我不确定为什么要在getContainerExtension()方法中添加此检查。可能有非常合理的原因,当按照上述步骤进行时,您可能会遇到问题。但是,到目前为止,我还没有遇到任何问题。

编辑:另请参见:Symfony2:我不喜欢的一些关于Bundles的事情。这篇博客文章提供了与我的答案相同的解决方案。此外,请参阅此拉取请求以获取Symfony的文档,该文档也描述了相同的方法。这使我相信可以这样做而不必担心副作用。


这很丑,但我猜如果你真的想打破Symfony的约定,那就是走的路。最干净的方法无论如何都必须正确命名您的bundle :-). - Alain Tiemblo
1
@AlainTiemblo 命名 bundle 并不总是可行的 - CMSIP2LocationBundle - tftd

0

正如文档所述:

创建扩展时,请遵循以下简单约定:

  • 扩展必须存储在DependencyInjection子命名空间中;
  • 扩展必须以bundle名称命名,并以Extension结尾(例如AcmeHelloBundle的AcmeHelloExtension);
  • 扩展应提供XSD模式。

我不确定您是否需要定义自己的buildgetAlias方法。如果需要,则getAlias方法应返回与根节点中定义的相同值。因此,它可能应该是helloworld_demo而不是hello_world_demo


据我理解文档,getAlias 方法被 Symfony 用来将扩展与 Bundle 关联起来。由于扩展的名称不再提供任何关于 Bundle 的提示,因此使用别名。编辑: 这在语义化配置文档页面的底部有解释:http://symfony.com/doc/2.0/cookbook/bundles/extension.html#extension-conventions - Florian Eckerstorfer
关于第一部分,我知道这些惯例,但出于美学考虑,我想打破它们。 - Florian Eckerstorfer

0
从书中 "在这种情况下,扩展类还必须实现一个getAlias()方法,并返回一个以bundle命名的唯一别名(例如acme_hello)。这是必需的,因为类名不遵循标准,不以Extension结尾。 此外,只有当用户在至少一个配置文件中指定了acme_hello别名时,才会调用您的扩展的load()方法。"
"所以,这个别名就是根配置名称。将您的代码更改为"
public function getAlias()
{
    return 'helloworld_demo';
}

它应该可以工作


[LogicException] The extension alias for the default extension of a bundle must be the underscored version of the bundle name ("hello_world_demo" instead of "helloworld_demo") - Florian Eckerstorfer
嗯...所以,我想唯一剩下的解决方案就是将你的包重命名为HelloworldDemoBundle等等... - Carlos Granados

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接