8000 [DI] Add a \"default\" EnvProcessor · symfony/symfony@aee4e33 · GitHub
[go: up one dir, main page]

Skip to content

Commit aee4e33

Browse files
jderussenicolas-grekas
authored andcommitted
[DI] Add a \"default\" EnvProcessor
1 parent 8c24c35 commit aee4e33

File tree

7 files changed

+186
-11
lines changed

7 files changed

+186
-11
lines changed

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
4.3.0
5+
-----
6+
7+
* added `%env(default:...)%` processor to fallback to a default value
8+
49
4.2.0
510
-----
611

src/Symfony/Component/DependencyInjection/EnvVarProcessor.php

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public static function getProvidedTypes()
4444
'json' => 'array',
4545
'key' => 'bool|int|float|string|array',
4646
'resolve' => 'string',
47+
'default' => 'bool|int|float|string|array',
4748
'string' => 'string',
4849
);
4950
}
@@ -57,7 +58,7 @@ public function getEnv($prefix, $name, \Closure $getEnv)
5758

5859
if ('key' === $prefix) {
5960
if (false === $i) {
60-
throw new RuntimeException(sprintf('Invalid configuration: env var "key:%s" does not contain a key specifier.', $name));
61+
throw new RuntimeException(sprintf('Invalid env "key:%s": a key specifier should be provided.', $name));
6162
}
6263

6364
$next = substr($name, $i + 1);
@@ -67,19 +68,39 @@ public function getEnv($prefix, $name, \Closure $getEnv)
6768
if (!\is_array($array)) {
6869
throw new RuntimeException(sprintf('Resolved value of "%s" did not result in an array value.', $next));
6970
}
70-
if (!array_key_exists($key, $array)) {
71-
throw new RuntimeException(sprintf('Key "%s" not found in "%s" (resolved from "%s")', $key, json_encode($array), $next));
71+
72+
if (!isset($array[$key]) && !array_key_exists($key, $array)) {
73+
throw new EnvNotFoundException(sprintf('Key "%s" not found in "%s" (resolved from "%s").', $key, json_encode($array), $next));
7274
}
7375

7476
return $array[$key];
7577
}
7678

79+
if ('default' === $prefix) {
80+
if (false === $i) {
81+
throw new RuntimeException(sprintf('Invalid env "default:%s": a fallback parameter should be provided.', $name));
82+
}
83+
84+
$next = substr($name, $i + 1);
85+
$default = substr($name, 0, $i);
86+
87+
if (!$this->container->hasParameter($default)) {
88+
throw new RuntimeException(sprintf('Invalid env fallback in "default:%s": parameter "%s" not found.', $name, F438 $default));
89+
}
90+
91+
try {
92+
return $getEnv($next);
93+
} catch (EnvNotFoundException $e) {
94+
return $this->container->getParameter($default);
95+
}
96+
}
97+
7798
if ('file' === $prefix) {
7899
if (!is_scalar($file = $getEnv($name))) {
79100
throw new RuntimeException(sprintf('Invalid file name: env var "%s" is non-scalar.', $name));
80101
}
81102
if (!file_exists($file)) {
82-
throw new RuntimeException(sprintf('Env "file:%s" not found: %s does not exist.', $name, $file));
103+
throw new EnvNotFoundException(sprintf('File "%s" not found (resolved from "%s").', $file, $name));
83104
}
84105

85106
return file_get_contents($file);
@@ -95,7 +116,7 @@ public function getEnv($prefix, $name, \Closure $getEnv)
95116
$env = $_SERVER[$name];
96117
} elseif (false === ($env = getenv($name)) || null === $env) { // null is a possible value because of thread safety issues
97118
if (!$this->container->hasParameter("env($name)")) {
98-
throw new EnvNotFoundException($name);
119+
throw new EnvNotFoundException(sprintf('Environment variable not found: "%s".', $name));
99120
}
100121

101122
if (null === $env = $this->container->getParameter("env($name)")) {

src/Symfony/Component/DependencyInjection/Exception/EnvNotFoundException.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,4 @@
1818
*/
1919
class EnvNotFoundException extends InvalidArgumentException
2020
{
21-
public function __construct(string $name)
22-
{
23-
parent::__construct(sprintf('Environment variable not found: "%s".', $name));
24-
}
2521
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public function testSimpleProcessor()
4040
'json' => array('array'),
4141
'key' => array('bool', 'int', 'float', 'string', 'array'),
4242
'resolve' => array('string'),
43+
'default' => array('bool', 'int', 'float', 'string', 'array'),
4344
'string' => array('string'),
4445
);
4546

src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,28 @@ public function testDumpedCsvEnvParameters()
439439
$this->assertSame(array('foo', 'bar'), $container->getParameter('hello'));
440440
}
441441

442+
public function testDumpedDefaultEnvParameters()
443+
{
444+
$container = new ContainerBuilder();
445+
$container->setParameter('fallback_param', 'baz');
446+
$container->setParameter('fallback_env', '%env(foobar)%');
447+
$container->setParameter('env(foobar)', 'foobaz');
448+
$container->setParameter('env(foo)', '{"foo": "bar"}');
449+
$container->setParameter('hello', '%env(default:fallback_param:bar)%');
450+
$container->setParameter('hello-bar', '%env(default:fallback_env:key:baz:json:foo)%');
451+
$container->compile();
452+
453+
$dumper = new PhpDumper($container);
454+
$dumper->dump();
455+
456+
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_default_env.php', $dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_DefaultParameters')));
457+
458+
require self::$fixturesPath.'/php/services_default_env.php';
459+
$container = new \Symfony_DI_PhpDumper_Test_DefaultParameters();
460+
$this->assertSame('baz', $container->getParameter('hello'));
461+
$this->assertSame('foobaz', $container->getParameter('hello-bar'));
462+
}
463+
442464
public function testDumpedJsonEnvParameters()
443465
{
444466
$container = new ContainerBuilder();

src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ public function testGetEnvUnknown()
317317

318318
/**
319319
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
320-
* @expectedExceptionMessage Invalid configuration: env var "key:foo" does not contain a key specifier.
320+
* @expectedExceptionMessage Invalid env "key:foo": a key specifier should be provided.
321321
*/
322322
public function testGetEnvKeyInvalidKey()
323323
{
@@ -355,7 +355,7 @@ public function noArrayValues()
355355
}
356356

357357
/**
358-
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
358+
* @expectedException \Symfony\Component\DependencyInjection\Exception\EnvNotFoundException
359359
* @expectedExceptionMessage Key "index" not found in
360360
* @dataProvider invalidArrayValues
361361
*/
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<?php
2+
3+
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
4+
use Symfony\Component\DependencyInjection\ContainerInterface;
5+
use Symfony\Component\DependencyInjection\Container;
6+
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
7+
use Symfony\Component\DependencyInjection\Exception\LogicException;
8+
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
9+
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
10+
11+
/**
12+
* This class has been auto-generated
13+
* by the Symfony Dependency Injection Component.
14+
*
15+
* @final since Symfony 3.3
16+
*/
17+
class Symfony_DI_PhpDumper_Test_DefaultParameters extends Container
18+
{
19+
private $parameters;
20+
private $targetDirs = array();
21+
22+
public function __construct()
23+
{
24+
$this->parameters = $this->getDefaultParameters();
25+
26+
$this->services = $this->privates = array();
27+
28+
$this->aliases = array();
29+
}
30+
31+
public function compile()
32+
{
33+
throw new LogicException('You cannot compile a dumped container that was already compiled.');
34+
}
35+
36+
public function isCompiled()
37+
{
38+
return true;
39+
}
40+
41+
public function getRemovedIds()
42+
{
43+
return array(
44+
'Psr\\Container\\ContainerInterface' => true,
45+
'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true,
46+
);
47+
}
48+
49+
public function getParameter($name)
50+
{
51+
$name = (string) $name;
52+
53+
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
54+
throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
55+
}
56+
if (isset($this->loadedDynamicParameters[$name])) {
57+
return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name);
58+
}
59+
60+
return $this->parameters[$name];
61+
}
62+
63+
public function hasParameter($name)
64+
{
65+
$name = (string) $name;
66+
67+
return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters);
68+
}
69+
70+
public function setParameter($name, $value)
71+
{
72+
throw new LogicException('Impossible to call set() on a frozen ParameterBag.');
73+
}
74+
75+
public function getParameterBag()
76+
{
77+
if (null === $this->parameterBag) {
78+
$parameters = $this->parameters;
79+
foreach ($this->loadedDynamicParameters as $name => $loaded) {
80+
$parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name);
81+
}
82+
$this->parameterBag = new FrozenParameterBag($parameters);
83+
}
84+
85+
return $this->parameterBag;
86+
}
87+
88+
private $loadedDynamicParameters = array(
89+
'fallback_env' => false,
90+
'hello' => false,
91+
'hello-bar' => false,
92+
);
93+
private $dynamicParameters = array();
94+
95+
/**
96+
* Computes a dynamic parameter.
97+
*
98+
* @param string The name of the dynamic parameter to load
99+
*
100+
* @return mixed The value of the dynamic parameter
101+
*
102+
* @throws InvalidArgumentException When the dynamic parameter does not exist
103+
*/
104+
private function getDynamicParameter($name)
105+
{
106+
switch ($name) {
107+
case 'fallback_env': $value = $this->getEnv('foobar'); break;
108+
case 'hello': $value = $this->getEnv('default:fallback_param:bar'); break;
109+
case 'hello-bar': $value = $this->getEnv('default:fallback_env:key:baz:json:foo'); break;
110+
default: throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name));
111+
}
112+
$this->loadedDynamicParameters[$name] = true;
113+
114+
return $this->dynamicParameters[$name] = $value;
115+
}
116+
117+
/**
118+
* Gets the default parameters.
119+
*
120+
* @return array An array of the default parameters
121+
*/
122+
protected function getDefaultParameters()
123+
{
124+
return array(
125+
'fallback_param' => 'baz',
126+
'env(foobar)' => 'foobaz',
127+
'env(foo)' => '{"foo": "bar"}',
128+
);
129+
}
130+
}

0 commit comments

Comments
 (0)
0