Reputation: 1526
My application consists of multiple bundles that are named like HelloWorldAdminBundle
, HelloWorldUserBundle
, HelloWorldDemoBundle
. This results in a configuration root like hello_world_demo
, hello_world_user
and hello_world_demo
. I want that the configuration roots of my bundles are helloworld_demo
, helloworld_user
and helloworld_admin
. At that point I have to mention that this is not really a technical problem, but more of an aesthetic problem.
I have tried to implement a custom extension and register it in the Bundle:
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->registerExtension(new HelloworldDemoExtension());
}
The extension:
...
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';
}
}
and finally the configuration:
...
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('helloworld_demo');
...
return $treeBuilder;
}
}
I followed the instructions How to expose a Semantic Configuration for a Bundle, however when I add an item to config.yml
I get the following error:
There is no extension able to load the configuration for "helloworld_demo"
Upvotes: 5
Views: 3752
Reputation: 11423
I solved this by overriding Symfony\Component\HttpKernel\Bundle\Bundle#getContainerExtension()
.
This method automatically creates and returns an instance of ExtensionInterface
, and also checks if the extension's alias (which you can specify by implementing getAlias
in your extension class, as per Carlos Granados' answer) conforms to the naming convention.
So by overriding the getContainerExtension()
method in your bundle class, and simply return an instance of your extension class, you can bypass the check and the LogicException
.
This is what your bundle class would look like:
<?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;
}
}
And, of course, don't forget to add this to your extension class:
/**
* The extension alias
*
* @return string
*/
public function getAlias()
{
return 'helloworld_user';
}
Warning: I'm not sure why this check was added to the getContainerExtension()
method. There might be a very valid reason, and you might encounter problems when following the above steps. However, I haven't had any problems with it so far.
Edit: Also see: Symfony2: Some things I don't like about Bundles. This blog article comes with the same solution as my answer. Also, see this pull request for Symfony's documentation, which also describes the same method. This makes me believe that it is safe to do so without having to expect side effects.
Upvotes: 3
Reputation: 1526
I found the solution to my problem. It works exactly as I described it in the question, however, a default extension (with the name of the bundle) must exist.
I now have an empty, but existing extension named HelloWorldDemoExtension (with the alias hello_world_demo
and additionally I added DemoExtension (with the alias helloworld_demo
) and it works.
Upvotes: 3
Reputation: 11351
From the book "In this case, the extension class must also implement a getAlias() method and return a unique alias named after the bundle (e.g. acme_hello). This is required because the class name doesn't follow the standards by ending in Extension. Additionally, the load() method of your extension will only be called if the user specifies the acme_hello alias in at least one configuration file. "
So, this alias IS the root configuration name. Change your code to
public function getAlias()
{
return 'helloworld_demo';
}
And it should work
Upvotes: 0
Reputation: 3393
As documentation says:
When creating an extension, follow these simple conventions:
- The extension must be stored in the DependencyInjection sub-namespace;
- The extension must be named after the bundle name and suffixed with Extension (AcmeHelloExtension for AcmeHelloBundle);
- The extension should provide an XSD schema.
I am not really know if you need define own build
and getAlias
methods. If you need it then getAlias
method should return this same value as you define in root node. So it should be helloworld_demo
probably instead of hello_world_demo
Upvotes: 0