[DI][DX] Throw exception on some ContainerBuilder methods used from extensions

This commit is contained in:
Maxime Steinhausser 2017-09-23 12:08:51 +02:00
parent 2e0cb6055f
commit 88549fff5b
2 changed files with 62 additions and 1 deletions

View File

@ -12,10 +12,13 @@
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
/**
* Merges extension configs into the container builder.
@ -52,7 +55,7 @@ class MergeExtensionConfigurationPass implements CompilerPassInterface
}
$config = $resolvingBag->resolveValue($config);
$tmpContainer = new ContainerBuilder($resolvingBag);
$tmpContainer = new MergeExtensionConfigurationContainerBuilder($extension, $resolvingBag);
$tmpContainer->setResourceTracking($container->isTrackingResources());
$tmpContainer->addObjectResource($extension);
if ($extension instanceof ConfigurationExtensionInterface && null !== $configuration = $extension->getConfiguration($config, $tmpContainer)) {
@ -121,3 +124,44 @@ class MergeExtensionConfigurationParameterBag extends EnvPlaceholderParameterBag
return null !== $this->processedEnvPlaceholders ? $this->processedEnvPlaceholders : parent::getEnvPlaceholders();
}
}
/**
* A container builder preventing using methods that wouldn't have any effect from extensions.
*
* @internal
*/
class MergeExtensionConfigurationContainerBuilder extends ContainerBuilder
{
private $extensionClass;
public function __construct(ExtensionInterface $extension, ParameterBagInterface $parameterBag = null)
{
parent::__construct($parameterBag);
$this->extensionClass = get_class($extension);
}
/**
* {@inheritdoc}
*/
public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION/*, int $priority = 0*/)
{
throw new LogicException(sprintf('You cannot add compiler pass "%s" from extension "%s". Compiler passes must be registered before the container is compiled.', get_class($pass), $this->extensionClass));
}
/**
* {@inheritdoc}
*/
public function registerExtension(ExtensionInterface $extension)
{
throw new LogicException(sprintf('You cannot register extension "%s" from "%s". Extensions must be registered before the container is compiled.', get_class($extension), $this->extensionClass));
}
/**
* {@inheritdoc}
*/
public function compile($resolveEnvPlaceholders = false)
{
throw new LogicException(sprintf('Cannot compile the container in extension "%s".', $this->extensionClass));
}
}

View File

@ -16,6 +16,7 @@ use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationPass;
use Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
@ -54,6 +55,22 @@ class MergeExtensionConfigurationPassTest extends TestCase
$this->assertEquals(array($provider), $tmpProviders);
}
public function testExtensionLoadGetAMergeExtensionConfigurationContainerBuilderInstance()
{
$extension = $this->getMockBuilder(FooExtension::class)->setMethods(array('load'))->getMock();
$extension->expects($this->once())
->method('load')
->with($this->isType('array'), $this->isInstanceOf(MergeExtensionConfigurationContainerBuilder::class))
;
$container = new ContainerBuilder(new ParameterBag());
$container->registerExtension($extension);
$container->prependExtensionConfig('foo', array());
$pass = new MergeExtensionConfigurationPass();
$pass->process($container);
}
public function testExtensionConfigurationIsTrackedByDefault()
{
$extension = $this->getMockBuilder(FooExtension::class)->setMethods(array('getConfiguration'))->getMock();