Skip to content
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

[Dotenv] add loadEnv(), a smoother alternative to loadForEnv() #29129

Merged
merged 1 commit into from Nov 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
51 changes: 29 additions & 22 deletions src/Symfony/Component/Dotenv/Dotenv.php
Expand Up @@ -48,34 +48,41 @@ final class Dotenv
*/
public function load(string $path, string ...$extraPaths): void
{
$this->doLoad(false, false, \func_get_args());
$this->doLoad(false, \func_get_args());
}

/**
* Loads one or several .env and the corresponding .env.$env, .env.local and .env.$env.local files if they exist.
* Loads a .env file and the corresponding .env.local, .env.$env and .env.$env.local files if they exist.
*
* .env.local is always ignored in test env because tests should produce the same results for everyone.
*
* @param string $path A file to load
* @param ...string $extraPaths A list of additional files to load
* @param string $path A file to load
* @param string $varName The name of the env vars that defines the app env
* @param string $defaultEnv The app env to use when none is defined
* @param array $testEnvs A list of app envs for which .env.local should be ignored
*
* @throws FormatException when a file has a syntax error
* @throws PathException when a file does not exist or is not readable
*
* @see https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
*/
public function loadForEnv(string $env, string $path, string ...$extraPaths): void
public function loadEnv(string $path, string $varName = 'APP_ENV', string $defaultEnv = 'dev', array $testEnvs = array('test')): void
{
$paths = \func_get_args();
for ($i = 1; $i < \func_num_args(); ++$i) {
$path = $paths[$i];
$pathList = array($path, "$path.$env");
if ('test' !== $env) {
$pathList[] = "$path.local";
}
$pathList[] = "$path.$env.local";
$this->load($path);

if (null === $env = $_SERVER[$varName] ?? $_ENV[$varName] ?? null) {
$this->populate(array($varName => $env = $defaultEnv));
}

$this->doLoad(false, true, $pathList);
if (!\in_array($env, $testEnvs, true) && file_exists($p = "$path.local")) {
$this->load($p);
$env = $_SERVER[$varName] ?? $_ENV[$varName] ?? $env;
}

if (file_exists($p = "$path.$env")) {
$this->load($p);
}

if (file_exists($p = "$path.$env.local")) {
$this->load($p);
}
}

Expand All @@ -90,7 +97,7 @@ public function loadForEnv(string $env, string $path, string ...$extraPaths): vo
*/
public function overload(string $path, string ...$extraPaths): void
{
$this->doLoad(true, false, \func_get_args());
$this->doLoad(true, \func_get_args());
}

/**
Expand Down Expand Up @@ -434,14 +441,14 @@ private function createFormatException($message)
return new FormatException($message, new FormatExceptionContext($this->data, $this->path, $this->lineno, $this->cursor));
}

private function doLoad(bool $overrideExistingVars, bool $ignoreMissingExtraPaths, array $paths): void
private function doLoad(bool $overrideExistingVars, array $paths): void
{
foreach ($paths as $i => $path) {
if (is_readable($path) && !is_dir($path)) {
$this->populate($this->parse(file_get_contents($path), $path), $overrideExistingVars);
} elseif (!$ignoreMissingExtraPaths || 0 === $i) {
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);
}
}
}
48 changes: 22 additions & 26 deletions src/Symfony/Component/Dotenv/Tests/DotenvTest.php
Expand Up @@ -186,7 +186,7 @@ public function testLoad()
$this->assertSame('BAZ', $bar);
}

public function testLoadForEnv()
public function testLoadEnv()
{
unset($_ENV['FOO']);
unset($_ENV['BAR']);
Expand All @@ -197,50 +197,46 @@ public function testLoadForEnv()

@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');
$path = tempnam($tmpdir, 'sf-');

// .env

(new DotEnv())->loadForEnv('dev', $path1, $path2);

file_put_contents($path, 'FOO=BAR');
(new DotEnv())->loadEnv($path, 'TEST_APP_ENV');
$this->assertSame('BAR', getenv('FOO'));
$this->assertSame('BAZ', getenv('BAR'));

// .env.dev

file_put_contents("$path1.dev", 'FOO=devBAR');
(new DotEnv())->loadForEnv('dev', $path1, $path2);
$this->assertSame('devBAR', getenv('FOO'));
$this->assertSame('dev', getenv('TEST_APP_ENV'));

// .env.local

file_put_contents("$path1.local", 'FOO=localBAR');
(new DotEnv())->loadForEnv('dev', $path1, $path2);
file_put_contents("$path.local", 'FOO=localBAR');
(new DotEnv())->loadEnv($path, 'TEST_APP_ENV');
$this->assertSame('localBAR', getenv('FOO'));

// special case for test

file_put_contents("$path1.local", 'FOO=testBAR');
(new DotEnv())->loadForEnv('test', $path1, $path2);
$_SERVER['TEST_APP_ENV'] = 'test';
(new DotEnv())->loadEnv($path, 'TEST_APP_ENV');
$this->assertSame('BAR', getenv('FOO'));

// .env.dev

unset($_SERVER['TEST_APP_ENV']);
file_put_contents("$path.dev", 'FOO=devBAR');
(new DotEnv())->loadEnv($path, 'TEST_APP_ENV');
$this->assertSame('devBAR', getenv('FOO'));

// .env.dev.local

file_put_contents("$path1.dev.local", 'FOO=devlocalBAR');
(new DotEnv())->loadForEnv('dev', $path1, $path2);
file_put_contents("$path.dev.local", 'FOO=devlocalBAR');
(new DotEnv())->loadEnv($path, 'TEST_APP_ENV');
$this->assertSame('devlocalBAR', getenv('FOO'));

putenv('FOO');
putenv('BAR');
unlink($path1);
unlink("$path1.dev");
unlink("$path1.local");
unlink("$path1.dev.local");
unlink($path2);
unlink($path);
unlink("$path.dev");
unlink("$path.local");
unlink("$path.dev.local");
rmdir($tmpdir);
}

Expand Down