Skip to content

Commit 69c922b

Browse files
committed
[Command] Improve --show-arguments for command debug:container
1 parent 9b0ca99 commit 69c922b

13 files changed

+565
-65
lines changed

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

Lines changed: 83 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\Console\Helper\Dumper;
1616
use Symfony\Component\Console\Helper\Table;
1717
use Symfony\Component\Console\Helper\TableCell;
18+
use Symfony\Component\Console\Helper\TableSeparator;
1819
use Symfony\Component\Console\Style\SymfonyStyle;
1920
use Symfony\Component\DependencyInjection\Alias;
2021
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
@@ -351,45 +352,104 @@ protected function describeContainerDefinition(Definition $definition, array $op
351352
}
352353
}
353354

355+
$inEdges = null !== $container && isset($options['id']) ? $this->getServiceEdges($container, $options['id']) : [];
356+
$tableRows[] = ['Usages', $inEdges ? implode(\PHP_EOL, $inEdges) : 'none'];
357+
358+
$options['output']->table($tableHeaders, $tableRows);
359+
354360
$showArguments = isset($options['show_arguments']) && $options['show_arguments'];
355-
$argumentsInformation = [];
361+
356362
if ($showArguments && ($arguments = $definition->getArguments())) {
357-
foreach ($arguments as $argument) {
358-
if ($argument instanceof ServiceClosureArgument) {
359-
$argument = $argument->getValues()[0];
360-
}
363+
$table = new Table($this->getOutput());
364+
$table->setHeaderTitle('Arguments');
365+
$table->setHeaders(['#', 'Service', 'Argument(s)']);
366+
367+
foreach ($arguments as $position => $argument) {
361368
if ($argument instanceof Reference) {
362-
$argumentsInformation[] = \sprintf('Service(%s)', (string) $argument);
369+
if (null === $container
370+
|| !($argumentDefinition = $container->getDefinition($argument))->hasTag('container.service_locator')
371+
) {
372+
$table->addRow([++$position, \sprintf('Service(%s)', $argument), '-']);
373+
} else {
374+
$argumentCollection = $argumentDefinition->getArguments()[0];
375+
$description = \sprintf('Service locator (%d element(s))', \count($argumentCollection));
376+
377+
foreach ($argumentCollection as $key => $argumentUnit) {
378+
$argumentValue = $argumentUnit->getValues()[0];
379+
$argumentDescription = !($argumentValue instanceof Reference) ? json_encode($argumentValue) : $argumentValue;
380+
381+
if (array_key_first($argumentCollection) === $key) {
382+
$table->addRow([++$position, $description, $argumentDescription]);
383+
} else {
384+
$table->addRow(['', '', $argumentDescription]);
385+
}
386+
}
387+
}
363388
} elseif ($argument instanceof IteratorArgument) {
389+
$argumentValues = $argument->getValues();
390+
364391
if ($argument instanceof TaggedIteratorArgument) {
365-
$argumentsInformation[] = \sprintf('Tagged Iterator for "%s"%s', $argument->getTag(), $options['is_debug'] ? '' : \sprintf(' (%d element(s))', \count($argument->getValues())));
392+
if (null === $container) {
393+
$description = \sprintf('Tagged Iterator for "%s"', $argument->getTag());
394+
395+
$table->addRow([++$position, $description, '-']);
396+
} else {
397+
$services = array_keys($container->findTaggedServiceIds($argument->getTag()));
398+
$description = \sprintf('Tagged Iterator for "%s"%s', $argument->getTag(), $options['is_debug'] ? '' : \sprintf(' (%d element(s))', \count($services)));
399+
400+
foreach ($services as $order => $ref) {
401+
if (array_key_first($services) === $order) {
402+
$table->addRow([++$position, $description, $ref]);
403+
} else {
404+
$table->addRow(['', '', $ref]);
405+
}
406+
}
407+
}
366408
} else {
367-
$argumentsInformation[] = \sprintf('Iterator (%d element(s))', \count($argument->getValues()));
409+
$description = \sprintf('Iterator (%d element(s))', \count($argumentValues));
410+
$table->addRow([++$position, $description, '-']);
368411
}
412+
} elseif ($argument instanceof ServiceLocatorArgument) {
413+
if (null === $container) {
414+
$description = 'Service locator';
415+
416+
if (null === $argument->getTaggedIteratorArgument()) {
417+
$description = \sprintf('Service locator (%d element(s))', \count($argument->getValues()));
418+
}
369419

370-
foreach ($argument->getValues() as $ref) {
371-
$argumentsInformation[] = \sprintf('- Service(%s)', $ref);
420+
$table->addRow([++$position, $description, '-']);
421+
} else {
422+
$services = null !== $argument->getTaggedIteratorArgument() ? array_keys($container->findTaggedServiceIds($argument->getTaggedIteratorArgument()->getTag())) : $argument->getValues();
423+
$description = \sprintf('Service locator (%d element(s))', \count($services));
424+
425+
foreach ($services as $order => $ref) {
426+
if (array_key_first($services) === $order) {
427+
$table->addRow([++$position, $description, $ref]);
428+
} else {
429+
$table->addRow(['', '', $ref]);
430+
}
431+
}
372432
}
373-
} elseif ($argument instanceof ServiceLocatorArgument) {
374-
$argumentsInformation[] = \sprintf('Service locator (%d element(s))', \count($argument->getValues()));
375433
} elseif ($argument instanceof Definition) {
376-
$argumentsInformation[] = 'Inlined Service';
434+
$table->addRow([++$position, 'Inlined Service', '-']);
377435
} elseif ($argument instanceof \UnitEnum) {
378-
$argumentsInformation[] = ltrim(var_export($argument, true), '\\');
436+
$table->addRow([++$position, ltrim(var_export($argument, true), '\\'), '-']);
379437
} elseif ($argument instanceof AbstractArgument) {
380-
$argumentsInformation[] = \sprintf('Abstract argument (%s)', $argument->getText());
438+
$table->addRow([++$position, \sprintf('Abstract argument (%s)', $argument->getText()), '-']);
439+
} elseif ($argument instanceof ServiceClosureArgument) {
440+
$table->addRow([++$position, \sprintf('Closure argument (%s)', $argument->getValues()[0]), '-']);
441+
} elseif (\is_array($argument)) {
442+
$table->addRow([++$position, \sprintf('Array (%d element(s))', \count($argument)), '-']);
381443
} else {
382-
$argumentsInformation[] = \is_array($argument) ? \sprintf('Array (%d element(s))', \count($argument)) : $argument;
444+
$table->addRow([++$position, $argument, '-']);
383445
}
384-
}
385446

386-
$tableRows[] = ['Arguments', implode("\n", $argumentsInformation)];
447+
if (--$position !== array_key_last($arguments)) {
448+
$table->addRow(new TableSeparator());
449+
}
450+
}
451+
$table->render();
387452
}
388-
389-
$inEdges = null !== $container && isset($options['id']) ? $this->getServiceEdges($container, $options['id']) : [];
390-
$tableRows[] = ['Usages', $inEdges ? implode(\PHP_EOL, $inEdges) : 'none'];
391-
392-
$options['output']->table($tableHeaders, $tableRows);
393453
}
394454

