Skip to content

[DI] Fix tracking env vars when merging configs (bis) #24009

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
[DI] Fix tracking env vars when merging configs (bis)
  • Loading branch information
nicolas-grekas committed Aug 28, 2017
commit baaff20f4aa3b587617c05e201208527922871fd
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ public function process(ContainerBuilder $container)
// this extension was not called
continue;
}
// EnvPlaceholderParameterBag tracks env vars when calling resolveValue().
// Clone so that tracking is done in a dedicated bag.
$resolvingBag = clone $container->getParameterBag();
$resolvingBag = $container->getParameterBag();
if ($resolvingBag instanceof EnvPlaceholderParameterBag && $extension instanceof Extension) {
// create a dedicated bag so that we can track env vars per-extension
$resolvingBag = new MergeExtensionConfigurationParameterBag($resolvingBag);
}
$config = $resolvingBag->resolveValue($config);

$tmpContainer = new ContainerBuilder($container->getParameterBag());
$tmpContainer = new ContainerBuilder($resolvingBag);
$tmpContainer->setResourceTracking($container->isTrackingResources());
$tmpContainer->addObjectResource($extension);
if ($extension instanceof ConfigurationExtensionInterface && null !== $configuration = $extension->getConfiguration($config, $tmpContainer)) {
Expand All @@ -63,13 +65,9 @@ public function process(ContainerBuilder $container)

$extension->load($config, $tmpContainer);

if ($resolvingBag instanceof EnvPlaceholderParameterBag) {
// $resolvingBag keeps track of env vars encoutered *before* merging configs
if ($extension instanceof Extension) {
// but we don't want to keep track of env vars that are *overridden* when configs are merged
$resolvingBag = new MergeExtensionConfigurationParameterBag($extension, $resolvingBag);
}
$container->getParameterBag()->mergeEnvPlaceholders($resolvingBag);
if ($resolvingBag instanceof MergeExtensionConfigurationParameterBag) {
// don't keep track of env vars that are *overridden* when configs are merged
$resolvingBag->freezeAfterProcessing($extension);
}

$container->merge($tmpContainer);
Expand All @@ -86,55 +84,41 @@ public function process(ContainerBuilder $container)
*/
class MergeExtensionConfigurationParameterBag extends EnvPlaceholderParameterBag
{
private $beforeProcessingEnvPlaceholders;
private $processedEnvPlaceholders;

public function __construct(Extension $extension, parent $resolvingBag)
public function __construct(parent $parameterBag)
{
$this->beforeProcessingEnvPlaceholders = $resolvingBag->getEnvPlaceholders();
$config = $this->resolveEnvPlaceholders($extension->getProcessedConfigs());
parent::__construct($this->resolveValue($config));
parent::__construct($parameterBag->all());
$this->mergeEnvPlaceholders($parameterBag);
}

/**
* {@inheritdoc}
*/
public function get($name)
public function freezeAfterProcessing(Extension $extension)
{
return $this->has($name) || (0 === strpos($name, 'env(') && ')' === substr($name, -1) && 'env()' !== $name) ? parent::get($name) : '';
$this->processedEnvPlaceholders = array();
$this->processMergedConfig($extension->getProcessedConfigs(), parent::getEnvPlaceholders());
}

/**
* {@inheritdoc}
*/
public function getEnvPlaceholders()
{
// contains the list of env vars that are still used after configs have been merged
$envPlaceholders = parent::getEnvPlaceholders();

foreach ($envPlaceholders as $env => $placeholders) {
if (isset($this->beforeProcessingEnvPlaceholders[$env])) {
// for still-used env vars, keep track of their before-processing placeholders
$envPlaceholders[$env] += $this->beforeProcessingEnvPlaceholders[$env];
}
}

return $envPlaceholders;
return null !== $this->processedEnvPlaceholders ? $this->processedEnvPlaceholders : parent::getEnvPlaceholders();
}

/**
* Replaces-back env placeholders to their original "%env(FOO)%" version.
*/
private function resolveEnvPlaceholders($value)
private function processMergedConfig($value, array $envPlaceholders)
{
if (is_array($value)) {
foreach ($value as $k => $v) {
$value[$this->resolveEnvPlaceholders($k)] = $this->resolveEnvPlaceholders($v);
$this->processMergedConfig($k, $envPlaceholders);
$this->processMergedConfig($v, $envPlaceholders);
}
} elseif (is_string($value)) {
foreach ($this->beforeProcessingEnvPlaceholders as $env => $placeholders) {
foreach ($envPlaceholders as $env => $placeholders) {
foreach ($placeholders as $placeholder) {
if (false !== stripos($value, $placeholder)) {
$value = str_ireplace($placeholder, "%env($env)%", $value);
$this->processedEnvPlaceholders[$env] = $placeholders;
break;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -641,10 +641,16 @@ public function merge(ContainerBuilder $container)
}

if ($this->getParameterBag() instanceof EnvPlaceholderParameterBag && $container->getParameterBag() instanceof EnvPlaceholderParameterBag) {
$envPlaceholders = $container->getParameterBag()->getEnvPlaceholders();
$this->getParameterBag()->mergeEnvPlaceholders($container->getParameterBag());
} else {
$envPlaceholders = array();
}

foreach ($container->envCounters as $env => $count) {
if (!$count && !isset($envPlaceholders[$env])) {
continue;
}
if (!isset($this->envCounters[$env])) {
$this->envCounters[$env] = $count;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,13 @@ public function testOverriddenEnvsAreMerged()
$container = new ContainerBuilder();
$container->registerExtension(new FooExtension());
$container->prependExtensionConfig('foo', array('bar' => '%env(FOO)%'));
$container->prependExtensionConfig('foo', array('bar' => '%env(BAR)%'));
$container->prependExtensionConfig('foo', array('bar' => '%env(BAR)%', 'baz' => '%env(BAZ)%'));

$pass = new MergeExtensionConfigurationPass();
$pass->process($container);

$this->assertSame(array('FOO'), array_keys($container->getParameterBag()->getEnvPlaceholders()));
$this->assertSame(array('FOO', 'BAZ'), array_keys($container->getParameterBag()->getEnvPlaceholders()));
$this->assertSame(array('BAZ' => 1, 'FOO' => 0), $container->getEnvCounters());
}
}

Expand All @@ -94,6 +95,7 @@ public function getConfigTreeBuilder()
$rootNode
->children()
->scalarNode('bar')->end()
->scalarNode('baz')->end()
->end();

return $treeBuilder;
Expand All @@ -116,5 +118,10 @@ public function load(array $configs, ContainerBuilder $container)
{
$configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs);

if (isset($config['baz'])) {
$container->getParameterBag()->get('env(BOZ)');
$container->resolveEnvPlaceholders($config['baz']);
}
}
}