diff --git a/src/Symfony/Component/Dotenv/CHANGELOG.md b/src/Symfony/Component/Dotenv/CHANGELOG.md
index 3cf07eecc86eb..ea9935fdb9adc 100644
--- a/src/Symfony/Component/Dotenv/CHANGELOG.md
+++ b/src/Symfony/Component/Dotenv/CHANGELOG.md
@@ -1,6 +1,11 @@
CHANGELOG
=========
+6.2
+---
+
+ * Add new `filter` argument to `debug:dotenv` command to be able to filter certain variable
+
5.4
---
diff --git a/src/Symfony/Component/Dotenv/Command/DebugCommand.php b/src/Symfony/Component/Dotenv/Command/DebugCommand.php
index 8827460caf432..9d51855e9359f 100644
--- a/src/Symfony/Component/Dotenv/Command/DebugCommand.php
+++ b/src/Symfony/Component/Dotenv/Command/DebugCommand.php
@@ -13,6 +13,7 @@
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
@@ -47,6 +48,25 @@ public function __construct(string $kernelEnvironment, string $projectDirectory)
parent::__construct();
}
+ protected function configure(): void
+ {
+ $this
+ ->setDefinition([
+ new InputArgument('filter', InputArgument::OPTIONAL, 'The name of an environment variable or a filter.', null, $this->getAvailableVars(...)),
+ ])
+ ->setHelp(<<<'EOT'
+The %command.full_name% command displays all the environment variables configured by dotenv:
+
+ php %command.full_name%
+
+To get specific variable, specify its full or partial name:
+
+ php %command.full_name% FOO_BAR
+
+EOT
+ );
+ }
+
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
@@ -78,25 +98,36 @@ protected function execute(InputInterface $input, OutputInterface $output): int
: sprintf('⨯> %s', $envFile);
}, $envFiles));
+ $nameFilter = $input->getArgument('filter');
+ $variables = $this->getVariables($availableFiles, $nameFilter);
+
$io->section('Variables');
- $io->table(
- array_merge(['Variable', 'Value'], $availableFiles),
- $this->getVariables($availableFiles)
- );
- $io->comment('Note real values might be different between web and CLI.');
+ if ($variables || null === $nameFilter) {
+ $io->table(
+ array_merge(['Variable', 'Value'], $availableFiles),
+ $this->getVariables($availableFiles, $nameFilter)
+ );
+
+ $io->comment('Note that values might be different between web and CLI.');
+ } else {
+ $io->warning(sprintf('No variables match the given filter "%s".', $nameFilter));
+ }
return 0;
}
- private function getVariables(array $envFiles): array
+ private function getVariables(array $envFiles, ?string $nameFilter): array
{
- $vars = explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? '');
- sort($vars);
+ $vars = $this->getAvailableVars();
$output = [];
$fileValues = [];
foreach ($vars as $var) {
+ if (null !== $nameFilter && 0 !== stripos($var, $nameFilter)) {
+ continue;
+ }
+
$realValue = $_SERVER[$var];
$varDetails = [$var, $realValue];
foreach ($envFiles as $envFile) {
@@ -113,6 +144,14 @@ private function getVariables(array $envFiles): array
return $output;
}
+ private function getAvailableVars(): array
+ {
+ $vars = explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? '');
+ sort($vars);
+
+ return $vars;
+ }
+
private function getEnvFiles(): array
{
$files = [
diff --git a/src/Symfony/Component/Dotenv/Tests/Command/DebugCommandTest.php b/src/Symfony/Component/Dotenv/Tests/Command/DebugCommandTest.php
index b3b089e4559c9..906c992924c16 100644
--- a/src/Symfony/Component/Dotenv/Tests/Command/DebugCommandTest.php
+++ b/src/Symfony/Component/Dotenv/Tests/Command/DebugCommandTest.php
@@ -14,6 +14,7 @@
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Helper\FormatterHelper;
use Symfony\Component\Console\Helper\HelperSet;
+use Symfony\Component\Console\Tester\CommandCompletionTester;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\Dotenv\Command\DebugCommand;
use Symfony\Component\Dotenv\Dotenv;
@@ -138,7 +139,88 @@ public function testWarningOnPhpEnvFile()
$this->assertStringContainsString('[WARNING] Due to existing dump file (.env.local.php)', $output);
}
- private function executeCommand(string $projectDirectory, string $env): string
+ public function testScenario1InDevEnvWithNameFilter()
+ {
+ $output = $this->executeCommand(__DIR__.'/Fixtures/Scenario1', 'dev', ['filter' => 'FoO']);
+
+ // Scanned Files
+ $this->assertStringContainsString('⨯ .env.local.php', $output);
+ $this->assertStringContainsString('⨯ .env.dev.local', $output);
+ $this->assertStringContainsString('⨯ .env.dev', $output);
+ $this->assertStringContainsString('✓ .env.local', $output);
+ $this->assertStringContainsString('✓ .env'.\PHP_EOL, $output);
+
+ // Skipped Files
+ $this->assertStringNotContainsString('.env.prod', $output);
+ $this->assertStringNotContainsString('.env.test', $output);
+ $this->assertStringNotContainsString('.env.dist', $output);
+
+ // Variables
+ $this->assertStringContainsString('Variable Value .env.local .env', $output);
+ $this->assertStringContainsString('FOO baz baz bar', $output);
+ $this->assertStringNotContainsString('TEST123 true n/a true', $output);
+ }
+
+ public function testScenario1InProdEnvWithMissingNameFilter()
+ {
+ $output = $this->executeCommand(__DIR__.'/Fixtures/Scenario1', 'prod', ['filter' => 'unknown']);
+
+ // Scanned Files
+ $this->assertStringContainsString('⨯ .env.local.php', $output);
+ $this->assertStringContainsString('✓ .env.prod.local', $output);
+ $this->assertStringContainsString('⨯ .env.prod', $output);
+ $this->assertStringContainsString('✓ .env.local', $output);
+ $this->assertStringContainsString('✓ .env'.\PHP_EOL, $output);
+
+ // Skipped Files
+ $this->assertStringNotContainsString('.env.dev', $output);
+ $this->assertStringNotContainsString('.env.test', $output);
+ $this->assertStringNotContainsString('.env.dist', $output);
+
+ // Variables
+ $this->assertStringContainsString('[WARNING] No variables match the given filter "unknown".', $output);
+ $this->assertStringNotContainsString('Variable Value .env.prod.local .env.local .env', $output);
+ $this->assertStringNotContainsString('FOO baz n/a baz bar', $output);
+ $this->assertStringNotContainsString('HELLO world world n/a n/a', $output);
+ $this->assertStringNotContainsString('TEST123 true n/a n/a true', $output);
+ }
+
+ public function testScenario2InProdEnvWithNameFilterPrefix()
+ {
+ $output = $this->executeCommand(__DIR__.'/Fixtures/Scenario2', 'prod', ['filter' => 'tes']);
+
+ // Scanned Files
+ $this->assertStringContainsString('✓ .env.local.php', $output);
+ $this->assertStringContainsString('⨯ .env.prod.local', $output);
+ $this->assertStringContainsString('✓ .env.prod', $output);
+ $this->assertStringContainsString('⨯ .env.local', $output);
+ $this->assertStringContainsString('✓ .env.dist', $output);
+
+ // Skipped Files
+ $this->assertStringNotContainsString('.env'.\PHP_EOL, $output);
+ $this->assertStringNotContainsString('.env.dev', $output);
+ $this->assertStringNotContainsString('.env.test', $output);
+
+ // Variables
+ $this->assertStringContainsString('Variable Value .env.local.php .env.prod .env.dist', $output);
+ $this->assertStringNotContainsString('FOO BaR BaR BaR n/a', $output);
+ $this->assertStringContainsString('TEST 1234 1234 1234 0000', $output);
+ }
+
+ public function testCompletion()
+ {
+ $env = 'prod';
+ $projectDirectory = __DIR__.'/Fixtures/Scenario2';
+
+ $_SERVER['TEST_ENV_KEY'] = $env;
+ (new Dotenv('TEST_ENV_KEY'))->bootEnv($projectDirectory.'/.env');
+
+ $command = new DebugCommand($env, $projectDirectory);
+ $tester = new CommandCompletionTester($command);
+ $this->assertSame(['FOO', 'HELLO', 'TEST', 'TEST123'], $tester->complete(['']));
+ }
+
+ private function executeCommand(string $projectDirectory, string $env, array $input = []): string
{
$_SERVER['TEST_ENV_KEY'] = $env;
(new Dotenv('TEST_ENV_KEY'))->bootEnv($projectDirectory.'/.env');
@@ -146,7 +228,7 @@ private function executeCommand(string $projectDirectory, string $env): string
$command = new DebugCommand($env, $projectDirectory);
$command->setHelperSet(new HelperSet([new FormatterHelper()]));
$tester = new CommandTester($command);
- $tester->execute([]);
+ $tester->execute($input);
return $tester->getDisplay();
}