added the concept of a main DIC extension for bundles

This allows for better conventions and better error messages if you
use the wrong configuration alias in a config file.

This is also the first step for a bigger refactoring of how the configuration
works (see next commits).

 * Bundle::registerExtensions() method has been renamed to Bundle::build()

 * The "main" DIC extension must be renamed to the new convention to be
   automatically registered:

      SensioBlogBundle -> DependencyInjection\SensioBlogExtension

 * The main DIC extension alias must follow the convention:

      sensio_blog for SensioBlogBundle

 * If you have more than one extension for a bundle (which should really
   never be the case), they must be registered manually by overriding the
   build() method

 * If you use YAML or PHP for your configuration, renamed the following
   configuration entry points in your configs:

      app -> framework
      webprofiler -> web_profiler
      doctrine_odm -> doctrine_mongo_db
This commit is contained in:
Fabien Potencier 2011-02-15 04:47:19 +01:00
parent 391e00c1de
commit 14aa95ba21
15 changed files with 78 additions and 60 deletions

View File

@ -24,9 +24,9 @@ use Symfony\Component\HttpKernel\Bundle\Bundle;
*/
class AsseticBundle extends Bundle
{
public function registerExtensions(ContainerBuilder $container)
public function build(ContainerBuilder $container)
{
parent::registerExtensions($container);
parent::build($container);
$container->addCompilerPass(new AssetManagerPass());
$container->addCompilerPass(new FilterManagerPass());

View File

@ -25,9 +25,9 @@ use Symfony\Component\HttpKernel\Bundle\Bundle;
*/
class DoctrineBundle extends Bundle
{
public function registerExtensions(ContainerBuilder $container)
public function build(ContainerBuilder $container)
{
parent::registerExtensions($container);
parent::build($container);
$container->addCompilerPass(new RegisterEventListenersAndSubscribersPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION);
}

View File

@ -402,6 +402,6 @@ class DoctrineMongoDBExtension extends AbstractDoctrineExtension
*/
public function getAlias()
{
return 'doctrine_odm';
return 'doctrine_mongo_db';
}
}

View File

@ -27,9 +27,9 @@ use Symfony\Bundle\DoctrineMongoDBBundle\DependencyInjection\Compiler\RegisterEv
*/
class DoctrineMongoDBBundle extends Bundle
{
public function registerExtensions(ContainerBuilder $container)
public function build(ContainerBuilder $container)
{
parent::registerExtensions($container);
parent::build($container);
$container->addCompilerPass(new RegisterEventListenersAndSubscribersPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION);
$container->addCompilerPass(new CreateProxyDirectoryPass(), PassConfig::TYPE_BEFORE_REMOVING);

View File

@ -506,6 +506,6 @@ class FrameworkExtension extends Extension
public function getAlias()
{
return 'app';
return 'framework';
}
}

View File

@ -64,9 +64,9 @@ class FrameworkBundle extends Bundle
}
}
public function registerExtensions(ContainerBuilder $container)
public function build(ContainerBuilder $container)
{
parent::registerExtensions($container);
parent::build($container);
$container->addScope(new Scope('request'));

View File

@ -22,9 +22,9 @@ use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\AddSecurityVoters
*/
class SecurityBundle extends Bundle
{
public function registerExtensions(ContainerBuilder $container)
public function build(ContainerBuilder $container)
{
parent::registerExtensions($container);
parent::build($container);
$container->addCompilerPass(new AddSecurityVotersPass());
}

View File

@ -22,9 +22,9 @@ use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\TwigEnvironmentPass;
*/
class TwigBundle extends Bundle
{
public function registerExtensions(ContainerBuilder $container)
public function build(ContainerBuilder $container)
{
parent::registerExtensions($container);
parent::build($container);
$container->addCompilerPass(new TwigEnvironmentPass());
}

View File

@ -85,6 +85,6 @@ class WebProfilerExtension extends Extension
public function getAlias()
{
return 'webprofiler';
return 'web_profiler';
}
}

View File

@ -22,9 +22,9 @@ use Symfony\Bundle\ZendBundle\DependencyInjection\Compiler\ZendLoggerWriterPass;
*/
class ZendBundle extends Bundle
{
public function registerExtensions(ContainerBuilder $container)
public function build(ContainerBuilder $container)
{
parent::registerExtensions($container);
parent::build($container);
$container->addCompilerPass(new ZendLoggerWriterPass());
}

View File

@ -13,6 +13,7 @@ namespace Symfony\Component\HttpKernel\Bundle;
use Symfony\Component\DependencyInjection\ContainerAware;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\Console\Application;
use Symfony\Component\Finder\Finder;
@ -41,6 +42,37 @@ abstract class Bundle extends ContainerAware implements BundleInterface
{
}
/**
* Builds the bundle.
*
* It is only ever called once when the cache is empty.
*
* The default implementation automatically registers a DIC extension
* if its name is the same as the bundle name after replacing the
* Bundle suffix by Extension (DependencyInjection\SensioBlogExtension
* for a SensioBlogBundle for instance). In such a case, the alias
* is forced to be the underscore version of the bundle name
* (sensio_blog for a SensioBlogBundle for instance).
*
* This method can be overriden to register compilation passes,
* other extensions, ...
*
* @param ContainerBuilder $container A ContainerBuilder instance
*/
public function build(ContainerBuilder $container)
{
$class = $this->getNamespace().'\\DependencyInjection\\'.str_replace('Bundle', 'Extension', $this->getName());
if (class_exists($class)) {
$extension = new $class();
$alias = Container::underscore(str_replace('Bundle', '', $this->getName()));
if ($alias !== $extension->getAlias()) {
throw new \LogicException(sprintf('The extension alias for the default extension of a bundle must be the underscored version of the bundle name ("%s" vs "%s")', $alias, $extension->getAlias()));
}
$container->registerExtension($extension);
}
}
/**
* Gets the Bundle namespace.
*
@ -96,33 +128,6 @@ abstract class Bundle extends ContainerAware implements BundleInterface
return $this->name = false === $pos ? $name : substr($name, $pos + 1);
}
/**
* Finds and registers Dependency Injection Container extensions.
*
* Override this method if your DIC extensions do not follow the conventions:
*
* * Extensions are in the 'DependencyInjection/' sub-directory
* * Extension class names ends with 'Extension'
*
* @param ContainerBuilder $container A ContainerBuilder instance
*/
public function registerExtensions(ContainerBuilder $container)
{
if (!$dir = realpath($this->getPath().'/DependencyInjection')) {
return;
}
$finder = new Finder();
$finder->files()->name('*Extension.php')->in($dir);
$prefix = $this->getNamespace().'\\DependencyInjection';
foreach ($finder as $file) {
$class = $prefix.strtr($file->getPath(), array($dir => '', '/' => '\\')).'\\'.$file->getBasename('.php');
$container->registerExtension(new $class());
}
}
/**
* Finds and registers Commands.
*

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\HttpKernel\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* BundleInterface.
*
@ -28,6 +30,15 @@ interface BundleInterface
*/
function shutdown();
/**
* Builds the bundle.
*
* It is only ever called once when the cache is empty.
*
* @param ContainerBuilder $container A ContainerBuilder instance
*/
public function build(ContainerBuilder $container);
/**
* Returns the bundle parent name.
*

View File

@ -458,7 +458,7 @@ abstract class Kernel implements KernelInterface
$container = new ContainerBuilder($parameterBag);
foreach ($this->bundles as $bundle) {
$bundle->registerExtensions($container);
$bundle->build($container);
if ($this->debug) {
$container->addObjectResource($bundle);

View File

@ -223,10 +223,12 @@ class ContainerAware implements ContainerAwareInterface
}
namespace Symfony\Component\HttpKernel\Bundle
{
use Symfony\Component\DependencyInjection\ContainerBuilder;
interface BundleInterface
{
function boot();
function shutdown();
public function build(ContainerBuilder $container);
function getParent();
function getName();
function getNamespace();
@ -237,6 +239,7 @@ namespace Symfony\Component\HttpKernel\Bundle
{
use Symfony\Component\DependencyInjection\ContainerAware;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\Console\Application;
use Symfony\Component\Finder\Finder;
abstract class Bundle extends ContainerAware implements BundleInterface
@ -249,6 +252,18 @@ abstract class Bundle extends ContainerAware implements BundleInterface
public function shutdown()
{
}
public function build(ContainerBuilder $container)
{
$class = $this->getNamespace().'\\DependencyInjection\\'.str_replace('Bundle', 'Extension', $this->getName());
if (class_exists($class)) {
$extension = new $class();
$alias = Container::underscore(str_replace('Bundle', '', $this->getName()));
if ($alias !== $extension->getAlias()) {
throw new \LogicException(sprintf('The extension alias for the default extension of a bundle must be the underscored version of the bundle name ("%s" vs "%s")', $alias, $extension->getAlias()));
}
$container->registerExtension($extension);
}
}
public function getNamespace()
{
if (null === $this->reflected) {
@ -276,19 +291,6 @@ abstract class Bundle extends ContainerAware implements BundleInterface
$pos = strrpos($name, '\\');
return $this->name = false === $pos ? $name : substr($name, $pos + 1);
}
public function registerExtensions(ContainerBuilder $container)
{
if (!$dir = realpath($this->getPath().'/DependencyInjection')) {
return;
}
$finder = new Finder();
$finder->files()->name('*Extension.php')->in($dir);
$prefix = $this->getNamespace().'\\DependencyInjection';
foreach ($finder as $file) {
$class = $prefix.strtr($file->getPath(), array($dir => '', '/' => '\\')).'\\'.$file->getBasename('.php');
$container->registerExtension(new $class());
}
}
public function registerCommands(Application $application)
{
if (!$dir = realpath($this->getPath().'/Command')) {
@ -727,7 +729,7 @@ abstract class Kernel implements KernelInterface
$parameterBag = new ParameterBag($this->getKernelParameters());
$container = new ContainerBuilder($parameterBag);
foreach ($this->bundles as $bundle) {
$bundle->registerExtensions($container);
$bundle->build($container);
if ($this->debug) {
$container->addObjectResource($bundle);
}

View File

@ -289,7 +289,7 @@ abstract class Kernel implements KernelInterface
$parameterBag = new ParameterBag($this->getKernelParameters());
$container = new ContainerBuilder($parameterBag);
foreach ($this->bundles as $bundle) {
$bundle->registerExtensions($container);
$bundle->build($container);
if ($this->debug) {
$container->addObjectResource($bundle);
}