Skip to content

Commit 55aa662

Browse files
committed
feature #24295 [DI][DX] Throw exception on some ContainerBuilder methods 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
2 parents 3f29df4 + 88549ff commit 55aa662

File tree

2 files changed

+62
-1
lines changed

2 files changed

+62
-1
lines changed

src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php

+45-1
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@
1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

1414
use Symfony\Component\DependencyInjection\ContainerBuilder;
15+
use Symfony\Component\DependencyInjection\Exception\LogicException;
1516
use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
1617
use Symfony\Component\DependencyInjection\Extension\Extension;
18+
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
1719
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
1820
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
21+
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
1922

2023
/**
2124
* Merges extension configs into the container builder.
@@ -52,7 +55,7 @@ public function process(ContainerBuilder $container)
5255
}
5356
$config = $resolvingBag->resolveValue($config);
5457

55-
$tmpContainer = new ContainerBuilder($resolvingBag);
58+
$tmpContainer = new MergeExtensionConfigurationContainerBuilder($extension, $resolvingBag);
5659
$tmpContainer->setResourceTracking($container->isTrackingResources());
5760
$tmpContainer->addObjectResource($extension);
5861
if ($extension instanceof ConfigurationExtensionInterface && null !== $configuration = $extension->getConfiguration($config, $tmpContainer)) {
@@ -121,3 +124,44 @@ public function getEnvPlaceholders()
121124
return null !== $this->processedEnvPlaceholders ? $this->processedEnvPlaceholders : parent::getEnvPlaceholders();
122125
}
123126
}
127+
128+
/**
129+
* A container builder preventing using methods that wouldn't have any effect from extensions.
130+
*
131+
* @internal
132+
*/
133+
class MergeExtensionConfigurationContainerBuilder extends ContainerBuilder
134+
{
135+
private $extensionClass;
136+
137+
public function __construct(ExtensionInterface $extension, ParameterBagInterface $parameterBag = null)
138+
{
139+
parent::__construct($parameterBag);
140+
141+
$this->extensionClass = get_class($extension);
142+
}
143+
144+
/**
145+
* {@inheritdoc}
146+
*/
147+
public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION/*, int $priority = 0*/)
148+
{
149+
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));
150+
}
151+
152+
/**
153+
* {@inheritdoc}
154+
*/
155+
public function registerExtension(ExtensionInterface $extension)
156+
{
157+
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));
158+
}
159+
160+
/**
161+
* {@inheritdoc}
162+
*/
163+
public function compile($resolveEnvPlaceholders = false)
164+
{
165+
throw new LogicException(sprintf('Cannot compile the container in extension "%s".', $this->extensionClass));
166+
}
167+
}

src/Symfony/Component/DependencyInjection/Tests/Compiler/MergeExtensionConfigurationPassTest.php

+17
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Component\Config\Definition\ConfigurationInterface;
1717
use Symfony\Component\Config\Resource\FileResource;
1818
use Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationPass;
19+
use Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationContainerBuilder;
1920
use Symfony\Component\DependencyInjection\ContainerBuilder;
2021
use Symfony\Component\DependencyInjection\Extension\Extension;
2122
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
@@ -54,6 +55,22 @@ public function testExpressionLanguageProviderForwarding()
5455
$this->assertEquals(array($provider), $tmpProviders);
5556
}
5657

58+
public function testExtensionLoadGetAMergeExtensionConfigurationContainerBuilderInstance()
59+
{
60+
$extension = $this->getMockBuilder(FooExtension::class)->setMethods(array('load'))->getMock();
61+
$extension->expects($this->once())
62+
->method('load')
63+
->with($this->isType('array'), $this->isInstanceOf(MergeExtensionConfigurationContainerBuilder::class))
64+
;
65+
66+
$container = new ContainerBuilder(new ParameterBag());
67+
$container->registerExtension($extension);
68+
$container->prependExtensionConfig('foo', array());
69+
70+
$pass = new MergeExtensionConfigurationPass();
71+
$pass->process($container);
72+
}
73+
5774
public function testExtensionConfigurationIsTrackedByDefault()
5875
{
5976
$extension = $this->getMockBuilder(FooExtension::class)->setMethods(array('getConfiguration'))->getMock();

0 commit comments

Comments
 (0)