Skip to content

Commit 669b975

Browse files
authored
fix: manage correctly non defined type in configuration (#355)
1 parent 93b4900 commit 669b975

10 files changed

+273
-26
lines changed

src/AttributeGenerator/DoctrineMongoDBAttributeGenerator.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ final class DoctrineMongoDBAttributeGenerator extends AbstractAttributeGenerator
3131
*/
3232
public function generateClassAttributes(Class_ $class): array
3333
{
34-
if ($doctrineAttributes = $this->config['types'][$class->name()]['doctrine']['attributes']) {
34+
if ($doctrineAttributes = isset($this->config['types'][$class->name()]) ? $this->config['types'][$class->name()]['doctrine']['attributes'] : false) {
3535
$attributes = [];
3636
foreach ($doctrineAttributes as $attributeName => $attributeArgs) {
3737
$attributes[] = new Attribute($attributeName, $attributeArgs);
@@ -46,7 +46,7 @@ public function generateClassAttributes(Class_ $class): array
4646

4747
$attributes = [];
4848
if ($class->isAbstract) {
49-
if ($inheritanceAttributes = ($this->config['doctrine']['inheritanceAttributes'])) {
49+
if ($inheritanceAttributes = $this->config['doctrine']['inheritanceAttributes']) {
5050
$attributes = [];
5151
foreach ($inheritanceAttributes as $attributeName => $attributeArgs) {
5252
$attributes[] = new Attribute($attributeName, $attributeArgs);

src/AttributeGenerator/DoctrineOrmAttributeGenerator.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ final class DoctrineOrmAttributeGenerator extends AbstractAttributeGenerator
4242
*/
4343
public function generateClassAttributes(Class_ $class): array
4444
{
45-
if ($doctrineAttributes = $this->config['types'][$class->name()]['doctrine']['attributes']) {
45+
if ($doctrineAttributes = (isset($this->config['types'][$class->name()]) ? $this->config['types'][$class->name()]['doctrine']['attributes'] : false)) {
4646
$attributes = [];
4747
foreach ($doctrineAttributes as $attributeName => $attributeArgs) {
4848
$attributes[] = new Attribute($attributeName, $attributeArgs);
@@ -288,14 +288,14 @@ private function getRelationName(string $rangeName): ?string
288288

289289
if (null !== $class->interfaceName()) {
290290
if (isset($this->config['types'][$rangeName]['namespaces']['interface'])) {
291-
return sprintf('%s\\%s', $this->config['types'][$class->name()]['namespaces']['interface'], $class->interfaceName());
291+
return sprintf('%s\\%s', $this->config['types'][$rangeName]['namespaces']['interface'], $class->interfaceName());
292292
}
293293

294294
return sprintf('%s\\%s', $this->config['namespaces']['interface'], $class->interfaceName());
295295
}
296296

297297
if (isset($this->config['types'][$rangeName]['namespaces']['class'])) {
298-
return sprintf('%s\\%s', $this->config['types'][$class->name()]['namespaces']['class'], $class->name());
298+
return sprintf('%s\\%s', $this->config['types'][$rangeName]['namespaces']['class'], $class->name());
299299
}
300300

301301
return sprintf('%s\\%s', $this->config['namespaces']['entity'], $rangeName);

src/ClassMutator/ClassParentMutator.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ public function __construct(array $config, PhpTypeConverterInterface $phpTypeCon
3737

3838
public function __invoke(Class_ $class): Class_
3939
{
40-
$typeConfig = $this->config['types'][$class->name()];
41-
$class->withParent($typeConfig['parent']);
40+
$typeConfig = $this->config['types'][$class->name()] ?? null;
41+
$class->withParent($typeConfig['parent'] ?? null);
4242

4343
if (null === $class->parent() && $subclassOf = $class->getSubClassOf()) {
4444
if (\count($subclassOf) > 1) {
@@ -51,7 +51,7 @@ public function __invoke(Class_ $class): Class_
5151
if ($class->hasParent() && isset($this->config['types'][$class->parent()]['namespaces']['class'])) {
5252
$parentNamespace = $this->config['types'][$class->parent()]['namespaces']['class'];
5353

54-
if ($class->isInNamespace($parentNamespace)) {
54+
if (!$class->isInNamespace($parentNamespace)) {
5555
$class->addUse(new Use_($parentNamespace.'\\'.$class->parent()));
5656
}
5757
}

src/ClassMutator/ClassPropertiesAppender.php

+13-10
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ public function __construct(PropertyGenerator $propertyGenerator, LoggerInterfac
5353

5454
public function __invoke(Class_ $class): Class_
5555
{
56-
$typeConfig = $this->config['types'][$class->name()];
56+
$typeConfig = $this->config['types'][$class->name()] ?? null;
5757

58-
if (!$typeConfig['allProperties']) {
58+
if (null !== $typeConfig && !$typeConfig['allProperties']) {
5959
foreach ($typeConfig['properties'] as $key => $value) {
6060
if ($value['exclude']) {
6161
continue;
@@ -75,9 +75,12 @@ public function __invoke(Class_ $class): Class_
7575
$class = $this->generateCustomField($key, $class->resource(), $typeConfig, $class, $this->config);
7676
}
7777
} else {
78-
$remainingProperties = $typeConfig['properties'];
78+
$remainingProperties = $typeConfig['properties'] ?? [];
79+
if (!isset($this->propertiesMap[$class->resourceUri()])) {
80+
$this->logger->warning(sprintf('Properties for "%s" not found in the map.', $class->resourceUri()));
81+
}
7982
// All properties
80-
foreach ($this->propertiesMap[$class->resourceUri()] as $property) {
83+
foreach ($this->propertiesMap[$class->resourceUri()] ?? [] as $property) {
8184
unset($remainingProperties[$property->localName()]);
8285
if ($property->hasProperty(self::SCHEMA_ORG_SUPERSEDED_BY)) {
8386
$supersededBy = $property->get(self::SCHEMA_ORG_SUPERSEDED_BY);
@@ -101,10 +104,10 @@ public function __invoke(Class_ $class): Class_
101104
/**
102105
* Add custom fields (not defined in the vocabulary).
103106
*
104-
* @param TypeConfiguration $typeConfig
105-
* @param Configuration $config
107+
* @param ?TypeConfiguration $typeConfig
108+
* @param Configuration $config
106109
*/
107-
private function generateCustomField(string $propertyName, RdfResource $type, array $typeConfig, Class_ $class, array $config): Class_
110+
private function generateCustomField(string $propertyName, RdfResource $type, ?array $typeConfig, Class_ $class, array $config): Class_
108111
{
109112
$this->logger->info(sprintf('The property "%s" (type "%s") is a custom property.', $propertyName, $type->getUri()));
110113
$customResource = new RdfResource('_:'.$propertyName, new RdfGraph());
@@ -116,10 +119,10 @@ private function generateCustomField(string $propertyName, RdfResource $type, ar
116119
/**
117120
* Updates generated $class with given field config.
118121
*
119-
* @param Configuration $config
120-
* @param TypeConfiguration $typeConfig
122+
* @param Configuration $config
123+
* @param ?TypeConfiguration $typeConfig
121124
*/
122-
private function generateField(array $config, Class_ $class, RdfResource $type, array $typeConfig, RdfResource $property, bool $isCustom = false): Class_
125+
private function generateField(array $config, Class_ $class, RdfResource $type, ?array $typeConfig, RdfResource $property, bool $isCustom = false): Class_
123126
{
124127
return ($this->propertyGenerator)($config, $class, $type, $typeConfig, $property, $isCustom);
125128
}

src/PropertyGenerator/PropertyGenerator.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,10 @@ public function __construct(GoodRelationsBridge $goodRelationsBridge, PhpTypeCon
5050
}
5151

5252
/**
53-
* @param Configuration $config
54-
* @param TypeConfiguration $typeConfig
53+
* @param Configuration $config
54+
* @param ?TypeConfiguration $typeConfig
5555
*/
56-
public function __invoke(array $config, Class_ $class, RdfResource $type, array $typeConfig, RdfResource $property, bool $isCustom = false): Class_
56+
public function __invoke(array $config, Class_ $class, RdfResource $type, ?array $typeConfig, RdfResource $property, bool $isCustom = false): Class_
5757
{
5858
$typeUri = $type->getUri();
5959
$propertyName = $property->localName();

src/TypesGenerator.php

+9-3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
use EasyRdf\Graph as RdfGraph;
2828
use EasyRdf\RdfNamespace;
2929
use EasyRdf\Resource as RdfResource;
30+
use Nette\InvalidArgumentException as NetteInvalidArgumentException;
3031
use PhpCsFixer\Cache\NullCacheManager;
3132
use PhpCsFixer\Differ\NullDiffer;
3233
use PhpCsFixer\Error\ErrorsManager;
@@ -212,7 +213,7 @@ public function generate(array $config): void
212213
}
213214

214215
$parentConfig = $parentClass->parent() ? ($config['types'][$parentClass->parent()] ?? null) : null;
215-
$parentClass = $parentClass->parent() ? $classes[$parentClass->parent()] : null;
216+
$parentClass = $parentClass->parent() && isset($classes[$parentClass->parent()]) ? $classes[$parentClass->parent()] : null;
216217
}
217218
}
218219
}
@@ -252,9 +253,14 @@ public function generate(array $config): void
252253
$this->filesystem->mkdir($classDir);
253254

254255
$path = sprintf('%s%s.php', $classDir, $className);
255-
$generatedFiles[] = $path;
256256

257-
file_put_contents($path, $this->printer->printFile($class->toNetteFile($config, $this->inflector)));
257+
try {
258+
file_put_contents($path, $this->printer->printFile($class->toNetteFile($config, $this->inflector)));
259+
} catch (NetteInvalidArgumentException $exception) {
260+
$this->logger->warning($exception->getMessage());
261+
}
262+
263+
$generatedFiles[] = $path;
258264

259265
if (null !== $class->interfaceNamespace()) {
260266
$interfaceDir = $this->namespaceToDir($config, $class->interfaceNamespace());

tests/AttributeGenerator/DoctrineMongoDBAttributeGeneratorTest.php

+13-1
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,20 @@ protected function setUp(): void
8181
$myEnumClass = new Class_('MyEnum', $myEnum);
8282
$this->classMap[$myEnumClass->name()] = $myEnumClass;
8383

84+
$customAttributes = new RdfResource('https://schema.org/CustomAttributes', $graph);
85+
$customAttributesClass = new Class_('CustomAttributes', $customAttributes);
86+
$this->classMap[$customAttributesClass->name()] = $customAttributesClass;
87+
8488
$configuration = new TypesGeneratorConfiguration();
8589
/** @var Configuration $processedConfiguration */
86-
$processedConfiguration = (new Processor())->processConfiguration($configuration, [['id' => ['generationStrategy' => 'auto', 'writable' => true], 'types' => ['MyEnum' => null, 'Product' => null, 'Vehicle' => null]]]);
90+
$processedConfiguration = (new Processor())->processConfiguration($configuration, [[
91+
'id' => ['generationStrategy' => 'auto', 'writable' => true],
92+
'types' => [
93+
'CustomAttributes' => ['doctrine' => ['attributes' => ['MongoDB\Document' => ['db' => 'my_db']]]],
94+
'Product' => null,
95+
// Vehicle is not added deliberately
96+
],
97+
]]);
8798

8899
$this->generator = new DoctrineMongoDBAttributeGenerator(
89100
new PhpTypeConverter(),
@@ -99,6 +110,7 @@ protected function setUp(): void
99110
public function testGenerateClassAttributes(): void
100111
{
101112
$this->assertSame([], $this->generator->generateClassAttributes($this->classMap['MyEnum']));
113+
$this->assertEquals([new Attribute('MongoDB\Document', ['db' => 'my_db'])], $this->generator->generateClassAttributes($this->classMap['CustomAttributes']));
102114
$this->assertEquals([new Attribute('MongoDB\MappedSuperclass')], $this->generator->generateClassAttributes($this->classMap['Product']));
103115
$this->assertEquals([new Attribute('MongoDB\Document')], $this->generator->generateClassAttributes($this->classMap['Vehicle']));
104116
}

tests/AttributeGenerator/DoctrineOrmAttributeGeneratorTest.php

+13-1
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,20 @@ protected function setUp(): void
119119
$myEnumClass = new Class_('MyEnum', $myEnum);
120120
$this->classMap[$myEnumClass->name()] = $myEnumClass;
121121

122+
$customAttributes = new RdfResource('https://schema.org/CustomAttributes', $graph);
123+
$customAttributesClass = new Class_('CustomAttributes', $customAttributes);
124+
$this->classMap[$customAttributesClass->name()] = $customAttributesClass;
125+
122126
$configuration = new TypesGeneratorConfiguration();
123127
/** @var Configuration $processedConfiguration */
124-
$processedConfiguration = (new Processor())->processConfiguration($configuration, [['id' => ['generationStrategy' => 'auto', 'writable' => true], 'types' => ['MyEnum' => null, 'Product' => null, 'Vehicle' => null, 'QuantitativeValue' => null]]]);
128+
$processedConfiguration = (new Processor())->processConfiguration($configuration, [[
129+
'id' => ['generationStrategy' => 'auto', 'writable' => true],
130+
'types' => [
131+
'CustomAttributes' => ['doctrine' => ['attributes' => ['ORM\Entity' => ['readOnly' => true]]]],
132+
'Product' => null,
133+
// Vehicle is not added deliberately
134+
],
135+
]]);
125136

126137
$this->generator = new DoctrineOrmAttributeGenerator(
127138
new PhpTypeConverter(),
@@ -137,6 +148,7 @@ protected function setUp(): void
137148
public function testGenerateClassAttributes(): void
138149
{
139150
$this->assertSame([], $this->generator->generateClassAttributes($this->classMap['MyEnum']));
151+
$this->assertEquals([new Attribute('ORM\Entity', ['readOnly' => true])], $this->generator->generateClassAttributes($this->classMap['CustomAttributes']));
140152
$this->assertEquals([new Attribute('ORM\MappedSuperclass')], $this->generator->generateClassAttributes($this->classMap['Product']));
141153
$this->assertEquals([new Attribute('ORM\Entity')], $this->generator->generateClassAttributes($this->classMap['Vehicle']));
142154
$this->assertEquals([new Attribute('ORM\Embeddable')], $this->generator->generateClassAttributes($this->classMap['QuantitativeValue']));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\SchemaGenerator\Tests\ClassMutator;
15+
16+
use ApiPlatform\SchemaGenerator\ClassMutator\ClassParentMutator;
17+
use ApiPlatform\SchemaGenerator\Model\Class_;
18+
use ApiPlatform\SchemaGenerator\Model\Use_;
19+
use ApiPlatform\SchemaGenerator\PhpTypeConverter;
20+
use ApiPlatform\SchemaGenerator\TypesGeneratorConfiguration;
21+
use EasyRdf\Graph as RdfGraph;
22+
use EasyRdf\Resource as RdfResource;
23+
use PHPUnit\Framework\TestCase;
24+
use Prophecy\PhpUnit\ProphecyTrait;
25+
use Prophecy\Prophecy\ObjectProphecy;
26+
use Psr\Log\LoggerInterface;
27+
use Symfony\Component\Config\Definition\Processor;
28+
29+
class ClassParentMutatorTest extends TestCase
30+
{
31+
use ProphecyTrait;
32+
33+
private ObjectProphecy $loggerProphecy;
34+
private ClassParentMutator $classParentMutator;
35+
36+
protected function setUp(): void
37+
{
38+
$this->loggerProphecy = $this->prophesize(LoggerInterface::class);
39+
40+
$configuration = new TypesGeneratorConfiguration();
41+
/** @var Configuration $processedConfiguration */
42+
$processedConfiguration = (new Processor())->processConfiguration($configuration, [[
43+
'types' => [
44+
'BlogPosting' => ['parent' => 'SocialMediaPosting'],
45+
'SocialMediaPosting' => ['namespaces' => ['class' => 'socialMediaNamespace']],
46+
],
47+
]]);
48+
49+
$this->classParentMutator = new ClassParentMutator($processedConfiguration, new PhpTypeConverter(), $this->loggerProphecy->reveal());
50+
}
51+
52+
/**
53+
* @dataProvider provideInvokeTestCases
54+
*/
55+
public function testInvoke(Class_ $class, Class_ $expectedClass, ?string $loggerMessage = null): void
56+
{
57+
if ($loggerMessage) {
58+
$this->loggerProphecy->warning($loggerMessage)->shouldBeCalled();
59+
}
60+
61+
$this->assertEquals($expectedClass, ($this->classParentMutator)($class));
62+
}
63+
64+
/**
65+
* @return \Generator<array{0: Class_, 1: Class_, 2?: string}>
66+
*/
67+
public function provideInvokeTestCases(): \Generator
68+
{
69+
$graph = new RdfGraph();
70+
$product = new Class_('Product', new RdfResource('https://schema.org/Product', $graph));
71+
yield 'no parent' => [clone $product, clone $product];
72+
73+
$graph = new RdfGraph();
74+
$graph->addResource('https://schema.org/CreativeWork', 'rdfs:subClassOf', 'https://schema.org/Thing');
75+
$creativeWork = new Class_('CreativeWork', new RdfResource('https://schema.org/CreativeWork', $graph));
76+
yield 'with subclass' => [clone $creativeWork, (clone $creativeWork)->withParent('Thing')];
77+
78+
$graph = new RdfGraph();
79+
$graph->addResource('https://schema.org/CreativeWork', 'rdfs:subClassOf', 'https://schema.org/Work');
80+
$graph->addResource('https://schema.org/CreativeWork', 'rdfs:subClassOf', 'https://schema.org/Thing');
81+
$creativeWork = new Class_('CreativeWork', new RdfResource('https://schema.org/CreativeWork', $graph));
82+
yield 'with multiple subclasses' => [clone $creativeWork, (clone $creativeWork)->withParent('Work'), 'The type "https://schema.org/CreativeWork" has several supertypes. Using the first one.'];
83+
84+
$graph = new RdfGraph();
85+
$blogPosting = new Class_('BlogPosting', new RdfResource('https://schema.org/BlogPosting', $graph));
86+
yield 'with parent' => [clone $blogPosting, (clone $blogPosting)->withParent('SocialMediaPosting')->addUse(new Use_('socialMediaNamespace\SocialMediaPosting'))];
87+
}
88+
}

0 commit comments

Comments
 (0)