From 228b220495bbfb2f2d84cee2bf052abfda65e476 Mon Sep 17 00:00:00 2001 From: Florent Mata Date: Sun, 2 Sep 2018 11:15:13 +0200 Subject: [PATCH] [Dotenv] add Dotenv::overload() to allow env vars override --- src/Symfony/Component/Dotenv/CHANGELOG.md | 5 ++ src/Symfony/Component/Dotenv/Dotenv.php | 44 ++++++++++++----- .../Component/Dotenv/Tests/DotenvTest.php | 47 +++++++++++++++++++ 3 files changed, 83 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Component/Dotenv/CHANGELOG.md b/src/Symfony/Component/Dotenv/CHANGELOG.md index f04cc1bdf7..f92a8d4e25 100644 --- a/src/Symfony/Component/Dotenv/CHANGELOG.md +++ b/src/Symfony/Component/Dotenv/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.2.0 +----- + + * added `Dotenv::overload()` and `$overrideExistingVars` as optional parameter of `Dotenv::populate()` + 3.3.0 ----- diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php index 153c9c9d3a..9278195d74 100644 --- a/src/Symfony/Component/Dotenv/Dotenv.php +++ b/src/Symfony/Component/Dotenv/Dotenv.php @@ -47,25 +47,30 @@ final class Dotenv */ public function load(string $path, string ...$paths): void { - array_unshift($paths, $path); + $this->doLoad(false, $path, ...$paths); + } - foreach ($paths as $path) { - if (!is_readable($path) || is_dir($path)) { - throw new PathException($path); - } - - $this->populate($this->parse(file_get_contents($path), $path)); - } + /** + * Loads one or several .env files and enables override existing vars. + * + * @param string $path A file to load + * @param ...string $paths A list of additional files to load + * + * @throws FormatException when a file has a syntax error + * @throws PathException when a file does not exist or is not readable + */ + public function overload(string $path, string ...$paths): void + { + $this->doLoad(true, $path, ...$paths); } /** * Sets values as environment variables (via putenv, $_ENV, and $_SERVER). * - * Note that existing environment variables are not overridden. - * - * @param array $values An array of env variables + * @param array $values An array of env variables + * @param bool $overrideExistingVars true when existing environment variables must be overridden */ - public function populate(array $values): void + public function populate(array $values, bool $overrideExistingVars = false): void { $loadedVars = array_flip(explode(',', getenv('SYMFONY_DOTENV_VARS'))); unset($loadedVars['']); @@ -73,7 +78,7 @@ final class Dotenv foreach ($values as $name => $value) { $notHttpName = 0 !== strpos($name, 'HTTP_'); // don't check existence with getenv() because of thread safety issues - if (!isset($loadedVars[$name]) && (isset($_ENV[$name]) || (isset($_SERVER[$name]) && $notHttpName))) { + if (!isset($loadedVars[$name]) && (!$overrideExistingVars && (isset($_ENV[$name]) || (isset($_SERVER[$name]) && $notHttpName)))) { continue; } @@ -399,4 +404,17 @@ final class Dotenv { return new FormatException($message, new FormatExceptionContext($this->data, $this->path, $this->lineno, $this->cursor)); } + + private function doLoad(bool $overrideExistingVars, string $path, string ...$paths): void + { + array_unshift($paths, $path); + + foreach ($paths as $path) { + if (!is_readable($path) || is_dir($path)) { + throw new PathException($path); + } + + $this->populate($this->parse(file_get_contents($path), $path), $overrideExistingVars); + } + } } diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php index b4b89280d5..81e1b25a4c 100644 --- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php +++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php @@ -186,6 +186,41 @@ class DotenvTest extends TestCase $this->assertSame('BAZ', $bar); } + public function testOverload() + { + unset($_ENV['FOO']); + unset($_ENV['BAR']); + unset($_SERVER['FOO']); + unset($_SERVER['BAR']); + + putenv('FOO=initial_foo_value'); + putenv('BAR=initial_bar_value'); + $_ENV['FOO'] = 'initial_foo_value'; + $_ENV['BAR'] = 'initial_bar_value'; + + @mkdir($tmpdir = sys_get_temp_dir().'/dotenv'); + + $path1 = tempnam($tmpdir, 'sf-'); + $path2 = tempnam($tmpdir, 'sf-'); + + file_put_contents($path1, 'FOO=BAR'); + file_put_contents($path2, 'BAR=BAZ'); + + (new DotEnv())->overload($path1, $path2); + + $foo = getenv('FOO'); + $bar = getenv('BAR'); + + putenv('FOO'); + putenv('BAR'); + unlink($path1); + unlink($path2); + rmdir($tmpdir); + + $this->assertSame('BAR', $foo); + $this->assertSame('BAZ', $bar); + } + /** * @expectedException \Symfony\Component\Dotenv\Exception\PathException */ @@ -228,6 +263,18 @@ class DotenvTest extends TestCase $this->assertSame('http_value', $_SERVER['HTTP_TEST_ENV_VAR']); } + public function testEnvVarIsOverriden() + { + putenv('TEST_ENV_VAR_OVERRIDEN=original_value'); + + $dotenv = new DotEnv(); + $dotenv->populate(array('TEST_ENV_VAR_OVERRIDEN' => 'new_value'), true); + + $this->assertSame('new_value', getenv('TEST_ENV_VAR_OVERRIDEN')); + $this->assertSame('new_value', $_ENV['TEST_ENV_VAR_OVERRIDEN']); + $this->assertSame('new_value', $_SERVER['TEST_ENV_VAR_OVERRIDEN']); + } + public function testMemorizingLoadedVarsNamesInSpecialVar() { // Special variable not exists