From 9a200247e18cb045267b253b3ddf86a88205c465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Vasseur?= Date: Wed, 16 Feb 2022 15:48:40 +0100 Subject: [PATCH] Add an env function to DI expression language --- .../Component/DependencyInjection/CHANGELOG.md | 1 + .../DependencyInjection/ContainerBuilder.php | 2 +- .../DependencyInjection/ExpressionLanguage.php | 4 ++-- .../ExpressionLanguageProvider.php | 17 ++++++++++++++++- .../Tests/ContainerBuilderTest.php | 13 +++++++++++++ .../Tests/Dumper/PhpDumperTest.php | 18 ++++++++++++++++++ 6 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index f27c70d302433..b2a997ad4f4b6 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * Add `$exclude` to `TaggedIterator` and `TaggedLocator` attributes * Add `$exclude` to `tagged_iterator` and `tagged_locator` configurator + * Add an `env` function to the expression language provider 6.0 --- diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 0d1f24f428bc7..c4976cc086887 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -1586,7 +1586,7 @@ private function getExpressionLanguage(): ExpressionLanguage if (!class_exists(\Symfony\Component\ExpressionLanguage\ExpressionLanguage::class)) { throw new LogicException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.'); } - $this->expressionLanguage = new ExpressionLanguage(null, $this->expressionLanguageProviders); + $this->expressionLanguage = new ExpressionLanguage(null, $this->expressionLanguageProviders, null, \Closure::fromCallable([$this, 'getEnv'])); } return $this->expressionLanguage; diff --git a/src/Symfony/Component/DependencyInjection/ExpressionLanguage.php b/src/Symfony/Component/DependencyInjection/ExpressionLanguage.php index 961c737e8d5c5..df47f53a4f625 100644 --- a/src/Symfony/Component/DependencyInjection/ExpressionLanguage.php +++ b/src/Symfony/Component/DependencyInjection/ExpressionLanguage.php @@ -30,10 +30,10 @@ class ExpressionLanguage extends BaseExpressionLanguage /** * {@inheritdoc} */ - public function __construct(CacheItemPoolInterface $cache = null, array $providers = [], callable $serviceCompiler = null) + public function __construct(CacheItemPoolInterface $cache = null, array $providers = [], callable $serviceCompiler = null, \Closure $getEnv = null) { // prepend the default provider to let users override it easily - array_unshift($providers, new ExpressionLanguageProvider($serviceCompiler)); + array_unshift($providers, new ExpressionLanguageProvider($serviceCompiler, $getEnv)); parent::__construct($cache, $providers); } diff --git a/src/Symfony/Component/DependencyInjection/ExpressionLanguageProvider.php b/src/Symfony/Component/DependencyInjection/ExpressionLanguageProvider.php index ee3612896ba6c..2cac25a031bde 100644 --- a/src/Symfony/Component/DependencyInjection/ExpressionLanguageProvider.php +++ b/src/Symfony/Component/DependencyInjection/ExpressionLanguageProvider.php @@ -11,6 +11,7 @@ namespace Symfony\Component\DependencyInjection; +use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\ExpressionLanguage\ExpressionFunction; use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface; @@ -19,6 +20,7 @@ * * To get a service, use service('request'). * To get a parameter, use parameter('kernel.debug'). + * To get an env variable, use env('SOME_VARIABLE'). * * @author Fabien Potencier */ @@ -26,9 +28,12 @@ class ExpressionLanguageProvider implements ExpressionFunctionProviderInterface { private ?\Closure $serviceCompiler; - public function __construct(callable $serviceCompiler = null) + private ?\Closure $getEnv; + + public function __construct(callable $serviceCompiler = null, \Closure $getEnv = null) { $this->serviceCompiler = null !== $serviceCompiler && !$serviceCompiler instanceof \Closure ? \Closure::fromCallable($serviceCompiler) : $serviceCompiler; + $this->getEnv = $getEnv; } public function getFunctions(): array @@ -45,6 +50,16 @@ public function getFunctions(): array }, function (array $variables, $value) { return $variables['container']->getParameter($value); }), + + new ExpressionFunction('env', function ($arg) { + return sprintf('$this->getEnv(%s)', $arg); + }, function (array $variables, $value) { + if (!$this->getEnv) { + throw new LogicException('You need to pass a getEnv closure to the expression langage provider to use the "env" function.'); + } + + return ($this->getEnv)($value); + }), ]; } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index e4bbfdf5f0ec4..c777694c4118d 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -517,6 +517,19 @@ public function testCreateServiceWithExpression() $this->assertEquals('foobar', $builder->get('foo')->arguments['foo']); } + public function testEnvExpressionFunction() + { + $container = new ContainerBuilder(); + $container->register('bar', 'BarClass') + ->setPublic(true) + ->setProperty('foo', new Expression('env("BAR_FOO")')); + $container->compile(true); + + $_ENV['BAR_FOO'] = 'Foo value'; + + $this->assertEquals('Foo value', $container->get('bar')->foo); + } + public function testCreateServiceWithAbstractArgument() { $this->expectException(RuntimeException::class); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index fbcf4459cbb7b..eed9c45e8b5d5 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -961,6 +961,24 @@ public function testPrivateWithIgnoreOnInvalidReference() $this->assertInstanceOf(\BazClass::class, $container->get('bar')->getBaz()); } + public function testEnvExpressionFunction() + { + $container = new ContainerBuilder(); + $container->register('bar', 'BarClass') + ->setPublic(true) + ->setProperty('foo', new Expression('env("BAR_FOO")')); + $container->compile(); + + $dumper = new PhpDumper($container); + eval('?>'.$dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Env_Expression_Function'])); + + $container = new \Symfony_DI_PhpDumper_Test_Env_Expression_Function(); + + $_ENV['BAR_FOO'] = 'Foo value'; + + $this->assertEquals('Foo value', $container->get('bar')->foo); + } + public function testArrayParameters() { $container = new ContainerBuilder();