Skip to content

Commit 5904d34

Browse files
committed
bug symfony#24488 [DI] Prefixed env vars and load time inlining are incompatible (nicolas-grekas)
This PR was merged into the 3.4 branch. Discussion ---------- [DI] Prefixed env vars and load time inlining are incompatible | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - That's because env var processors are not registered yet. Commits ------- 91c9287 [DI] Prefixed env vars and load time inlining are incompatible
2 parents 7f899a9 + 91c9287 commit 5904d34

File tree

3 files changed

+56
-10
lines changed

3 files changed

+56
-10
lines changed

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\DependencyInjection\ContainerBuilder;
1515
use Symfony\Component\DependencyInjection\Exception\LogicException;
16+
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
1617
use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
1718
use Symfony\Component\DependencyInjection\Extension\Extension;
1819
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
@@ -164,4 +165,30 @@ public function compile($resolveEnvPlaceholders = false)
164165
{
165166
throw new LogicException(sprintf('Cannot compile the container in extension "%s".', $this->extensionClass));
166167
}
168+
169+
/**
170+
* {@inheritdoc}
171+
*/
172+
public function resolveEnvPlaceholders($value, $format = null, array &$usedEnvs = null)
173+
{
174+
if (true !== $format || !\is_string($value)) {
175+
return parent::resolveEnvPlaceholders($value, $format, $usedEnvs);
176+
}
177+
178+
$bag = $this->getParameterBag();
179+
$value = $bag->resolveValue($value);
180+
181+
foreach ($bag->getEnvPlaceholders() as $env => $placeholders) {
182+
if (false === strpos($env, ':')) {
183+
continue;
184+
}
185+
foreach ($placeholders as $placeholder) {
186+
if (false !== stripos($value, $placeholder)) {
187+
throw new RuntimeException(sprintf('Using a cast in "env(%s)" is incompatible with resolution at compile time in "%s". The logic in the extension should be moved to a compiler pass, or an env parameter with no cast should be used instead.', $env, $this->extensionClass));
188+
}
189+
}
190+
}
191+
192+
return parent::resolveEnvPlaceholders($value, $format, $usedEnvs);
193+
}
167194
}

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

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,14 @@ public function process(ContainerBuilder $container)
3434
$types = array();
3535
$processors = array();
3636
foreach ($container->findTaggedServiceIds('container.env_var_processor') as $id => $tags) {
37-
foreach ($tags as $attr) {
38-
if (!$r = $container->getReflectionClass($class = $container->getDefinition($id)->getClass())) {
39-
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
40-
} elseif (!$r->isSubclassOf(EnvVarProcessorInterface::class)) {
41-
throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, EnvVarProcessorInterface::class));
42-
}
43-
foreach ($class::getProvidedTypes() as $prefix => $type) {
44-
$processors[$prefix] = new ServiceClosureArgument(new Reference($id));
45-
$types[$prefix] = self::validateProvidedTypes($type, $class);
46-
}
37+
if (!$r = $container->getReflectionClass($class = $container->getDefinition($id)->getClass())) {
38+
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
39+
} elseif (!$r->isSubclassOf(EnvVarProcessorInterface::class)) {
40+
throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, EnvVarProcessorInterface::class));
41+
}
42+
foreach ($class::getProvidedTypes() as $prefix => $type) {
43+
$processors[$prefix] = new ServiceClosureArgument(new Reference($id));
44+
$types[$prefix] = self::validateProvidedTypes($type, $class);
4745
}
4846
}
4947

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,19 @@ public function testOverriddenEnvsAreMerged()
101101
$this->assertSame(array('BAZ', 'FOO'), array_keys($container->getParameterBag()->getEnvPlaceholders()));
102102
$this->assertSame(array('BAZ' => 1, 'FOO' => 0), $container->getEnvCounters());
103103
}
104+
105+
/**
106+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
107+
* @expectedExceptionMessage Using a cast in "env(int:FOO)" is incompatible with resolution at compile time in "Symfony\Component\DependencyInjection\Tests\Compiler\BarExtension". The logic in the extension should be moved to a compiler pass, or an env parameter with no cast should be used instead.
108+
*/
109+
public function testProcessedEnvsAreIncompatibleWithResolve()
110+
{
111+
$container = new ContainerBuilder();
112+
$container->registerExtension(new BarExtension());
113+
$container->prependExtensionConfig('bar', array());
114+
115+
(new MergeExtensionConfigurationPass())->process($container);
116+
}
104117
}
105118

106119
class FooConfiguration implements ConfigurationInterface
@@ -142,3 +155,11 @@ public function load(array $configs, ContainerBuilder $container)
142155
}
143156
}
144157
}
158+
159+
class BarExtension extends Extension
160+
{
161+
public function load(array $configs, ContainerBuilder $container)
162+
{
163+
$container->resolveEnvPlaceholders('%env(int:FOO)%', true);
164+
}
165+
}

0 commit comments

Comments
 (0)