feature #26498 Allow "json:" env var processor to accept null value (mcfedr)

This PR was merged into the 4.1-dev branch.

Discussion
----------

Allow "json:" env var processor to accept null value

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets |
| License       | MIT
| Doc PR        | Currently no docs for this feature

Edits the EnvVarProcessor so that it allows any type of variable in JSON encoded vars.

Previously it was only possible to use `%env(json:ENV)%` for array types, but this seems to be an arbitrary restriction, when I could have any other data type in that JSON.

Valid JSON that was previously rejected:
- `1`
- `null`
- `"string"`

Commits
-------

abc7480828 Allow "json:" env var processor to parse null values
This commit is contained in:
Fabien Potencier 2018-03-27 14:13:01 +02:00
commit 2e47edc4a5
4 changed files with 178 additions and 6 deletions

View File

@ -129,8 +129,8 @@ class EnvVarProcessor implements EnvVarProcessorInterface
throw new RuntimeException(sprintf('Invalid JSON in env var "%s": '.json_last_error_msg(), $name));
}
if (!is_array($env)) {
throw new RuntimeException(sprintf('Invalid JSON env var "%s": array expected, %s given.', $name, gettype($env)));
if (null !== $env && !is_array($env)) {
throw new RuntimeException(sprintf('Invalid JSON env var "%s": array or null expected, %s given.', $name, gettype($env)));
}
return $env;

View File

@ -432,6 +432,27 @@ class PhpDumperTest extends TestCase
$this->assertSame(array('foo', 'bar'), $container->getParameter('hello'));
}
public function testDumpedJsonEnvParameters()
{
$container = new ContainerBuilder();
$container->setParameter('env(foo)', '["foo","bar"]');
$container->setParameter('env(bar)', 'null');
$container->setParameter('hello', '%env(json:foo)%');
$container->setParameter('hello-bar', '%env(json:bar)%');
$container->compile();
$dumper = new PhpDumper($container);
$dumper->dump();
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_json_env.php', $dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_JsonParameters')));
putenv('foobar="hello"');
require self::$fixturesPath.'/php/services_json_env.php';
$container = new \Symfony_DI_PhpDumper_Test_JsonParameters();
$this->assertSame(array('foo', 'bar'), $container->getParameter('hello'));
$this->assertNull($container->getParameter('hello-bar'));
}
public function testCustomEnvParameters()
{
$container = new ContainerBuilder();

View File

@ -233,17 +233,29 @@ class EnvVarProcessorTest extends TestCase
$this->assertSame('hello', $result);
}
public function testGetEnvJson()
/**
* @dataProvider validJson
*/
public function testGetEnvJson($value, $processed)
{
$processor = new EnvVarProcessor(new Container());
$result = $processor->getEnv('json', 'foo', function ($name) {
$result = $processor->getEnv('json', 'foo', function ($name) use ($value) {
$this->assertSame('foo', $name);
return json_encode(array(1));
return $value;
});
$this->assertSame(array(1), $result);
$this->assertSame($processed, $result);
}
public function validJson()
{
return array(
array('[1]', array(1)),
array('{"key": "value"}', array('key' => 'value')),
array(null, null),
);
}
/**
@ -284,6 +296,7 @@ class EnvVarProcessorTest extends TestCase
array(1.1),
array(true),
array(false),
array('foo'),
);
}

View File

@ -0,0 +1,138 @@
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
/**
* This class has been auto-generated
* by the Symfony Dependency Injection Component.
*
* @final since Symfony 3.3
*/
class Symfony_DI_PhpDumper_Test_JsonParameters extends Container
{
private $parameters;
private $targetDirs = array();
/**
* @internal but protected for BC on cache:clear
*/
protected $privates = array();
public function __construct()
{
$this->parameters = $this->getDefaultParameters();
$this->services = $this->privates = array();
$this->aliases = array();
}
public function reset()
{
$this->privates = array();
parent::reset();
}
public function compile()
{
throw new LogicException('You cannot compile a dumped container that was already compiled.');
}
public function isCompiled()
{
return true;
}
public function getRemovedIds()
{
return array(
'Psr\\Container\\ContainerInterface' => true,
'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true,
);
}
public function getParameter($name)
{
$name = (string) $name;
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
}
if (isset($this->loadedDynamicParameters[$name])) {
return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name);
}
return $this->parameters[$name];
}
public function hasParameter($name)
{
$name = (string) $name;
return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters);
}
public function setParameter($name, $value)
{
throw new LogicException('Impossible to call set() on a frozen ParameterBag.');
}
public function getParameterBag()
{
if (null === $this->parameterBag) {
$parameters = $this->parameters;
foreach ($this->loadedDynamicParameters as $name => $loaded) {
$parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name);
}
$this->parameterBag = new FrozenParameterBag($parameters);
}
return $this->parameterBag;
}
private $loadedDynamicParameters = array(
'hello' => false,
'hello-bar' => false,
);
private $dynamicParameters = array();
/**
* Computes a dynamic parameter.
*
* @param string The name of the dynamic parameter to load
*
* @return mixed The value of the dynamic parameter
*
* @throws InvalidArgumentException When the dynamic parameter does not exist
*/
private function getDynamicParameter($name)
{
switch ($name) {
case 'hello': $value = $this->getEnv('json:foo'); break;
case 'hello-bar': $value = $this->getEnv('json:bar'); break;
default: throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name));
}
$this->loadedDynamicParameters[$name] = true;
return $this->dynamicParameters[$name] = $value;
}
/**
* Gets the default parameters.
*
* @return array An array of the default parameters
*/
protected function getDefaultParameters()
{
return array(
'env(foo)' => '["foo","bar"]',
'env(bar)' => 'null',
);
}
}