395455
protected function describeContainerDeprecations(ContainerBuilder $container, array $options = []): void

src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTestCase.php

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ abstract protected static function getDescriptor();
268268

269269
abstract protected static function getFormat();
270270

271-
private function assertDescription($expectedDescription, $describedObject, array $options = [])
271+
private function assertDescription($expectedDescription, $describedObject, array $options = []): void
272272
{
273273
$options['is_debug'] = false;
274274
$options['raw_output'] = true;
@@ -361,4 +361,31 @@ public static function getDescribeContainerBuilderWithPriorityTagsTestData(): ar
361361

362362
return $data;
363363
}
364+
365+
/** @dataProvider getDescribeContainerBuilderWithLocatorAndIteratorTestData */
366+
public function testDescribeContainerBuilderWithLocatorAndIterator($object, $expectedDescription, array $options)
367+
{
368+
$this->assertDescription($expectedDescription, $object, $options);
369+
}
370+
371+
public static function getDescribeContainerBuilderWithLocatorAndIteratorTestData(): \Generator
372+
{
373+
$file = \sprintf('%s.%s', trim('definition_arguments_with_locator_in_container', '.'), static::getFormat());
374+
$description = file_get_contents(__DIR__.'/../../Fixtures/Descriptor/'.$file);
375+
376+
yield 'Show arguments option used through a container ('.$file.')' => [
377+
'object' => ObjectsProvider::getContainerServicesWithLocatorArguments(),
378+
'expectedDescription' => $description,
379+
'options' => ['show_arguments' => true, 'id' => 'definition_1'],
380+
];
381+
382+
$file = \sprintf('%s.%s', trim('definition_arguments_with_locator_without_container', '.'), static::getFormat());
383+
$description = file_get_contents(__DIR__.'/../../Fixtures/Descriptor/'.$file);
384+
385+
yield 'Show arguments option used outside of a container ('.$file.')' => [
386+
'object' => ObjectsProvider::getDefinitionWithLocatorArguments(),
387+
'expectedDescription' => $description,
388+
'options' => ['show_arguments' => true],
389+
];
390+
}
364391
}

