Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 48b78fe

Browse filesBrowse files
feature #43755 [Dotenv] Add $overrideExistingVars to bootEnv() and loadEnv() and dotenv_overload to SymfonyRuntime (fancyweb)
This PR was merged into the 5.4 branch. Discussion ---------- [Dotenv] Add $overrideExistingVars to bootEnv() and loadEnv() and dotenv_overload to SymfonyRuntime | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | #41681 (comment) | License | MIT | Doc PR | - The goal is to be able to use `bootEnv()` and `loadEnv()` and override existing vars directly instead of having to call `overload()` in a second time. Commits ------- bcb0592 [Dotenv][Runtime] Add $overrideExistingVars to bootEnv() and loadEnv() and dotenv_overload to SymfonyRuntime
2 parents 886bac1 + bcb0592 commit 48b78fe
Copy full SHA for 48b78fe

File tree

8 files changed

+124
-19
lines changed
Filter options

8 files changed

+124
-19
lines changed

‎src/Symfony/Component/Dotenv/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Dotenv/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ CHANGELOG
66

77
* Add `dotenv:dump` command to compile the contents of the .env files into a PHP-optimized file called `.env.local.php`
88
* Add `debug:dotenv` command to list all dotenv files with variables and values
9+
* Add `$overrideExistingVars` on `Dotenv::bootEnv()` and `Dotenv::loadEnv()`
910

1011
5.1.0
1112
-----

‎src/Symfony/Component/Dotenv/Dotenv.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Dotenv/Dotenv.php
+10-10Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -106,22 +106,22 @@ public function load(string $path, string ...$extraPaths): void
106106
* @throws FormatException when a file has a syntax error
107107
* @throws PathException when a file does not exist or is not readable
108108
*/
109-
public function loadEnv(string $path, string $envKey = null, string $defaultEnv = 'dev', array $testEnvs = ['test']): void
109+
public function loadEnv(string $path, string $envKey = null, string $defaultEnv = 'dev', array $testEnvs = ['test'], bool $overrideExistingVars = false): void
110110
{
111111
$k = $envKey ?? $this->envKey;
112112

113113
if (is_file($path) || !is_file($p = "$path.dist")) {
114-
$this->load($path);
114+
$this->doLoad($overrideExistingVars, [$path]);
115115
} else {
116-
$this->load($p);
116+
$this->doLoad($overrideExistingVars, [$p]);
117117
}
118118

119119
if (null === $env = $_SERVER[$k] ?? $_ENV[$k] ?? null) {
120-
$this->populate([$k => $env = $defaultEnv]);
120+
$this->populate([$k => $env = $defaultEnv], $overrideExistingVars);
121121
}
122122

123123
if (!\in_array($env, $testEnvs, true) && is_file($p = "$path.local")) {
124-
$this->load($p);
124+
$this->doLoad($overrideExistingVars, [$p]);
125125
$env = $_SERVER[$k] ?? $_ENV[$k] ?? $env;
126126
}
127127

@@ -130,11 +130,11 @@ public function loadEnv(string $path, string $envKey = null, string $defaultEnv
130130
}
131131

132132
if (is_file($p = "$path.$env")) {
133-
$this->load($p);
133+
$this->doLoad($overrideExistingVars, [$p]);
134134
}
135135

136136
if (is_file($p = "$path.$env.local")) {
137-
$this->load($p);
137+
$this->doLoad($overrideExistingVars, [$p]);
138138
}
139139
}
140140

