Skip to content

Commit 68cd3f9

Browse files
committedNov 20, 2023
DotEnv debug command aware of custom dotenv_path
Introduce SYMFONY_DOTENV_PATH set by DotEnv class and read by debug:dotenv command to contextualize the debug info with the file that was actually parsed.
1 parent 782d55c commit 68cd3f9

File tree

5 files changed

+85
-25
lines changed

5 files changed

+85
-25
lines changed
 

‎CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
7.1
5+
---
6+
7+
* Add `SYMFONY_DOTENV_PATH` variable with the path to the `.env` file loaded by `Dotenv::loadEnv()` or `Dotenv::bootEnv()`
8+
49
6.2
510
---
611

‎Command/DebugCommand.php

+27-23
Original file line numberDiff line numberDiff line change
@@ -70,21 +70,23 @@ protected function execute(InputInterface $input, OutputInterface $output): int
7070
return 1;
7171
}
7272

73-
$envFiles = $this->getEnvFiles();
74-
$availableFiles = array_filter($envFiles, fn (string $file) => is_file($this->getFilePath($file)));
73+
$filePath = $_SERVER['SYMFONY_DOTENV_PATH'] ?? $this->projectDirectory.\DIRECTORY_SEPARATOR.'.env';
7574

76-
if (\in_array('.env.local.php', $availableFiles, true)) {
77-
$io->warning('Due to existing dump file (.env.local.php) all other dotenv files are skipped.');
75+
$envFiles = $this->getEnvFiles($filePath);
76+
$availableFiles = array_filter($envFiles, fn (string $file) => is_file($file));
77+
78+
if (\in_array(sprintf('%s.local.php', $filePath), $availableFiles, true)) {
79+
$io->warning(sprintf('Due to existing dump file (%s.local.php) all other dotenv files are skipped.', $this->getRelativeName($filePath)));
7880
}
7981

80-
if (is_file($this->getFilePath('.env')) && is_file($this->getFilePath('.env.dist'))) {
81-
$io->warning('The file .env.dist gets skipped due to the existence of .env.');
82+
if (is_file($filePath) && is_file(sprintf('%s.dist', $filePath))) {
83+
$io->warning(sprintf('The file %s.dist gets skipped due to the existence of %1$s.', $this->getRelativeName($filePath)));
8284
}
8385

8486
$io->section('Scanned Files (in descending priority)');
85-
$io->listing(array_map(static fn (string $envFile) => \in_array($envFile, $availableFiles, true)
86-
? sprintf('<fg=green>✓</> %s', $envFile)
87-
: sprintf('<fg=red>⨯</> %s', $envFile), $envFiles));
87+
$io->listing(array_map(fn (string $envFile) => \in_array($envFile, $availableFiles, true)
88+
? sprintf('<fg=green>✓</> %s', $this->getRelativeName($envFile))
89+
: sprintf('<fg=red>⨯</> %s', $this->getRelativeName($envFile)), $envFiles));
8890

8991
$nameFilter = $input->getArgument('filter');
9092
$variables = $this->getVariables($availableFiles, $nameFilter);
@@ -93,7 +95,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
9395

9496
if ($variables || null === $nameFilter) {
9597
$io->table(
96-
array_merge(['Variable', 'Value'], $availableFiles),
98+
array_merge(['Variable', 'Value'], array_map($this->getRelativeName(...), $availableFiles)),
9799
$this->getVariables($availableFiles, $nameFilter)
98100
);
99101

@@ -147,36 +149,38 @@ private function getAvailableVars(): array
147149
return $vars;
148150
}
149151

150-
private function getEnvFiles(): array
152+
private function getEnvFiles(string $filePath): array
151153
{
152154
$files = [
153-
'.env.local.php',
154-
sprintf('.env.%s.local', $this->kernelEnvironment),
155-
sprintf('.env.%s', $this->kernelEnvironment),
155+
sprintf('%s.local.php', $filePath),
156+
sprintf('%s.%s.local', $filePath, $this->kernelEnvironment),
157+
sprintf('%s.%s', $filePath, $this->kernelEnvironment),
156158
];
157159

158160
if ('test' !== $this->kernelEnvironment) {
159-
$files[] = '.env.local';
161+
$files[] = sprintf('%s.local', $filePath);
160162
}
161163

162-
if (!is_file($this->getFilePath('.env')) && is_file($this->getFilePath('.env.dist'))) {
163-
$files[] = '.env.dist';
164+
if (!is_file($filePath) && is_file(sprintf('%s.dist', $filePath))) {
165+
$files[] = sprintf('%s.dist', $filePath);
164166
} else {
165-
$files[] = '.env';
167+
$files[] = $filePath;
166168
}
167169

168170
return $files;
169171
}
170172

171-
private function getFilePath(string $file): string
173+
private function getRelativeName(string $filePath): string
172174
{
173-
return $this->projectDirectory.\DIRECTORY_SEPARATOR.$file;
175+
if (str_starts_with($filePath, $this->projectDirectory)) {
176+
return substr($filePath, \strlen($this->projectDirectory) + 1);
177+
}
178+
179+
return basename($filePath);
174180
}
175181

176-
private function loadValues(string $file): array
182+
private function loadValues(string $filePath): array
177183
{
178-
$filePath = $this->getFilePath($file);
179-
180184
if (str_ends_with($filePath, '.php')) {
181185
return include $filePath;
182186
}

‎Command/DotenvDumpCommand.php

+1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ private function loadEnv(string $dotenvPath, string $env, array $config): array
107107
try {
108108
$dotenv->loadEnv($dotenvPath, null, 'dev', $testEnvs);
109109
unset($_ENV['SYMFONY_DOTENV_VARS']);
110+
unset($_ENV['SYMFONY_DOTENV_PATH']);
110111

111112
return $_ENV;
112113
} finally {

‎Dotenv.php

+12
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ public function load(string $path, string ...$extraPaths): void
100100
*/
101101
public function loadEnv(string $path, string $envKey = null, string $defaultEnv = 'dev', array $testEnvs = ['test'], bool $overrideExistingVars = false): void
102102
{
103+
$this->populatePath($path);
104+
103105
$k = $envKey ?? $this->envKey;
104106

105107
if (is_file($path) || !is_file($p = "$path.dist")) {
@@ -144,6 +146,7 @@ public function bootEnv(string $path, string $defaultEnv = 'dev', array $testEnv
144146
$k = $this->envKey;
145147

146148
if (\is_array($env) && ($overrideExistingVars || !isset($env[$k]) || ($_SERVER[$k] ?? $_ENV[$k] ?? $env[$k]) === $env[$k])) {
149+
$this->populatePath($path);
147150
$this->populate($env, $overrideExistingVars);
148151
} else {
149152
$this->loadEnv($path, $k, $defaultEnv, $testEnvs, $overrideExistingVars);
@@ -556,4 +559,13 @@ private function doLoad(bool $overrideExistingVars, array $paths): void
556559
$this->populate($this->parse(file_get_contents($path), $path), $overrideExistingVars);
557560
}
558561
}
562+
563+
private function populatePath(string $path): void
564+
{
565+
$_ENV['SYMFONY_DOTENV_PATH'] = $_SERVER['SYMFONY_DOTENV_PATH'] = $path;
566+
567+
if ($this->usePutenv) {
568+
putenv('SYMFONY_DOTENV_PATH='.$path);
569+
}
570+
}
559571
}

‎Tests/Command/DebugCommandTest.php

+40-2
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,28 @@ public function testScenario2InProdEnv()
124124
$this->assertStringContainsString('TEST 1234 1234 1234 0000', $output);
125125
}
126126

127+
public function testScenario2WithCustomPath()
128+
{
129+
$output = $this->executeCommand(__DIR__.'/Fixtures', 'prod', [], __DIR__.'/Fixtures/Scenario2/.env');
130+
131+
// Scanned Files
132+
$this->assertStringContainsString('✓ Scenario2/.env.local.php', $output);
133+
$this->assertStringContainsString('⨯ Scenario2/.env.prod.local', $output);
134+
$this->assertStringContainsString('✓ Scenario2/.env.prod', $output);
135+
$this->assertStringContainsString('⨯ Scenario2/.env.local', $output);
136+
$this->assertStringContainsString('✓ Scenario2/.env.dist', $output);
137+
138+
// Skipped Files
139+
$this->assertStringNotContainsString('.env'.\PHP_EOL, $output);
140+
$this->assertStringNotContainsString('.env.dev', $output);
141+
$this->assertStringNotContainsString('.env.test', $output);
142+
143+
// Variables
144+
$this->assertStringContainsString('Variable Value Scenario2/.env.local.php Scenario2/.env.prod Scenario2/.env.dist', $output);
145+
$this->assertStringContainsString('FOO BaR BaR BaR n/a', $output);
146+
$this->assertStringContainsString('TEST 1234 1234 1234 0000', $output);
147+
}
148+
127149
public function testWarningOnEnvAndEnvDistFile()
128150
{
129151
$output = $this->executeCommand(__DIR__.'/Fixtures/Scenario3', 'dev');
@@ -132,6 +154,14 @@ public function testWarningOnEnvAndEnvDistFile()
132154
$this->assertStringContainsString('[WARNING] The file .env.dist gets skipped', $output);
133155
}
134156

157+
public function testWarningOnEnvAndEnvDistFileWithCustomPath()
158+
{
159+
$output = $this->executeCommand(__DIR__.'/Fixtures', 'dev', dotenvPath: __DIR__.'/Fixtures/Scenario3/.env');
160+
161+
// Warning
162+
$this->assertStringContainsString('[WARNING] The file Scenario3/.env.dist gets skipped', $output);
163+
}
164+
135165
public function testWarningOnPhpEnvFile()
136166
{
137167
$output = $this->executeCommand(__DIR__.'/Fixtures/Scenario2', 'prod');
@@ -140,6 +170,14 @@ public function testWarningOnPhpEnvFile()
140170
$this->assertStringContainsString('[WARNING] Due to existing dump file (.env.local.php)', $output);
141171
}
142172

173+
public function testWarningOnPhpEnvFileWithCustomPath()
174+
{
175+
$output = $this->executeCommand(__DIR__.'/Fixtures', 'prod', dotenvPath: __DIR__.'/Fixtures/Scenario2/.env');
176+
177+
// Warning
178+
$this->assertStringContainsString('[WARNING] Due to existing dump file (Scenario2/.env.local.php)', $output);
179+
}
180+
143181
public function testScenario1InDevEnvWithNameFilter()
144182
{
145183
$output = $this->executeCommand(__DIR__.'/Fixtures/Scenario1', 'dev', ['filter' => 'FoO']);
@@ -226,10 +264,10 @@ public function testCompletion()
226264
$this->assertSame(['FOO', 'TEST'], $tester->complete(['']));
227265
}
228266

229-
private function executeCommand(string $projectDirectory, string $env, array $input = []): string
267+
private function executeCommand(string $projectDirectory, string $env, array $input = [], string $dotenvPath = null): string
230268
{
231269
$_SERVER['TEST_ENV_KEY'] = $env;
232-
(new Dotenv('TEST_ENV_KEY'))->bootEnv($projectDirectory.'/.env');
270+
(new Dotenv('TEST_ENV_KEY'))->bootEnv($dotenvPath ?? $projectDirectory.'/.env');
233271

234272
$command = new DebugCommand($env, $projectDirectory);
235273
$command->setHelperSet(new HelperSet([new FormatterHelper()]));

0 commit comments

Comments
 (0)
Please sign in to comment.