Skip to content

[WIP][DependencyInjection] Issue #7555 - Resolve environment variables at runtime #10138

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

Closed
wants to merge 1 commit into from
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
class ParameterBag implements ParameterBagInterface
{
protected $parameters = array();
protected $environmentMap = array();
protected $resolved = false;

/**
Expand Down Expand Up @@ -157,6 +158,10 @@ public function resolve()
return;
}

if ($this->has('environment_map') && is_array($map = $this->get('environment_map'))) {
$this->environmentMap = $map;
}

$parameters = array();
foreach ($this->parameters as $key => $value) {
try {
Expand All @@ -173,6 +178,20 @@ public function resolve()
$this->resolved = true;
}

public function resolveEnvironmentMap()
{
if ($this->has('environment_map') && is_array($map = $this->get('environment_map'))) {
$this->environmentMap = $map;

foreach ($map as $key => $var) {
$value = getenv($var);
if ($value !== false) {
$this->parameters[strtolower($key)] = $this->resolveValue($value);
}
}
}
}

/**
* Replaces parameter placeholders (%name%) by their values.
*
Expand Down Expand Up @@ -227,14 +246,19 @@ public function resolveString($value, array $resolving = array())
throw new ParameterCircularReferenceException(array_keys($resolving));
}

if (isset($this->environmentMap[$key])) {
throw new RuntimeException(sprintf('Parameter "%s" is set via the environment map and may not be used in another parameter.', $key));
}

$resolving[$key] = true;

return $this->resolved ? $this->get($key) : $this->resolveValue($this->get($key), $resolving);
}

$self = $this;
$environmentMap = $self->environmentMap;

return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($self, $resolving, $value) {
return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($self, $resolving, $value, $environmentMap) {
// skip %%
if (!isset($match[1])) {
return '%%';
Expand All @@ -245,6 +269,10 @@ public function resolveString($value, array $resolving = array())
throw new ParameterCircularReferenceException(array_keys($resolving));
}

if (isset($environmentMap[$key])) {
throw new RuntimeException(sprintf('Parameter "%s" is set via the environment map and may not be used in another parameter.', $key));
}

$resolved = $self->get($key);

if (!is_string($resolved) && !is_numeric($resolved)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,15 @@ public function testAdd()
$bag = new FrozenParameterBag(array());
$bag->add(array());
}

public function testResolveEnvironmentMaps()
{
$bag = new FrozenParameterBag(array('foo' => 'bar', 'environment_map' => array('foo' => 'SYMFONY_TEST')));

putenv('SYMFONY_TEST=baz');
$bag->resolveEnvironmentMap();
putenv('SYMFONY_TEST');

$this->assertEquals($bag->get('foo'), 'baz');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,30 @@ public function testResolveStringWithSpacesReturnsString($expected, $test, $desc
}
}

public function testResolveEnvironmentMaps()
{
$bag = new ParameterBag(array('foo' => 'bar', 'qux' => 'mu', 'environment_map' => array('foo' => 'SYMFONY_TEST')));
$bag->resolve();

putenv('SYMFONY_TEST=baz_%qux%');
$bag->resolveEnvironmentMap();
putenv('SYMFONY_TEST');

$this->assertEquals($bag->get('foo'), 'baz_mu');
}

public function testIllegalResolveEnvironmentMaps()
{
try {
$bag = new ParameterBag(array('foo' => 'bar', 'baz' => '%foo%', 'environment_map' => array('foo' => 'SYMFONY_TEST')));
$bag->resolve();
$this->fail('->resolve() throws an Symfony\Component\DependencyInjection\Exception\RuntimeException if a parameter uses a parameter part of the environment map.');
} catch (\Exception $e) {
$this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\RuntimeException', $e, '->resolve() throws an Symfony\Component\DependencyInjection\Exception\RuntimeException if a parameter uses a parameter part of the environment map.');
$this->assertEquals('Parameter "foo" is set via the environment map and may not be used in another parameter.', $e->getMessage(), '->resolve() throws an Symfony\Component\DependencyInjection\Exception\RuntimeException with the offending environment variable.');
}
}

public function stringsWithSpacesProvider()
{
return array(
Expand Down
13 changes: 13 additions & 0 deletions src/Symfony/Component/HttpKernel/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,8 @@ protected function initializeContainer()
$this->container = new $class();
$this->container->set('kernel', $this);

$this->postProcessContainer($this->container);

if (!$fresh && $this->container->has('cache_warmer')) {
$this->container->get('cache_warmer')->warmUp($this->container->getParameter('kernel.cache_dir'));
}
Expand Down Expand Up @@ -676,6 +678,17 @@ protected function prepareContainer(ContainerBuilder $container)
$container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions));
}

/**
* Post processing of the Container after it was loaded from cache.
* This always occurs
*
* @param ContainerInterface $container
*/
protected function postProcessContainer(ContainerInterface $container)
{
$container->getParameterBag()->resolveEnvironmentMap();
}

/**
* Gets a new ContainerBuilder instance used to build the service container.
*
Expand Down