@@ -145,16 +145,16 @@ public function loadEnv(string $path, string $envKey = null, string $defaultEnv
145145
*
146146
* See method loadEnv() for rules related to .env files.
147147
*/
148-
public function bootEnv(string $path, string $defaultEnv = 'dev', array $testEnvs = ['test']): void
148+
public function bootEnv(string $path, string $defaultEnv = 'dev', array $testEnvs = ['test'], bool $overrideExistingVars = false): void
149149
{
150150
$p = $path.'.local.php';
151151
$env = is_file($p) ? include $p : null;
152152
$k = $this->envKey;
153153

154154
if (\is_array($env) && (!isset($env[$k]) || ($_SERVER[$k] ?? $_ENV[$k] ?? $env[$k]) === $env[$k])) {
155-
$this->populate($env);
155+
$this->populate($env, $overrideExistingVars);
156156
} else {
157-
$this->loadEnv($path, $k, $defaultEnv, $testEnvs);
157+
$this->loadEnv($path, $k, $defaultEnv, $testEnvs, $overrideExistingVars);
158158
}
159159

160160
$_SERVER += $_ENV;

‎src/Symfony/Component/Dotenv/Tests/DotenvTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Dotenv/Tests/DotenvTest.php
+78-7Lines changed: 78 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -236,61 +236,117 @@ public function testLoadEnv()
236236
putenv('SYMFONY_DOTENV_VARS');
237237
putenv('FOO');
238238
putenv('TEST_APP_ENV');
239+
240+
$_ENV['EXISTING_KEY'] = $_SERVER['EXISTING_KEY'] = 'EXISTING_VALUE';
241+
putenv('EXISTING_KEY=EXISTING_VALUE');
239242
};
240243

241244
@mkdir($tmpdir = sys_get_temp_dir().'/dotenv');
242245

243246
$path = tempnam($tmpdir, 'sf-');
244247

245248
// .env
246-
file_put_contents($path, 'FOO=BAR');
249+
file_put_contents($path, "FOO=BAR\nEXISTING_KEY=NEW_VALUE");
247250

248251
$resetContext();
249252
(new Dotenv())->usePutenv()->loadEnv($path, 'TEST_APP_ENV');
250253
$this->assertSame('BAR', getenv('FOO'));
251254
$this->assertSame('dev', getenv('TEST_APP_ENV'));
255+
$this->assertSame('EXISTING_VALUE', getenv('EXISTING_KEY'));
256+
$this->assertSame('EXISTING_VALUE', $_ENV['EXISTING_KEY']);
257+
258+
$resetContext();
259+
(new Dotenv())->usePutenv()->loadEnv($path, 'TEST_APP_ENV', 'dev', ['test'], true);
260+
$this->assertSame('BAR', getenv('FOO'));
261+
$this->assertSame('dev', getenv('TEST_APP_ENV'));
262+
$this->assertSame('NEW_VALUE', getenv('EXISTING_KEY'));
263+
$this->assertSame('NEW_VALUE', $_ENV['EXISTING_KEY']);
252264

253265
// .env.local
254-
file_put_contents("$path.local", 'FOO=localBAR');
266+
file_put_contents("$path.local", "FOO=localBAR\nEXISTING_KEY=localNEW_VALUE");
255267

256268
$resetContext();
257269
$_SERVER['TEST_APP_ENV'] = 'local';
258270
(new Dotenv())->usePutenv()->loadEnv($path, 'TEST_APP_ENV');
259271
$this->assertSame('localBAR', getenv('FOO'));
272+
$this->assertSame('EXISTING_VALUE', getenv('EXISTING_KEY'));
273+
$this->assertSame('EXISTING_VALUE', $_ENV['EXISTING_KEY']);
274+
275+
$resetContext();
276+
$_SERVER['TEST_APP_ENV'] = 'local';
277+
(new Dotenv())->usePutenv()->loadEnv($path, 'TEST_APP_ENV', 'dev', ['test'], true);
278+
$this->assertSame('localBAR', getenv('FOO'));
279+
$this->assertSame('localNEW_VALUE', getenv('EXISTING_KEY'));
280+
$this->assertSame('localNEW_VALUE', $_ENV['EXISTING_KEY']);
260281

261282
// special case for test
262283
$resetContext();
263284
$_SERVER['TEST_APP_ENV'] = 'test';
264285
(new Dotenv())->usePutenv()->loadEnv($path, 'TEST_APP_ENV');
265286
$this->assertSame('BAR', getenv('FOO'));
287+
$this->assertSame('EXISTING_VALUE', getenv('EXISTING_KEY'));
288+
$this->assertSame('EXISTING_VALUE', $_ENV['EXISTING_KEY']);
289+
290+
$resetContext();
291+
$_SERVER['TEST_APP_ENV'] = 'test';
292+
(new Dotenv())->usePutenv()->loadEnv($path, 'TEST_APP_ENV', 'dev', ['test'], true);
293+
$this->assertSame('BAR', getenv('FOO'));
294+
$this->assertSame('NEW_VALUE', getenv('EXISTING_KEY'));
295+
$this->assertSame('NEW_VALUE', $_ENV['EXISTING_KEY']);
266296

267297
// .env.dev
268-
file_put_contents("$path.dev", 'FOO=devBAR');
298+
file_put_contents("$path.dev", "FOO=devBAR\nEXISTING_KEY=devNEW_VALUE");
269299

270300
$resetContext();
271301
(new Dotenv())->usePutenv()->loadEnv($path, 'TEST_APP_ENV');
272302
$this->assertSame('devBAR', getenv('FOO'));
303+
$this->assertSame('EXISTING_VALUE', getenv('EXISTING_KEY'));
304+
$this->assertSame('EXISTING_VALUE', $_ENV['EXISTING_KEY']);
305+
306+
$resetContext();
307+
(new Dotenv())->usePutenv()->loadEnv($path, 'TEST_APP_ENV', 'dev', ['test'], true);
308+
$this->assertSame('devBAR', getenv('FOO'));
309+
$this->assertSame('devNEW_VALUE', getenv('EXISTING_KEY'));
310+
$this->assertSame('devNEW_VALUE', $_ENV['EXISTING_KEY']);
273311

274312
// .env.dev.local
275-
file_put_contents("$path.dev.local", 'FOO=devlocalBAR');
313+
file_put_contents("$path.dev.local", "FOO=devlocalBAR\nEXISTING_KEY=devlocalNEW_VALUE");
276314

277315
$resetContext();
278316
(new Dotenv())->usePutenv()->loadEnv($path, 'TEST_APP_ENV');
279317
$this->assertSame('devlocalBAR', getenv('FOO'));
318+
$this->assertSame('EXISTING_VALUE', getenv('EXISTING_KEY'));
319+
$this->assertSame('EXISTING_VALUE', $_ENV['EXISTING_KEY']);
320+
321+
$resetContext();
322+
(new Dotenv())->usePutenv()->loadEnv($path, 'TEST_APP_ENV', 'dev', ['test'], true);
323+
$this->assertSame('devlocalBAR', getenv('FOO'));
324+
$this->assertSame('devlocalNEW_VALUE', getenv('EXISTING_KEY'));
325+
$this->assertSame('devlocalNEW_VALUE', $_ENV['EXISTING_KEY']);
280326
unlink("$path.local");
281327
unlink("$path.dev");
282328
unlink("$path.dev.local");
283329

284330
// .env.dist
285-
file_put_contents("$path.dist", 'FOO=distBAR');
331+
file_put_contents("$path.dist", "FOO=distBAR\nEXISTING_KEY=distNEW_VALUE");
286332

287333
$resetContext();
288334
unlink($path);
289335
(new Dotenv())->usePutenv()->loadEnv($path, 'TEST_APP_ENV');
290336
$this->assertSame('distBAR', getenv('FOO'));
337+
$this->assertSame('EXISTING_VALUE', getenv('EXISTING_KEY'));
338+
$this->assertSame('EXISTING_VALUE', $_ENV['EXISTING_KEY']);
339+
340+
$resetContext();
341+
(new Dotenv())->usePutenv()->loadEnv($path, 'TEST_APP_ENV', 'dev', ['test'], true);
342+
$this->assertSame('distBAR', getenv('FOO'));
343+
$this->assertSame('distNEW_VALUE', getenv('EXISTING_KEY'));
344+
$this->assertSame('distNEW_VALUE', $_ENV['EXISTING_KEY']);
291345
unlink("$path.dist");
292346

293347
$resetContext();
348+
unset($_ENV['EXISTING_KEY'], $_SERVER['EXISTING_KEY']);
349+
putenv('EXISTING_KEY');
294350
rmdir($tmpdir);
295351
}
296352

