Skip to content

Navigation Menu

Sign in
Appearance settings

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 47a2f58

Browse filesBrowse files
committed
feature #27684 [FrameworkBundle] Debug container environment variables (ro0NL)
This PR was squashed before being merged into the 4.3-dev branch (closes #27684). Discussion ---------- [FrameworkBundle] Debug container environment variables | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no <!-- see https://symfony.com/bc --> | Deprecations? | no | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | #... <!-- #-prefixed issue number(s), if any --> | License | MIT | Doc PR | symfony/symfony-docs#... <!-- required for new features --> This PR is an attempt to ease debugging environment variables used by the container. Main purpose is to tell which are missing and show detailed usage information. ![image](https://user-images.githubusercontent.com/1047696/47601226-ae43c480-d9cd-11e8-926b-8c49069189fc.png) ![image](https://user-images.githubusercontent.com/1047696/47601234-d7645500-d9cd-11e8-9e3f-d1c2ad85dbc5.png) Commits ------- b813a05 [FrameworkBundle] Debug container environment variables
2 parents 31cd26b + b813a05 commit 47a2f58
Copy full SHA for 47a2f58

File tree

Expand file treeCollapse file tree

9 files changed

+235
-7
lines changed
Filter options
Expand file treeCollapse file tree

9 files changed

+235
-7
lines changed

‎src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php
+21-4Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ protected function configure()
5858
new InputOption('parameter', null, InputOption::VALUE_REQUIRED, 'Displays a specific parameter for an application'),
5959
new InputOption('parameters', null, InputOption::VALUE_NONE, 'Displays parameters for an application'),
6060
new InputOption('types', null, InputOption::VALUE_NONE, 'Displays types (classes/interfaces) available in the container'),
61+
new InputOption('env-var', null, InputOption::VALUE_REQUIRED, 'Displays a specific environment variable used in the container'),
62+
new InputOption('env-vars', null, InputOption::VALUE_NONE, 'Displays environment variables used in the container'),
6163
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
6264
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw description'),
6365
])
@@ -75,6 +77,14 @@ protected function configure()
7577
7678
<info>php %command.full_name% --types</info>
7779
80+
To see environment variables used by the container, use the <info>--env-vars</info> flag:
81+
82+
<info>php %command.full_name% --env-vars</info>
83+
84+
Display a specific environment variable by specifying its name with the <info>--env-var</info> option:
85+
86+
<info>php %command.full_name% --env-var=APP_ENV</info>
87+
7888
Use the --tags option to display tagged <comment>public</comment> services grouped by tag:
7989
8090
<info>php %command.full_name% --tags</info>
@@ -116,7 +126,11 @@ protected function execute(InputInterface $input, OutputInterface $output)
116126
$this->validateInput($input);
117127
$object = $this->getContainerBuilder();
118128

