Skip to content

Commit f68b1d3

Browse files
committed
Add JSON format option for orm:mapping:describe command output
1 parent a1fdc6e commit f68b1d3

File tree

2 files changed

+119
-2
lines changed

2 files changed

+119
-2
lines changed

src/Tools/Console/Command/MappingDescribeCommand.php

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Doctrine\ORM\Mapping\FieldMapping;
1111
use Doctrine\Persistence\Mapping\MappingException;
1212
use InvalidArgumentException;
13+
use JsonException;
1314
use Symfony\Component\Console\Completion\CompletionInput;
1415
use Symfony\Component\Console\Completion\CompletionSuggestions;
1516
use Symfony\Component\Console\Input\InputArgument;
@@ -55,6 +56,7 @@ protected function configure(): void
5556
->addArgument('entityName', InputArgument::REQUIRED, 'Full or partial name of entity')
5657
->setDescription('Display information about mapped objects')
5758
->addOption('em', null, InputOption::VALUE_REQUIRED, 'Name of the entity manager to operate on')
59+
->addOption('format', null, InputOption::VALUE_REQUIRED, 'Output format (json, text)', 'text')
5860
->setHelp(<<<'EOT'
5961
The %command.full_name% command describes the metadata for the given full or partial entity class name.
6062
@@ -63,6 +65,15 @@ protected function configure(): void
6365
Or:
6466
6567
<info>%command.full_name%</info> MyEntity
68+
69+
To output the metadata in JSON format, use the <info>--format</info> option:
70+
71+
<info>%command.full_name% My\Namespace\Entity\MyEntity --format=json</info>
72+
73+
To use a specific entity manager (e.g., for multi-DB projects), use the <info>--em</info> option:
74+
75+
<info>%command.full_name% My\Namespace\Entity\MyEntity --em=my_custom_entity_manager</info>
76+
6677
EOT);
6778
}
6879

@@ -72,7 +83,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
7283

7384
$entityManager = $this->getEntityManager($input);
7485

75-
$this->displayEntity($input->getArgument('entityName'), $entityManager, $ui);
86+
$this->displayEntity($input->getArgument('entityName'), $entityManager, $ui, $input->getOption('format'));
7687

7788
return 0;
7889
}
@@ -89,6 +100,10 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti
89100

90101
$suggestions->suggestValues(array_values($entities));
91102
}
103+
104+
if ($input->mustSuggestOptionValuesFor('format')) {
105+
$suggestions->suggestValues(array_values($this->getAvailableFormatOptions()));
106+
}
92107
}
93108

