bug #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
-------
91c9287c55
[DI] Prefixed env vars and load time inlining are incompatible
This commit is contained in:
commit
5904d34125
@ -13,6 +13,7 @@ namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\LogicException;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Extension\Extension;
|
||||
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
|
||||
@ -164,4 +165,30 @@ class MergeExtensionConfigurationContainerBuilder extends ContainerBuilder
|
||||
{
|
||||
throw new LogicException(sprintf('Cannot compile the container in extension "%s".', $this->extensionClass));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resolveEnvPlaceholders($value, $format = null, array &$usedEnvs = null)
|
||||
{
|
||||
if (true !== $format || !\is_string($value)) {
|
||||
return parent::resolveEnvPlaceholders($value, $format, $usedEnvs);
|
||||
}
|
||||
|
||||
$bag = $this->getParameterBag();
|
||||
$value = $bag->resolveValue($value);
|
||||
|
||||
foreach ($bag->getEnvPlaceholders() as $env => $placeholders) {
|
||||
if (false === strpos($env, ':')) {
|
||||
continue;
|
||||
}
|
||||
foreach ($placeholders as $placeholder) {
|
||||
if (false !== stripos($value, $placeholder)) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parent::resolveEnvPlaceholders($value, $format, $usedEnvs);
|
||||
}
|
||||
}
|
||||
|
@ -34,16 +34,14 @@ class RegisterEnvVarProcessorsPass implements CompilerPassInterface
|
||||
$types = array();
|
||||
$processors = array();
|
||||
foreach ($container->findTaggedServiceIds('container.env_var_processor') as $id => $tags) {
|
||||
foreach ($tags as $attr) {
|
||||
if (!$r = $container->getReflectionClass($class = $container->getDefinition($id)->getClass())) {
|
||||
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
|
||||
} elseif (!$r->isSubclassOf(EnvVarProcessorInterface::class)) {
|
||||
throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, EnvVarProcessorInterface::class));
|
||||
}
|
||||
foreach ($class::getProvidedTypes() as $prefix => $type) {
|
||||
$processors[$prefix] = new ServiceClosureArgument(new Reference($id));
|
||||
$types[$prefix] = self::validateProvidedTypes($type, $class);
|
||||
}
|
||||
if (!$r = $container->getReflectionClass($class = $container->getDefinition($id)->getClass())) {
|
||||
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
|
||||
} elseif (!$r->isSubclassOf(EnvVarProcessorInterface::class)) {
|
||||
throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, EnvVarProcessorInterface::class));
|
||||
}
|
||||
foreach ($class::getProvidedTypes() as $prefix => $type) {
|
||||
$processors[$prefix] = new ServiceClosureArgument(new Reference($id));
|
||||
$types[$prefix] = self::validateProvidedTypes($type, $class);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,6 +101,19 @@ class MergeExtensionConfigurationPassTest extends TestCase
|
||||
$this->assertSame(array('BAZ', 'FOO'), array_keys($container->getParameterBag()->getEnvPlaceholders()));
|
||||
$this->assertSame(array('BAZ' => 1, 'FOO' => 0), $container->getEnvCounters());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
||||
* @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.
|
||||
*/
|
||||
public function testProcessedEnvsAreIncompatibleWithResolve()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->registerExtension(new BarExtension());
|
||||
$container->prependExtensionConfig('bar', array());
|
||||
|
||||
(new MergeExtensionConfigurationPass())->process($container);
|
||||
}
|
||||
}
|
||||
|
||||
class FooConfiguration implements ConfigurationInterface
|
||||
@ -142,3 +155,11 @@ class FooExtension extends Extension
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BarExtension extends Extension
|
||||
{
|
||||
public function load(array $configs, ContainerBuilder $container)
|
||||
{
|
||||
$container->resolveEnvPlaceholders('%env(int:FOO)%', true);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user