Skip to content

[DI][Config] Make accessing environment variables in configuration mo… #3

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
@@ -0,0 +1,32 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Config\Definition\Builder;

use Symfony\Component\Config\Definition\ExpressionNode;

/**
* This class provides a fluent interface for defining a node.
*
* @author Magnus Nordlander <[email protected]>
*/
class ExpressionNodeDefinition extends VariableNodeDefinition
{
/**
* Instantiate a Node.
*
* @return VariableNode The node
*/
protected function instantiateNode()
{
return new ExpressionNode($this->name, $this->parent);
}
}
13 changes: 13 additions & 0 deletions src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public function __construct()
'float' => __NAMESPACE__.'\\FloatNodeDefinition',
'array' => __NAMESPACE__.'\\ArrayNodeDefinition',
'enum' => __NAMESPACE__.'\\EnumNodeDefinition',
'expression' => __NAMESPACE__.'\\ExpressionNodeDefinition',
);
}

Expand Down Expand Up @@ -135,6 +136,18 @@ public function variableNode($name)
return $this->node($name, 'variable');
}

/**
* Creates a child variable node.
*
* @param string $name The name of the node
*
* @return VariableNodeDefinition The builder of the child node
*/
public function expressionNode($name)
{
return $this->node($name, 'expression');
}

/**
* Returns the parent node.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Symfony\Component\Config\Definition\ArrayNode;
use Symfony\Component\Config\Definition\EnumNode;
use Symfony\Component\Config\Definition\PrototypedArrayNode;
use Symfony\Component\ExpressionLanguage\Expression;

/**
* Dumps a XML reference configuration for the given configuration/node instance.
Expand Down Expand Up @@ -120,6 +121,10 @@ private function writeNode(NodeInterface $node, $depth = 0, $root = false, $name
$prototypeValue = implode('|', array_map('json_encode', $prototype->getValues()));
break;

case 'Symfony\Component\Config\Definition\ExpressionNode':
$prototypeValue = 'expression';
break;

default:
$prototypeValue = 'value';
}
Expand Down Expand Up @@ -297,6 +302,10 @@ private function writeValue($value)
return '';
}

if ($value instanceof Expression) {
return (string) $value;
}

if (is_array($value)) {
return implode(',', $value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Symfony\Component\Config\Definition\ArrayNode;
use Symfony\Component\Config\Definition\EnumNode;
use Symfony\Component\Config\Definition\PrototypedArrayNode;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\Yaml\Inline;

/**
Expand Down Expand Up @@ -106,6 +107,8 @@ private function writeNode(NodeInterface $node, $depth = 0)
} elseif (!is_array($example)) {
$default = '[]';
}
} elseif ($default instanceof Expression) {
$default = Inline::dump((string) $default);
} else {
$default = Inline::dump($default);
}
Expand Down
86 changes: 86 additions & 0 deletions src/Symfony/Component/Config/Definition/ExpressionNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Config\Definition;

use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
use Symfony\Component\ExpressionLanguage\Expression;

/**
* This node represents a Symfony Expression Language Expression.
*
* @author Magnus Nordlander <[email protected]>
*/
class ExpressionNode extends VariableNode
{
/**
* {@inheritdoc}
*/
protected function validateType($value)
{
if (!$value instanceof Expression) {
$e = new InvalidTypeException(sprintf('Invalid type for path "%s": expected Symfony\\Component\\ExpressionLanguage\\Expression , but got %s.', $this->getPath(), gettype($value)));

if ($hint = $this->getInfo()) {
$e->addHint($hint);
}
$e->setPath($this->getPath());

throw $e;
}
}

/**
* {@inheritdoc}
*/
protected function preNormalize($value)
{
$value = parent::preNormalize($value);

return $this->transformToExpression($value);
}

/**
* {@inheritdoc}
*/
public function getDefaultValue()
{
$value = parent::getDefaultValue();

return $this->transformToExpression($value);
}

/**
* {@inheritdoc}
*/
protected function isValueEmpty($value)
{
// a boolean value cannot be empty
return null === $value;
}

private function transformToExpression($value)
{
if (null === $value) {
return;
}

if ($value instanceof Expression) {
return $value;
}

if (!class_exists(Expression::class) {
throw new \RuntimeException('The Symfony Expression Language component must be installed to use expression nodes in configurations.');
}

return new Expression($value);
}
}
3 changes: 2 additions & 1 deletion src/Symfony/Component/Config/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"symfony/filesystem": "~2.8|~3.0"
},
"suggest": {
"symfony/yaml": "To use the yaml reference dumper"
"symfony/yaml": "To use the yaml reference dumper",
"symfony/expression-language": "To use the expression node type"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Config\\": "" },
Expand Down
21 changes: 21 additions & 0 deletions src/Symfony/Component/DependencyInjection/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Symfony\Component\DependencyInjection;

use Symfony\Component\DependencyInjection\Exception\EnvironmentVariableNotFoundException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
Expand Down Expand Up @@ -151,6 +152,26 @@ public function setParameter($name, $value)
$this->parameterBag->set($name, $value);
}

/**
* @internal
*/
public function getEnvironmentVariable($name, $default = null)
{
if (isset($_ENV[$name])) {
return $_ENV[$name];
}

if (false !== $value = getenv($name)) {
return $value;
}

if (2 > func_num_args()) {
throw new EnvironmentVariableNotFoundException($name);
}

return $default;
}

/**
* Sets a service.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\DependencyInjection\Exception;

/**
* This exception is thrown when an environment variable was not found.
*
* @author Magnus Nordlander <[email protected]>
*/
class EnvironmentVariableNotFoundException extends InvalidArgumentException
{
public function __construct($name)
{
parent::__construct(sprintf('You have requested a non-existent environment variable "%s".', $sourceId, $name));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*
* To get a service, use service('request').
* To get a parameter, use parameter('kernel.debug').
* To get an environment variable, use env('UID').
*
* @author Fabien Potencier <[email protected]>
*/
Expand All @@ -38,6 +39,20 @@ public function getFunctions()
}, function (array $variables, $value) {
return $variables['container']->getParameter($value);
}),

new ExpressionFunction('env', function ($arg, $default = null) {
if (2 > func_num_args()) {
return sprintf('$this->getEnvironmentVariable(%s)', $arg);
}

return sprintf('$this->getEnvironmentVariable(%s, %s)', $arg, $default);
}, function (array $variables, $value, $default = null) {
if (2 > func_num_args()) {
return $variables['container']->getEnvironmentVariable($value);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I am quite mistaken, this (and the same three lines down) won't work with getEnvironmentVariable declared as protected. I would suggest keeping it public.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, fixed!

}

return $variables['container']->getEnvironmentVariable($value, $default);
}),
);
}
}