Skip to content

Commit

Permalink
feature #24295 [DI][DX] Throw exception on some ContainerBuilder meth…
Browse files Browse the repository at this point in the history
…ods used from extensions (ogizanagi)

This PR was merged into the 3.4 branch.

Discussion
----------

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

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | no
| New feature?  | yes <!-- don't forget updating src/**/CHANGELOG.md files -->
| BC breaks?    | no (unlikely, that would mean there already was an issue in userland code)
| Deprecations? | no <!-- don't forget updating UPGRADE-*.md files -->
| Tests pass?   | yes
| Fixed tickets | #24282 <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | N/A

Commits
-------

88549ff [DI][DX] Throw exception on some ContainerBuilder methods used from extensions
  • Loading branch information
ogizanagi committed Sep 26, 2017
2 parents 3f29df4 + 88549ff commit 55aa662
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 1 deletion.
Expand Up @@ -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.
Expand Down Expand Up @@ -52,7 +55,7 @@ public function process(ContainerBuilder $container)
}
$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)) {
Expand Down Expand Up @@ -121,3 +124,44 @@ public function getEnvPlaceholders()
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));
}
}
Expand Up @@ -16,6 +16,7 @@
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;
Expand Down Expand Up @@ -54,6 +55,22 @@ public function testExpressionLanguageProviderForwarding()
$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();
Expand Down

0 comments on commit 55aa662

Please sign in to comment.