119-
if ($input->getOption('types')) {
129+
if ($input->getOption('env-vars')) {
130+
$options = ['env-vars' => true];
131+
} elseif ($envVar = $input->getOption('env-var')) {
132+
$options = ['env-vars' => true, 'name' => $envVar];
133+
} elseif ($input->getOption('types')) {
120134
$options = [];
121135
$options['filter'] = [$this, 'filterToServiceTypes'];
122136
} elseif ($input->getOption('parameters')) {
@@ -156,7 +170,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
156170
throw $e;
157171
}
158172

159-
if (!$input->getArgument('name') && !$input->getOption('tag') && !$input->getOption('parameter') && $input->isInteractive()) {
173+
if (!$input->getArgument('name') && !$input->getOption('tag') && !$input->getOption('parameter') && !$input->getOption('env-vars') && !$input->getOption('env-var') && $input->isInteractive()) {
160174
if ($input->getOption('tags')) {
161175
$errorIo->comment('To search for a specific tag, re-run this command with a search term. (e.g. <comment>debug:container --tag=form.type</comment>)');
162176
} elseif ($input->getOption('parameters')) {
@@ -209,12 +223,15 @@ protected function getContainerBuilder()
209223
if (!$kernel->isDebug() || !(new ConfigCache($kernel->getContainer()->getParameter('debug.container.dump'), true))->isFresh()) {
210224
$buildContainer = \Closure::bind(function () { return $this->buildContainer(); }, $kernel, \get_class($kernel));
211225
$container = $buildContainer();
212-
$container->getCompilerPassConfig()->setRemovingPasses([]);
213-
$container->compile();
214226
} else {
215227
(new XmlFileLoader($container = new ContainerBuilder(), new FileLocator()))->load($kernel->getContainer()->getParameter('debug.container.dump'));
228+
$container->setParameter('container.build_hash', $hash = ContainerBuilder::hash(__METHOD__));
229+
$container->setParameter('container.build_id', hash('crc32', $hash.time()));
216230
}
217231

232+
$container->getCompilerPassConfig()->setRemovingPasses([]);
233+
$container->compile();
234+
218235
return $this->containerBuilder = $container;
219236
}
220237

‎src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php
+39Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ public function describe(OutputInterface $output, $object, array $options = [])
5252
case $object instanceof ParameterBag:
5353
$this->describeContainerParameters($object, $options);
5454
break;
55+
case $object instanceof ContainerBuilder && !empty($options['env-vars']):
56+
$this->describeContainerEnvVars($this->getContainerEnvVars($object), $options);
57+
break;
5558
case $object instanceof ContainerBuilder && isset($options['group_by']) && 'tags' === $options['group_by']:
5659
$this->describeContainerTags($object, $options);
5760
break;
@@ -157,6 +160,11 @@ abstract protected function describeContainerAlias(Alias $alias, array $options
157160
*/
158161
abstract protected function describeContainerParameter($parameter, array $options = []);
159162

163+
/**
164+
* Describes container environment variables.
165+
*/
166+
abstract protected function describeContainerEnvVars(array $envs, array $options = []);
167+
160168
/**
161169
* Describes event dispatcher listeners.
162170
*
@@ -311,4 +319,35 @@ public static function getClassDescription(string $class, string &$resolvedClass
311319

312320
return '';
313321
}
322+
323+
private function getContainerEnvVars(ContainerBuilder $container): array
324+
{
325+
$getEnvReflection = new \ReflectionMethod($container, 'getEnv');
326+
$getEnvReflection->setAccessible(true);
327+
$envs = [];
328+
foreach (array_keys($container->getEnvCounters()) as $env) {
329+
$processor = 'string';
330+
if (false !== $i = strrpos($name = $env, ':')) {
331+
$name = substr($env, $i + 1);
332+
$processor = substr($env, 0, $i);
333+
}
334+
$defaultValue = ($hasDefault = $container->hasParameter("env($name)")) ? $container->getParameter("env($name)") : null;
335+
if (false === ($runtimeValue = $_ENV[$name] ?? $_SERVER[$name] ?? getenv($name))) {
336+
$runtimeValue = null;
337+
}
338+
$processedValue = ($hasRuntime = null !== $runtimeValue) || $hasDefault ? $getEnvReflection->invoke($container, $env) : null;
339+
$envs[$name.$processor] = [
340+
'name' => $name,
341+
'processor' => $processor,
342+
'default_available' => $hasDefault,
343+
'default_value' => $defaultValue,
344+
'runtime_available' => $hasRuntime,
345+
'runtime_value' => $runtimeValue,
346+
'processed_value' => $processedValue,
347+
];
348+
}
349+
ksort($envs);
350+
351+
return array_values($envs);
352+
}
314353
}

‎src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Bundle\FrameworkBundle\Console\Descriptor;
1313

14+
use Symfony\Component\Console\Exception\LogicException;
1415
use Symfony\Component\DependencyInjection\Alias;
1516
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1617
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
@@ -177,6 +178,14 @@ protected function describeContainerParameter($parameter, array $options = [])
177178
$this->writeData([$key => $parameter], $options);
178179
}
179180

181+
/**
182+
* {@inheritdoc}
183+
*/
184+
protected function describeContainerEnvVars(array $envs, array $options = [])
185+
{
186+
throw new LogicException('Using the JSON format to debug environment variables is not supported.');
187+
}
188+
180189
/**
181190
* Writes data as json.
182191
*

‎src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Bundle\FrameworkBundle\Console\Descriptor;
1313

14+
use Symfony\Component\Console\Exception\LogicException;
1415
use Symfony\Component\DependencyInjection\Alias;
1516
use Symfony\Component\DependencyInjection\ContainerBuilder;
1617
use Symfony\Component\DependencyInjection\Definition;
@@ -273,6 +274,14 @@ protected function describeContainerParameter($parameter, array $options = [])
273274
$this->write(isset($options['parameter']) ? sprintf("%s\n%s\n\n%s", $options['parameter'], str_repeat('=', \strlen($options['parameter'])), $this->formatParameter($parameter)) : $parameter);
274275
}
275276

277+
/**
278+
* {@inheritdoc}
279+
*/
280+
protected function describeContainerEnvVars(array $envs, array $options = [])
281+
{
282+
throw new LogicException('Using the markdown format to debug environment variables is not supported.');
283+
}
284+
276285
/**
277286
* {@inheritdoc}
278287
*/

‎src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
+66Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Bundle\FrameworkBundle\Console\Descriptor;
1313

1414
use Symfony\Component\Console\Formatter\OutputFormatter;
15+
use Symfony\Component\Console\Helper\Dumper;
1516
use Symfony\Component\Console\Helper\Table;
1617
use Symfony\Component\Console\Style\SymfonyStyle;
1718
use Symfony\Component\DependencyInjection\Alias;
@@ -384,6 +385,71 @@ protected function describeContainerParameter($parameter, array $options = [])
384385
]);
385386
}
386387

388+
/**
389+
* {@inheritdoc}
390+
*/
391+
protected function describeContainerEnvVars(array $envs, array $options = [])
392+
{
393+
$dump = new Dumper($this->output);
394+
$options['output']->title('Symfony Container Environment Variables');
395+
396+
if (null !== $name = $options['name'] ?? null) {
397+
$options['output']->comment('Displaying detailed environment variable usage matching '.$name);
398+
399+
$matches = false;
400+
foreach ($envs as $env) {
401+
if ($name === $env['name'] || false !== stripos($env['name'], $name)) {
402+
$matches = true;
403+
$options['output']->section('%env('.$env['processor'].':'.$env['name'].')%');
404+
$options['output']->table([], [
405+
['<info>Default value</>', $env['default_available'] ? $dump($env['default_value']) : 'n/a'],
406+
['<info>Real value</>', $env['runtime_available'] ? $dump($env['runtime_value']) : 'n/a'],
407+
['<info>Processed value</>', $env['default_available'] || $env['runtime_available'] ? $dump($env['processed_value']) : 'n/a'],
408+
]);
409+
}
410+
}
411+
412+
if (!$matches) {
413+
$options['output']->block('None of the environment variables match this name.');
414+
} else {
415+
$options['output']->comment('Note real values might be different between web and CLI.');
416+
}
417+
418+
return;
419+
}
420+
421+
if (!$envs) {
422+
$options['output']->block('No environment variables are being used.');
423+
424+
return;
425+
}
426+
427+
$rows = [];
428+
$missing = [];
429+
foreach ($envs as $env) {
430+
if (isset($rows[$env['name']])) {
431+
continue;
432+
}
433+
434+
$rows[$env['name']] = [
435+
$env['name'],
436+
$env['default_available'] ? $dump($env['default_value']) : 'n/a',
437+
$env['runtime_available'] ? $dump($env['runtime_value']) : 'n/a',
438+
];
439+
if (!$env['default_available'] && !$env['runtime_available']) {
440+
$missing[$env['name']] = true;
441+
}
442+
}
443+
444+
$options['output']->table(['Name', 'Default value', 'Real value'], $rows);
445+
$options['output']->comment('Note real values might be different between web and CLI.');
446+
447+
if ($missing) {
448+
$options['output']->warning('The following variables are missing:');
449+
$options['output']->listing(array_keys($missing));
450+
}
451+
}
452+
387453
/**
388454
* {@inheritdoc}
389455
*/

‎src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Bundle\FrameworkBundle\Console\Descriptor;
1313

14+
use Symfony\Component\Console\Exception\LogicException;
1415
use Symfony\Component\DependencyInjection\Alias;
1516
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
1617
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
@@ -131,6 +132,14 @@ protected function describeContainerParameter($parameter, array $options = [])
131132
$this->writeDocument($this->getContainerParameterDocument($parameter, $options));
132133
}
133134