@@ -490,22 +546,37 @@ public function testBootEnv()
490546
unset($_SERVER['TEST_APP_ENV'], $_ENV['TEST_APP_ENV']);
491547
unset($_SERVER['TEST_APP_DEBUG'], $_ENV['TEST_APP_DEBUG']);
492548
unset($_SERVER['FOO'], $_ENV['FOO']);
549+
550+
$_ENV['EXISTING_KEY'] = $_SERVER['EXISTING_KEY'] = 'EXISTING_VALUE';
493551
};
494552

495553
@mkdir($tmpdir = sys_get_temp_dir().'/dotenv');
496554
$path = tempnam($tmpdir, 'sf-');
497555

498-
file_put_contents($path, 'FOO=BAR');
556+
file_put_contents($path, "FOO=BAR\nEXISTING_KEY=NEW_VALUE");
499557
$resetContext();
500558
(new Dotenv('TEST_APP_ENV', 'TEST_APP_DEBUG'))->bootEnv($path);
501559
$this->assertSame('BAR', $_SERVER['FOO']);
560+
$this->assertSame('EXISTING_VALUE', $_SERVER['EXISTING_KEY']);
561+
562+
$resetContext();
563+
(new Dotenv('TEST_APP_ENV', 'TEST_APP_DEBUG'))->bootEnv($path, 'dev', ['test'], true);
564+
$this->assertSame('BAR', $_SERVER['FOO']);
565+
$this->assertSame('NEW_VALUE', $_SERVER['EXISTING_KEY']);
502566
unlink($path);
503567