src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
use Symfony\Component\DependencyInjection\Alias;
1717
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
1818
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
19+
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
20+
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
21+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
22+
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
1923
use Symfony\Component\DependencyInjection\ContainerBuilder;
2024
use Symfony\Component\DependencyInjection\Definition;
2125
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
@@ -242,6 +246,87 @@ public static function getContainerDefinitionsWithPriorityTags()
242246
];
243247
}
244248

249+
public static function getContainerServicesWithLocatorArguments()
250+
{
251+
$container = new ContainerBuilder(new ParameterBag([
252+
'kernel.debug' => true,
253+
'kernel.project_dir' => __DIR__,
254+
'kernel.container_class' => 'testContainer',
255+
]));
256+
$service0 = new Definition('Full\\Qualified\\Class1');
257+
$service1 = new Definition('Full\\Qualified\\Class2');
258+
$service2 = new Definition('Full\\Qualified\\Class3');
259+
$service3 = new Definition('Full\\Qualified\\Class4');
260+
$container->addDefinitions([
261+
'definition_1' => $service0
262+
->addArgument(new Reference('definition_2'))
263+
->addArgument(new ServiceLocatorArgument(
264+
new TaggedIteratorArgument('app_tag'),
265+
))
266+
->addArgument(new TaggedIteratorArgument('app_tag'))
267+
->addArgument(new ServiceLocatorArgument([
268+
'Full\\Qualified\\Class2' => new Reference('definition_2'),
269+
'Full\\Qualified\\Class3' => new Reference('definition_3'),
270+
'Full\\Qualified\\Class4' => new Reference('definition_4'),
271+
'mainEmail' => 'contact@email.com',
272+
]))
273+
->addArgument(ServiceLocatorTagPass::register($container, [
274+
new Reference('definition_2'),
275+
new Reference('definition_3'),
276+
new Reference('definition_4'),
277+
'mainEmail' => 'contact@email.com',
278+
]))
279+
->addArgument(ServiceLocatorTagPass::register($container, [
280+
1,
281+
true,
282+
'contact@email.com',
283+
new ServiceClosureArgument(new Reference('mailer')),
284+
]))
285+
->addArgument(new AbstractArgument('to complete'))
286+
->addArgument([
287+
new Reference('definition_2'),
288+
new Reference('definition_3'),
289+
new Reference('definition_4'),
290+
])
291+
->addArgument(FooUnitEnum::BAR)
292+
->addArgument(new IteratorArgument([
293+
new Reference('definition_2'),
294+
new Reference('definition_3'),
295+
new Reference('definition_4'),
296+
]))
297+
->addArgument(new ServiceClosureArgument(new Reference('mailer'))),
298+
'definition_2' => $service1
299+
->addTag('app_tag'),
300+
'definition_3' => $service2
301+
->addTag('app_tag'),
302+
'definition_4' => $service3
303+
->addTag('app_tag'),
304+
]);
305+
306+
return $container;
307+
}
308+
309+
public static function getDefinitionWithLocatorArguments()
310+
{
311+
$definition0 = new Definition('Full\\Qualified\\Class1');
312+
313+
return $definition0
314+
->addArgument(new ServiceLocatorArgument(
315+
new TaggedIteratorArgument('app_tag'),
316+
))
317+
->addArgument(new TaggedIteratorArgument('app_tag'))
318+
->addArgument(new ServiceLocatorArgument([
319+
'Full\\Qualified\\Class2' => new Reference('definition_2'),
320+
'Full\\Qualified\\Class3' => new Reference('definition_3'),
321+
'Full\\Qualified\\Class4' => new Reference('definition_4'),
322+
]))
323+
->addArgument(new IteratorArgument([
324+
new Definition('definition_2'),
325+
new Definition('definition_3'),
326+
new Definition('definition_4'),
327+
]));
328+
}
329+
245330
public static function getContainerAliases()
246331
{
247332
return [
Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,33 @@
1-
---------------- ---------------------------------
2-
 Option   Value 
3-
---------------- ---------------------------------
4-
Service ID -
5-
Class Full\Qualified\Class1
6-
Tags -
7-
Public yes
8-
Synthetic no
9-
Lazy yes
10-
Shared yes
11-
Abstract yes
12-
Autowired no
13-
Autoconfigured no
14-
Factory Class Full\Qualified\FactoryClass
15-
Factory Method get
16-
Arguments Service(.definition_2)
17-
%parameter%
18-
Inlined Service
19-
Array (3 element(s))
20-
Iterator (2 element(s))
21-
- Service(definition_1)
22-
- Service(.definition_2)
23-
Abstract argument (placeholder)
24-
Usages none
25-
---------------- ---------------------------------
1+
---------------- -----------------------------
2+
 Option   Value 
3+
---------------- -----------------------------
4+
Service ID -
5+
Class Full\Qualified\Class1
6+
Tags -
7+
Public yes
8+
Synthetic no
9+
Lazy yes
10+
Shared yes
11+
Abstract yes
12+
Autowired no
13+
Autoconfigured no
14+
Factory Class Full\Qualified\FactoryClass
15+
Factory Method get
16+
Usages none
17+
---------------- -----------------------------
2618

19+
+---+---------------- Arguments ------+-------------+
20+
| # | Service | Argument(s) |
21+
+---+---------------------------------+-------------+
22+
| 1 | Service(.definition_2) | - |
23+
+---+---------------------------------+-------------+
24+
| 2 | %parameter% | - |
25+
+---+---------------------------------+-------------+
26+
| 3 | Inlined Service | - |
27+
+---+---------------------------------+-------------+
28+
| 4 | Array (3 element(s)) | - |
29+
+---+---------------------------------+-------------+
30+
| 5 | Iterator (2 element(s)) | - |
31+
+---+---------------------------------+-------------+
32+
| 6 | Abstract argument (placeholder) | - |
33+
+---+---------------------------------+-------------+
Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
1-
---------------- ----------------------------------------------------------------
2-
 Option   Value 
3-
---------------- ----------------------------------------------------------------
4-
Service ID -
5-
Class definition_with_enum
6-
Tags -
7-
Public no
8-
Synthetic no
9-
Lazy no
10-
Shared yes
11-
Abstract no
12-
Autowired no
13-
Autoconfigured no
14-
Arguments Symfony\Bundle\FrameworkBundle\Tests\Fixtures\FooUnitEnum::FOO
15-
Usages none
16-
---------------- ----------------------------------------------------------------
1+
---------------- ----------------------
2+
 Option   Value 
3+
---------------- ----------------------
4+
Service ID -
5+
Class definition_with_enum
6+
Tags -
7+
Public no
8+
Synthetic no
9+
Lazy no
10+
Shared yes
11+
Abstract no
12+
Autowired no
13+
Autoconfigured no
14+
Usages none
15+
---------------- ----------------------
1716

17+
+---+------------------------------- Arguments ----------------------+-------------+
18+
| # | Service | Argument(s) |
19+
+---+----------------------------------------------------------------+-------------+
20+
| 1 | Symfony\Bundle\FrameworkBundle\Tests\Fixtures\FooUnitEnum::FOO | - |
21+
+---+----------------------------------------------------------------+-------------+

0 commit comments

Comments
 (0)