[DI] Prefixed env vars and load time inlining are incompatible

This commit is contained in:
Nicolas Grekas 2017-10-08 15:44:15 +02:00
parent b43bdf398d
commit 91c9287c55
3 changed files with 56 additions and 10 deletions

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}