135+
/**
136+
* {@inheritdoc}
137+
*/
138+
protected function describeContainerEnvVars(array $envs, array $options = [])
139+
{
140+
throw new LogicException('Using the XML format to debug environment variables is not supported.');
141+
}
142+
134143
/**
135144
* Writes DOM document.
136145
*

‎src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php
+69Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,75 @@ public function testIgnoreBackslashWhenFindingService(string $validServiceId)
8080
$this->assertNotContains('No services found', $tester->getDisplay());
8181
}
8282

83+
public function testDescribeEnvVars()
84+
{
85+
putenv('REAL=value');
86+
static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml']);
87+
88+
$application = new Application(static::$kernel);
89+
$application->setAutoExit(false);
90+
91+
$tester = new ApplicationTester($application);
92+
$tester->run(['command' => 'debug:container', '--env-vars' => true], ['decorated' => false]);
93+
94+
$this->assertStringMatchesFormat(<<<'TXT'
95+
96+
Symfony Container Environment Variables
97+
=======================================
98+
99+
--------- ----------------- ------------
100+
Name Default value Real value
101+
--------- ----------------- ------------
102+
JSON "[1, "2.5", 3]" n/a
103+
REAL n/a "value"
104+
UNKNOWN n/a n/a
105+
--------- ----------------- ------------
106+
107+
// Note real values might be different between web and CLI.%w
108+
109+
[WARNING] The following variables are missing:%w
110+
111+
* UNKNOWN
112+
113+
TXT
114+
, $tester->getDisplay(true));
115+
116+
putenv('REAL');
117+
}
118+
119+
public function testDescribeEnvVar()
120+
{
121+
static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml']);
122+
123+
$application = new Application(static::$kernel);
124+
$application->setAutoExit(false);
125+
126+
$tester = new ApplicationTester($application);
127+
$tester->run(['command' => 'debug:container', '--env-var' => 'js'], ['decorated' => false]);
128+
129+
$this->assertContains(<<<'TXT'
130+
%env(float:key:2:json:JSON)%
131+
----------------------------
132+
133+
----------------- -----------------
134+
Default value "[1, "2.5", 3]"
135+
Real value n/a
136+
Processed value 3.0
137+
----------------- -----------------
138+
139+
%env(int:key:2:json:JSON)%
140+
--------------------------
141+
142+
----------------- -----------------
143+
Default value "[1, "2.5", 3]"
144+
Real value n/a
145+
Processed value 3
146+
----------------- -----------------
147+
148+
TXT
149+
, $tester->getDisplay(true));
150+
}
151+
83152
public function provideIgnoreBackslashWhenFindingService()
84153
{
85154
return [

‎src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ContainerDebug/config.yml

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ContainerDebug/config.yml
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
imports:
22
- { resource: ../config/default.yml }
33

4+
parameters:
5+
env(JSON): '[1, "2.5", 3]'
6+
47
services:
58
_defaults: { public: true }
69
public:
@@ -10,3 +13,10 @@ services:
1013
public: false
1114
Symfony\Bundle\FrameworkBundle\Tests\Fixtures\BackslashClass:
1215
class: Symfony\Bundle\FrameworkBundle\Tests\Fixtures\BackslashClass
16+
env:
17+
class: stdClass
18+
arguments:
19+
- '%env(UNKNOWN)%'
20+
- '%env(REAL)%'
21+
- '%env(int:key:2:json:JSON)%'
22+
- '%env(float:key:2:json:JSON)%'

‎src/Symfony/Bundle/FrameworkBundle/composer.json

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/composer.json
+3-3Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"fig/link-util": "^1.0",
3535
"symfony/asset": "~3.4|~4.0",
3636
"symfony/browser-kit": "^4.3",
37-
"symfony/console": "~3.4|~4.0",
37+
"symfony/console": "^4.3",
3838
"symfony/css-selector": "~3.4|~4.0",
3939
"symfony/dom-crawler": "~3.4|~4.0",
4040
"symfony/polyfill-intl-icu": "~1.0",
@@ -53,7 +53,7 @@
5353
"symfony/templating": "~3.4|~4.0",
5454
"symfony/twig-bundle": "~2.8|~3.2|~4.0",
5555
"symfony/validator": "^4.1",
56-
"symfony/var-dumper": "~3.4|~4.0",
56+
"symfony/var-dumper": "^4.3",
5757
"symfony/workflow": "^4.3",
5858
"symfony/yaml": "~3.4|~4.0",
5959
"symfony/property-info": "~3.4|~4.0",
@@ -69,7 +69,7 @@
6969
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0",
7070
"symfony/asset": "<3.4",
7171
"symfony/browser-kit": "<4.3",
72-
"symfony/console": "<3.4",
72+
"symfony/console": "<4.3",
7373
"symfony/dotenv": "<4.2",
7474
"symfony/form": "<4.3",
7575
"symfony/messenger": "<4.3",

0 commit comments

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