94109
/**
@@ -100,9 +115,47 @@ private function displayEntity(
100115
string $entityName,
101116
EntityManagerInterface $entityManager,
102117
SymfonyStyle $ui,
118+
string|null $format,
103119
): void {
104120
$metadata = $this->getClassMetadata($entityName, $entityManager);
105121

122+
if ($format === 'json') {
123+
$ui->text(json_encode(
124+
[
125+
'name' => $metadata->name,
126+
'rootEntityName' => $metadata->rootEntityName,
127+
'customGeneratorDefinition' => $this->formatValueToJson($metadata->customGeneratorDefinition),
128+
'customRepositoryClassName' => $metadata->customRepositoryClassName,
129+
'isMappedSuperclass' => $metadata->isMappedSuperclass,
130+
'isEmbeddedClass' => $metadata->isEmbeddedClass,
131+
'parentClasses' => $metadata->parentClasses,
132+
'subClasses' => $metadata->subClasses,
133+
'embeddedClasses' => $metadata->embeddedClasses,
134+
'identifier' => $metadata->identifier,
135+
'inheritanceType' => $metadata->inheritanceType,
136+
'discriminatorColumn' => $this->formatValueToJson($metadata->discriminatorColumn),
137+
'discriminatorValue' => $metadata->discriminatorValue,
138+
'discriminatorMap' => $metadata->discriminatorMap,
139+
'generatorType' => $metadata->generatorType,
140+
'table' => $this->formatValueToJson($metadata->table),
141+
'isIdentifierComposite' => $metadata->isIdentifierComposite,
142+
'containsForeignIdentifier' => $metadata->containsForeignIdentifier,
143+
'containsEnumIdentifier' => $metadata->containsEnumIdentifier,
144+
'sequenceGeneratorDefinition' => $this->formatValueToJson($metadata->sequenceGeneratorDefinition),
145+
'changeTrackingPolicy' => $metadata->changeTrackingPolicy,
146+
'isVersioned' => $metadata->isVersioned,
147+
'versionField' => $metadata->versionField,
148+
'isReadOnly' => $metadata->isReadOnly,
149+
'entityListeners' => $metadata->entityListeners,
150+
'associationMappings' => $this->formatMappingsToJson($metadata->associationMappings),
151+
'fieldMappings' => $this->formatMappingsToJson($metadata->fieldMappings),
152+
],
153+
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR,
154+
));
155+
156+
return;
157+
}
158+
106159
$ui->table(
107160
['Field', 'Value'],
108161
array_merge(
@@ -115,7 +168,7 @@ private function displayEntity(
115168
$this->formatField('Embedded class?', $metadata->isEmbeddedClass),
116169
$this->formatField('Parent classes', $metadata->parentClasses),
117170
$this->formatField('Sub classes', $metadata->subClasses),
118-
$this->formatField('Embedded classes', $metadata->subClasses),
171+
$this->formatField('Embedded classes', $metadata->embeddedClasses),
119172
$this->formatField('Identifier', $metadata->identifier),
120173
$this->formatField('Inheritance type', $metadata->inheritanceType),
121174
$this->formatField('Discriminator column', $metadata->discriminatorColumn),
@@ -240,6 +293,22 @@ private function formatValue(mixed $value): string
240293
throw new InvalidArgumentException(sprintf('Do not know how to format value "%s"', print_r($value, true)));
241294
}
242295

296+
/** @throws JsonException */
297+
private function formatValueToJson(mixed $value): mixed
298+
{
299+
if (is_object($value)) {
300+
$value = (array) $value;
301+
}
302+
303+
if (is_array($value)) {
304+
foreach ($value as $k => $v) {
305+
$value[$k] = $this->formatValueToJson($v);
306+
}
307+
}
308+
309+
return $value;
310+
}
311+
243312
/**
244313
* Add the given label and value to the two column table output
245314
*
@@ -281,6 +350,22 @@ private function formatMappings(array $propertyMappings): array
281350
return $output;
282351
}
283352

353+
/**
354+
* @param array<string, FieldMapping|AssociationMapping> $propertyMappings
355+
*
356+
* @return array<string, mixed>
357+
*/
358+
private function formatMappingsToJson(array $propertyMappings): array
359+
{
360+
$output = [];
361+
362+
foreach ($propertyMappings as $propertyName => $mapping) {
363+
$output[$propertyName] = $this->formatValueToJson((array) $mapping);
364+
}
365+
366+
return $output;
367+
}
368+
284369
/**
285370
* Format the entity listeners
286371
*
@@ -293,4 +378,10 @@ private function formatEntityListeners(array $entityListeners): array
293378
{
294379
return $this->formatField('Entity listeners', array_map('get_class', $entityListeners));
295380
}
381+
382+
/** @return string[] */
383+
private function getAvailableFormatOptions(): array
384+
{
385+
return ['text', 'json'];
386+
}
296387
}

tests/Tests/ORM/Tools/Console/Command/MappingDescribeCommandTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
use Symfony\Component\Console\Tester\CommandCompletionTester;
1717
use Symfony\Component\Console\Tester\CommandTester;
1818

19+
use function json_decode;
20+
1921
/**
2022
* Tests for {@see \Doctrine\ORM\Tools\Console\Command\MappingDescribeCommand}
2123
*/
@@ -56,6 +58,25 @@ public function testShowSpecificFuzzySingle(): void
5658
self::assertStringContainsString('Root entity name', $display);
5759
}
5860

61+
public function testShowSpecificFuzzySingleJson(): void
62+
{
63+
$this->tester->execute([
64+
'command' => $this->command->getName(),
65+
'entityName' => 'AttractionInfo',
66+
'--format' => 'json',
67+
]);
68+
69+
$display = $this->tester->getDisplay();
70+
$decodedJson = json_decode($display, true);
71+
72+
self::assertJson($display);
73+
self::assertSame(AttractionInfo::class, $decodedJson['name']);
74+
self::assertArrayHasKey('rootEntityName', $decodedJson);
75+
self::assertArrayHasKey('fieldMappings', $decodedJson);
76+
self::assertArrayHasKey('associationMappings', $decodedJson);
77+
self::assertArrayHasKey('id', $decodedJson['fieldMappings']);
78+
}
79+
5980
public function testShowSpecificFuzzyAmbiguous(): void
6081
{
6182
$this->expectException(InvalidArgumentException::class);
@@ -111,5 +132,10 @@ public static function provideCompletionSuggestions(): iterable
111132
'Doctrine\\\\Tests\\\\Models\\\\Cache\\\\Bar',
112133
],
113134
];
135+
136+
yield 'format option value' => [
137+
['--format='],
138+
['text', 'json'],
139+
];
114140
}
115141
}

0 commit comments

Comments
 (0)