[HttpKernel] added BundleInterface::getContainerExtension() which is implicitly loaded

This commit is contained in:
Kris Wallsmith 2011-04-25 21:12:35 -07:00
parent 3ab5a51e17
commit 7a7b448680
5 changed files with 52 additions and 54 deletions

View File

@ -27,6 +27,7 @@ abstract class Bundle extends ContainerAware implements BundleInterface
{ {
protected $name; protected $name;
protected $reflected; protected $reflected;
protected $extension;
/** /**
* Boots the Bundle. * Boots the Bundle.
@ -47,13 +48,6 @@ abstract class Bundle extends ContainerAware implements BundleInterface
* *
* It is only ever called once when the cache is empty. * 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 overridden to register compilation passes, * This method can be overridden to register compilation passes,
* other extensions, ... * other extensions, ...
* *
@ -61,16 +55,21 @@ abstract class Bundle extends ContainerAware implements BundleInterface
*/ */
public function build(ContainerBuilder $container) 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); /**
* Returns the bundle's container extension.
*
* @return ExtensionInterface|null The container extension
*/
public function getContainerExtension()
{
if (null === $this->extension) {
$class = $this->getNamespace().'\\DependencyInjection\\'.str_replace('Bundle', 'Extension', $this->getName());
$this->extension = class_exists($class) ? new $class() : false;
} }
return $this->extension ?: null;
} }
/** /**

View File

@ -39,6 +39,13 @@ interface BundleInterface
*/ */
function build(ContainerBuilder $container); function build(ContainerBuilder $container);
/**
* Returns the container extension that should be implicitly loaded.
*
* @return ExtensionInterface|null The default extension
*/
function getContainerExtension();
/** /**
* Returns the bundle parent name. * Returns the bundle parent name.
* *

View File

@ -15,26 +15,24 @@ use Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationPa
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
/** /**
* Handles automatically loading each bundle's default extension. * Ensures certain extensions are always loaded.
* *
* @author Kris Wallsmith <kris.wallsmith@symfony.com> * @author Kris Wallsmith <kris@symfony.com>
*/ */
class MergeExtensionConfigurationPass extends BaseMergeExtensionConfigurationPass class MergeExtensionConfigurationPass extends BaseMergeExtensionConfigurationPass
{ {
private $extensions;
public function __construct(array $extensions)
{
$this->extensions = $extensions;
}
public function process(ContainerBuilder $container) public function process(ContainerBuilder $container)
{ {
foreach ($container->getParameter('kernel.bundles') as $bundleName => $bundleClass) { foreach ($this->extensions as $extension) {
$bundleRefl = new \ReflectionClass($bundleClass); if (!count($container->getExtensionConfig($extension))) {
$extClass = $bundleRefl->getNamespaceName().'\\DependencyInjection\\'.substr($bundleName, 0, -6).'Extension'; $container->loadFromExtension($extension, array());
if (class_exists($extClass)) {
$ext = new $extClass();
$alias = $ext->getAlias();
// ensure all "main" extensions are loaded
if (!count($container->getExtensionConfig($alias))) {
$container->loadFromExtension($alias, array());
}
} }
} }

View File

@ -529,19 +529,25 @@ abstract class Kernel implements KernelInterface
*/ */
protected function buildContainer() protected function buildContainer()
{ {
$parameterBag = new ParameterBag($this->getKernelParameters()); $container = new ContainerBuilder(new ParameterBag($this->getKernelParameters()));
$extensions = array();
$container = new ContainerBuilder($parameterBag);
$container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass());
foreach ($this->bundles as $bundle) { foreach ($this->bundles as $bundle) {
$bundle->build($container); $bundle->build($container);
if ($extension = $bundle->getContainerExtension()) {
$container->registerExtension($extension);
$extensions[] = $extension->getAlias();
}
if ($this->debug) { if ($this->debug) {
$container->addObjectResource($bundle); $container->addObjectResource($bundle);
} }
} }
$container->addObjectResource($this); $container->addObjectResource($this);
// ensure these extensions are implicitly loaded
$container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions));
if (null !== $cont = $this->registerContainerConfiguration($this->getContainerLoader($container))) { if (null !== $cont = $this->registerContainerConfiguration($this->getContainerLoader($container))) {
$container->merge($cont); $container->merge($cont);
} }

View File

@ -17,32 +17,20 @@ class MergeExtensionConfigurationPassTest extends \PHPUnit_Framework_TestCase
{ {
public function testAutoloadMainExtension() public function testAutoloadMainExtension()
{ {
$bundles = array(
'ExtensionAbsentBundle' => 'Symfony\\Tests\\Component\\HttpKernel\\Fixtures\\ExtensionAbsentBundle\\ExtensionAbsentBundle',
'ExtensionLoadedBundle' => 'Symfony\\Tests\\Component\\HttpKernel\\Fixtures\\ExtensionLoadedBundle\\ExtensionLoadedBundle',
'ExtensionPresentBundle' => 'Symfony\\Tests\\Component\\HttpKernel\\Fixtures\\ExtensionPresentBundle\\ExtensionPresentBundle',
);
$container = $this->getMock('Symfony\\Component\\DependencyInjection\\ContainerBuilder'); $container = $this->getMock('Symfony\\Component\\DependencyInjection\\ContainerBuilder');
$params = $this->getMock('Symfony\\Component\\DependencyInjection\\ParameterBag\\ParameterBag'); $params = $this->getMock('Symfony\\Component\\DependencyInjection\\ParameterBag\\ParameterBag');
$container->expects($this->once()) $container->expects($this->at(0))
->method('getParameter')
->with('kernel.bundles')
->will($this->returnValue($bundles));
$container->expects($this->exactly(2))
->method('getExtensionConfig') ->method('getExtensionConfig')
->will($this->returnCallback(function($name) { ->with('loaded')
switch ($name) { ->will($this->returnValue(array(array())));
case 'extension_present': $container->expects($this->at(1))
return array(); ->method('getExtensionConfig')
case 'extension_loaded': ->with('notloaded')
return array(array()); ->will($this->returnValue(array()));
}
}));
$container->expects($this->once()) $container->expects($this->once())
->method('loadFromExtension') ->method('loadFromExtension')
->with('extension_present', array()); ->with('notloaded', array());
$container->expects($this->any()) $container->expects($this->any())
->method('getParameterBag') ->method('getParameterBag')
@ -60,7 +48,7 @@ class MergeExtensionConfigurationPassTest extends \PHPUnit_Framework_TestCase
->method('getExtensions') ->method('getExtensions')
->will($this->returnValue(array())); ->will($this->returnValue(array()));
$configPass = new MergeExtensionConfigurationPass(); $configPass = new MergeExtensionConfigurationPass(array('loaded', 'notloaded'));
$configPass->process($container); $configPass->process($container);
} }
} }