504-
file_put_contents($path.'.local.php', '<?php return ["TEST_APP_ENV" => "dev", "FOO" => "BAR"];');
568+
file_put_contents($path.'.local.php', '<?php return ["TEST_APP_ENV" => "dev", "FOO" => "BAR", "EXISTING_KEY" => "localphpNEW_VALUE"];');
505569
$resetContext();
506570
(new Dotenv('TEST_APP_ENV', 'TEST_APP_DEBUG'))->bootEnv($path);
507571
$this->assertSame('BAR', $_SERVER['FOO']);
508572
$this->assertSame('1', $_SERVER['TEST_APP_DEBUG']);
573+
$this->assertSame('EXISTING_VALUE', $_SERVER['EXISTING_KEY']);
574+
575+
$resetContext();
576+
(new Dotenv('TEST_APP_ENV', 'TEST_APP_DEBUG'))->bootEnv($path, 'dev', ['test'], true);
577+
$this->assertSame('BAR', $_SERVER['FOO']);
578+
$this->assertSame('1', $_SERVER['TEST_APP_DEBUG']);
579+
$this->assertSame('localphpNEW_VALUE', $_SERVER['EXISTING_KEY']);
509580
unlink($path.'.local.php');
510581

511582
$resetContext();

‎src/Symfony/Component/Runtime/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Runtime/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ CHANGELOG
66

77
* The component is not experimental anymore
88
* Add options "env_var_name" and "debug_var_name" to `GenericRuntime` and `SymfonyRuntime`
9+
* Add option "dotenv_overload" to `SymfonyRuntime`
910

1011
5.3.0
1112
-----

‎src/Symfony/Component/Runtime/SymfonyRuntime.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Runtime/SymfonyRuntime.php
+3-1Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class_exists(MissingDotenv::class, false) || class_exists(Dotenv::class) || clas
4040
* - "prod_envs" to define the names of the production envs - defaults to ["prod"];
4141
* - "test_envs" to define the names of the test envs - defaults to ["test"];
4242
* - "use_putenv" to tell Dotenv to set env vars using putenv() (NOT RECOMMENDED.)
43+
* - "dotenv_overload" to tell Dotenv to override existing vars
4344
*
4445
* When the "debug" / "env" options are not defined, they will fallback to the
4546
* "APP_DEBUG" / "APP_ENV" environment variables, and to the "--env|-e" / "--no-debug"
@@ -84,6 +85,7 @@ class SymfonyRuntime extends GenericRuntime
8485
* error_handler?: string|false,
8586
* env_var_name?: string,
8687
* debug_var_name?: string,
88+
* dotenv_overload?: ?bool,
8789
* } $options
8890
*/
8991
public function __construct(array $options = [])
@@ -102,7 +104,7 @@ public function __construct(array $options = [])
102104
(new Dotenv($envKey, $debugKey))
103105
->setProdEnvs((array) ($options['prod_envs'] ?? ['prod']))
104106
->usePutenv($options['use_putenv'] ?? false)
105-
->bootEnv($options['project_dir'].'/'.($options['dotenv_path'] ?? '.env'), 'dev', (array) ($options['test_envs'] ?? ['test']));
107+
->bootEnv($options['project_dir'].'/'.($options['dotenv_path'] ?? '.env'), 'dev', (array) ($options['test_envs'] ?? ['test']), $options['dotenv_overload'] ?? false);
106108
$options['debug'] ?? $options['debug'] = '1' === $_SERVER[$debugKey];
107109
$options['disable_dotenv'] = true;
108110
} else {

‎src/Symfony/Component/Runtime/Tests/phpt/autoload.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Runtime/Tests/phpt/autoload.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
use Symfony\Component\Runtime\SymfonyRuntime;
44

5-
$_SERVER['APP_RUNTIME_OPTIONS'] = [
5+
$_SERVER['APP_RUNTIME_OPTIONS'] = $_SERVER['APP_RUNTIME_OPTIONS'] ?? [];
6+
$_SERVER['APP_RUNTIME_OPTIONS'] += [
67
'project_dir' => __DIR__,
78
] + ($_SERVER['APP_RUNTIME_OPTIONS'] ?? []);
89

+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
use Symfony\Component\HttpFoundation\Request;
4+
use Symfony\Component\HttpFoundation\Response;
5+
6+
$_SERVER['SOME_VAR'] = 'ccc';
7+
$_SERVER['APP_RUNTIME_OPTIONS'] = [
8+
'dotenv_overload' => true,
9+
];
10+
11+
require __DIR__.'/autoload.php';
12+
13+
return function (Request $request, array $context) {
14+
return new Response('OK Request '.$context['SOME_VAR']);
15+
};
+14Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
Test Dotenv overload
3+
--SKIPIF--
4+
<?php require dirname(__DIR__, 6).'/vendor/autoload.php'; if (4 > (new \ReflectionMethod(\Symfony\Component\Dotenv\Dotenv::class, 'bootEnv'))->getNumberOfParameters()) die('Skip because Dotenv version is too low');
5+
--INI--
6+
display_errors=1
7+
--FILE--
8+
<?php
9+
10+
require $_SERVER['SCRIPT_FILENAME'] = __DIR__.'/dotenv_overload.php';
11+
12+
?>
13+
--EXPECTF--
14+
OK Request foo_bar

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.