Skip to content

Commit

Permalink
feature #26498 Allow "json:" env var processor to accept null value (…
Browse files Browse the repository at this point in the history
…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
-------

abc7480 Allow "json:" env var processor to parse null values
  • Loading branch information
fabpot committed Mar 27, 2018
2 parents 3424cc7 + abc7480 commit 2e47edc
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 6 deletions.
4 changes: 2 additions & 2 deletions src/Symfony/Component/DependencyInjection/EnvVarProcessor.php
Expand Up @@ -129,8 +129,8 @@ public function getEnv($prefix, $name, \Closure $getEnv)
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;
Expand Down
Expand Up @@ -432,6 +432,27 @@ public function testDumpedCsvEnvParameters()
$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();
Expand Down
Expand Up @@ -233,17 +233,29 @@ public function testGetEnvBase64()
$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),
);
}

/**
Expand Down Expand Up @@ -284,6 +296,7 @@ public function otherJsonValues()
array(1.1),
array(true),
array(false),
array('foo'),
);
}

Expand Down
@@ -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',
);
}
}

0 comments on commit 2e47edc

Please sign in to comment.