Skip to content

Commit 5c7bb2f

Browse files
authored
fix: make sure the default cardinality is used (#384)
1 parent 262f5b2 commit 5c7bb2f

File tree

8 files changed

+86
-68
lines changed

8 files changed

+86
-68
lines changed

src/Schema/PropertyGenerator/PropertyGenerator.php

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -69,26 +69,6 @@ public function __invoke(string $name, array $config, Class_ $class, array $cont
6969

7070
$propertyConfig = $typeConfig['properties'][$name] ?? null;
7171

72-
$cardinality = $propertyConfig['cardinality'] ?? false;
73-
if (!$cardinality || CardinalitiesExtractor::CARDINALITY_UNKNOWN === $cardinality) {
74-
$cardinality = $cardinalities[$propertyUri] ?? $config['relations']['defaultCardinality'];
75-
}
76-
77-
$isArray = \in_array($cardinality, [
78-
CardinalitiesExtractor::CARDINALITY_0_N,
79-
CardinalitiesExtractor::CARDINALITY_1_N,
80-
CardinalitiesExtractor::CARDINALITY_N_N,
81-
], true);
82-
83-
$schemaProperty = new SchemaProperty($name);
84-
$schemaProperty->isArray = $isArray;
85-
86-
$schemaProperty = ($this->propertyGenerator)($name, $config, $class, $context, $isCustom, $schemaProperty);
87-
88-
if (!$schemaProperty instanceof SchemaProperty) {
89-
throw new \LogicException(sprintf('Property has to be an instance of "%s".', SchemaProperty::class));
90-
}
91-
9272
// Warn when property are not part of GoodRelations
9373
if ($config['checkIsGoodRelations'] && !$this->goodRelationsBridge->exists($name)) {
9474
$this->logger ? $this->logger->warning(sprintf('The property "%s" (type "%s") is not part of GoodRelations.', $propertyUri, $typeUri)) : null;
@@ -135,10 +115,35 @@ public function __invoke(string $name, array $config, Class_ $class, array $cont
135115
return null;
136116
}
137117

118+
$type = $this->typeConverter->getType($range);
119+
120+
$cardinality = $propertyConfig['cardinality'] ?? CardinalitiesExtractor::CARDINALITY_UNKNOWN;
121+
if (CardinalitiesExtractor::CARDINALITY_UNKNOWN === $cardinality) {
122+
$cardinality = $cardinalities[$propertyUri] ?? CardinalitiesExtractor::CARDINALITY_UNKNOWN;
123+
}
124+
if (!$type && CardinalitiesExtractor::CARDINALITY_UNKNOWN === $cardinality) {
125+
$cardinality = $config['relations']['defaultCardinality'];
126+
}
127+
128+
$isArray = \in_array($cardinality, [
129+
CardinalitiesExtractor::CARDINALITY_0_N,
130+
CardinalitiesExtractor::CARDINALITY_1_N,
131+
CardinalitiesExtractor::CARDINALITY_N_N,
132+
], true);
133+
134+
$schemaProperty = new SchemaProperty($name);
135+
$schemaProperty->isArray = $isArray;
136+
137+
$schemaProperty = ($this->propertyGenerator)($name, $config, $class, $context, $isCustom, $schemaProperty);
138+
139+
if (!$schemaProperty instanceof SchemaProperty) {
140+
throw new \LogicException(sprintf('Property has to be an instance of "%s".', SchemaProperty::class));
141+
}
142+
138143
$isNullable = (bool) ($propertyConfig['nullable'] ?? !\in_array($cardinality, [
139-
CardinalitiesExtractor::CARDINALITY_1_1,
140-
CardinalitiesExtractor::CARDINALITY_1_N,
141-
], true));
144+
CardinalitiesExtractor::CARDINALITY_1_1,
145+
CardinalitiesExtractor::CARDINALITY_1_N,
146+
], true));
142147

143148
$columnPrefix = false;
144149
$isEmbedded = $propertyConfig['embedded'] ?? false;
@@ -150,7 +155,7 @@ public function __invoke(string $name, array $config, Class_ $class, array $cont
150155
$schemaProperty->resource = $typeProperty;
151156
$schemaProperty->range = $range;
152157
$schemaProperty->rangeName = $rangeName;
153-
$schemaProperty->type = $this->typeConverter->getType($range);
158+
$schemaProperty->type = $type;
154159
$schemaProperty->cardinality = $cardinality;
155160
$schemaProperty->ormColumn = $propertyConfig['ormColumn'] ?? null;
156161
$schemaProperty->isReadable = $propertyConfig['readable'] ?? true;

src/SchemaGeneratorConfiguration.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ public function getConfigTreeBuilder(): TreeBuilder
245245
->scalarNode('inversedBy')->defaultNull()->info('The doctrine inversed by attribute')->example('episodes')->end()
246246
->booleanNode('readable')->defaultTrue()->info('Is the property readable?')->end()
247247
->booleanNode('writable')->defaultTrue()->info('Is the property writable?')->end()
248-
->booleanNode('nullable')->defaultTrue()->info('Is the property nullable?')->end()
248+
->booleanNode('nullable')->defaultNull()->info('Is the property nullable? (if null, cardinality will be used: will be true if no cardinality found)')->end()
249249
->booleanNode('required')->defaultTrue()->info('Is the property required?')->end()
250250
->booleanNode('unique')->defaultFalse()->info('The property unique')->end()
251251
->booleanNode('embedded')->defaultFalse()->info('Is the property embedded?')->end()

tests/ClassMutator/ClassPropertiesAppenderTest.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,25 +101,25 @@ public function provideInvokeTestCases(): \Generator
101101
$article = new SchemaClass('Article', new RdfResource('https://schema.org/Article'));
102102
$graph = new RdfGraph();
103103
$expectedArticleBodyProperty = new Property('articleBody');
104-
$expectedArticleBodyProperty->cardinality = CardinalitiesExtractor::CARDINALITY_1_1;
104+
$expectedArticleBodyProperty->cardinality = CardinalitiesExtractor::CARDINALITY_UNKNOWN;
105105
$expectedArticleBodyProperty->resource = new RdfResource('https://schema.org/articleBody', $graph);
106106
$expectedArticleBodyProperty->range = new RdfResource('https://schema.org/Text', $graph);
107107
$expectedArticleBodyProperty->rangeName = 'Text';
108108
$expectedArticleBodyProperty->type = 'string';
109-
$expectedArticleBodyProperty->isNullable = false;
109+
$expectedArticleBodyProperty->isNullable = true;
110110
$expectedArticleSectionProperty = new Property('articleSection');
111-
$expectedArticleSectionProperty->cardinality = CardinalitiesExtractor::CARDINALITY_1_1;
111+
$expectedArticleSectionProperty->cardinality = CardinalitiesExtractor::CARDINALITY_UNKNOWN;
112112
$expectedArticleSectionProperty->resource = new RdfResource('https://schema.org/articleSection', $graph);
113113
$expectedArticleSectionProperty->range = new RdfResource('https://schema.org/Text', $graph);
114114
$expectedArticleSectionProperty->rangeName = 'Text';
115115
$expectedArticleSectionProperty->type = 'string';
116-
$expectedArticleSectionProperty->isNullable = false;
116+
$expectedArticleSectionProperty->isNullable = true;
117117
yield 'no configuration' => [clone $article, (clone $article)->addProperty($expectedArticleBodyProperty)->addProperty($expectedArticleSectionProperty), $graph];
118118

119119
$graph = new RdfGraph();
120120
$person = new SchemaClass('Person', new RdfResource('https://schema.org/Person', $graph));
121121
$expectedGivenNameProperty = new Property('givenName');
122-
$expectedGivenNameProperty->cardinality = CardinalitiesExtractor::CARDINALITY_1_1;
122+
$expectedGivenNameProperty->cardinality = CardinalitiesExtractor::CARDINALITY_UNKNOWN;
123123
$expectedGivenNameProperty->resource = new RdfResource('https://schema.org/givenName', $graph);
124124
$expectedGivenNameProperty->range = new RdfResource('https://schema.org/Text', $graph);
125125
$expectedGivenNameProperty->rangeName = 'Text';

tests/Command/DumpConfigurationTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,8 @@ interface: null
240240
# Is the property writable?
241241
writable: true
242242
243-
# Is the property nullable?
244-
nullable: true
243+
# Is the property nullable? (if null, cardinality will be used: will be true if no cardinality found)
244+
nullable: null
245245
246246
# Is the property required?
247247
required: true

tests/Command/GenerateCommandTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public function testCustomAttributes(): void
9393
use Doctrine\Common\Collections\ArrayCollection;
9494
use Doctrine\Common\Collections\Collection;
9595
use Doctrine\ORM\Mapping as ORM;
96+
use Symfony\Component\Validator\Constraints as Assert;
9697
9798
/**
9899
* A book.

tests/TypesGeneratorTest.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,16 +123,16 @@ public function testGenerate(): void
123123

124124
$socialMediaPosting = file_get_contents("$this->outputDir/App/Entity/SocialMediaPosting.php");
125125
$this->assertStringContainsString('abstract class SocialMediaPosting extends Article', $socialMediaPosting);
126-
$this->assertStringContainsString('private ?CreativeWork $sharedContent = null;', $socialMediaPosting);
126+
$this->assertStringContainsString('private CreativeWork $sharedContent;', $socialMediaPosting);
127127
$this->assertStringContainsString(<<<'PHP'
128-
public function setSharedContent(?CreativeWork $sharedContent): void
128+
public function setSharedContent(CreativeWork $sharedContent): void
129129
{
130130
$this->sharedContent = $sharedContent;
131131
}
132132
PHP, $socialMediaPosting);
133133

134134
$this->assertStringContainsString(<<<'PHP'
135-
public function getSharedContent(): ?CreativeWork
135+
public function getSharedContent(): CreativeWork
136136
{
137137
return $this->sharedContent;
138138
}
@@ -175,9 +175,9 @@ public function testGenerateAllResolveTypes(): void
175175

176176
$competencyWorldEntity = file_get_contents("$this->outputDir/App/Entity/CompetencyWorldEntity.php");
177177
$this->assertStringContainsString('class CompetencyWorldEntity extends Thing', $competencyWorldEntity);
178-
$this->assertStringContainsString('private string $hasAppellation;', $competencyWorldEntity);
179-
$this->assertStringContainsString('public function setHasAppellation(string $hasAppellation): void', $competencyWorldEntity);
180-
$this->assertStringContainsString('public function getHasAppellation(): string', $competencyWorldEntity);
178+
$this->assertStringContainsString('private ?string $hasAppellation = null;', $competencyWorldEntity);
179+
$this->assertStringContainsString('public function setHasAppellation(?string $hasAppellation): void', $competencyWorldEntity);
180+
$this->assertStringContainsString('public function getHasAppellation(): ?string', $competencyWorldEntity);
181181
}
182182

183183
public function testGenerateVocabAllTypes(): void

tests/e2e/customized/App/Schema/Entity/Person.php

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -77,19 +77,22 @@ class Person extends MyCustomClass implements MyCustomInterface
7777
*
7878
* @see https://schema.org/gender
7979
*/
80-
#[ORM\Column(nullable: true)]
80+
#[ORM\Column]
8181
#[ApiProperty(types: ['https://schema.org/gender'])]
82+
#[Assert\NotNull]
8283
#[Assert\Choice(callback: [GenderType::class, 'toArray'])]
83-
private ?string $gender = null;
84+
private string $gender;
8485

8586
/**
8687
* Physical address of the item.
8788
*
8889
* @see https://schema.org/address
8990
*/
90-
#[ORM\ManyToOne(targetEntity: 'App\Schema\Entity\PostalAddress')]
91+
#[ORM\OneToOne(targetEntity: 'App\Schema\Entity\PostalAddress')]
92+
#[ORM\JoinColumn(nullable: false)]
9193
#[ApiProperty(types: ['https://schema.org/address'])]
92-
private ?PostalAddress $address = null;
94+
#[Assert\NotNull]
95+
private PostalAddress $address;
9396

9497
/**
9598
* Date of birth.
@@ -145,13 +148,16 @@ class Person extends MyCustomClass implements MyCustomInterface
145148
*
146149
* @see https://schema.org/knowsAbout
147150
*/
148-
#[ORM\ManyToOne(targetEntity: 'App\Schema\Entity\Thing')]
151+
#[ORM\OneToOne(targetEntity: 'App\Schema\Entity\Thing')]
152+
#[ORM\JoinColumn(nullable: false)]
149153
#[ApiProperty(types: ['https://schema.org/knowsAbout'])]
150-
private ?Thing $knowsAbout = null;
154+
#[Assert\NotNull]
155+
private Thing $knowsAbout;
151156

152157
/** @see _:customColumn */
153158
#[ORM\Column(type: 'decimal', precision: 5, scale: 1, options: ['comment' => 'my comment'])]
154-
private ?Person $customColumn = null;
159+
#[Assert\NotNull]
160+
private Person $customColumn;
155161

156162
public function __construct()
157163
{
@@ -193,22 +199,22 @@ public function getAdditionalName(): ?string
193199
return $this->additionalName;
194200
}
195201

196-
public function setGender(?string $gender): void
202+
public function setGender(string $gender): void
197203
{
198204
$this->gender = $gender;
199205
}
200206

201-
public function getGender(): ?string
207+
public function getGender(): string
202208
{
203209
return $this->gender;
204210
}
205211

206-
public function setAddress(?PostalAddress $address): void
212+
public function setAddress(PostalAddress $address): void
207213
{
208214
$this->address = $address;
209215
}
210216

211-
public function getAddress(): ?PostalAddress
217+
public function getAddress(): PostalAddress
212218
{
213219
return $this->address;
214220
}
@@ -271,22 +277,22 @@ public function getSiblings(): Collection
271277
return $this->siblings;
272278
}
273279

274-
public function setKnowsAbout(?Thing $knowsAbout): void
280+
public function setKnowsAbout(Thing $knowsAbout): void
275281
{
276282
$this->knowsAbout = $knowsAbout;
277283
}
278284

279-
public function getKnowsAbout(): ?Thing
285+
public function getKnowsAbout(): Thing
280286
{
281287
return $this->knowsAbout;
282288
}
283289

284-
public function setCustomColumn(?Person $customColumn): void
290+
public function setCustomColumn(Person $customColumn): void
285291
{
286292
$this->customColumn = $customColumn;
287293
}
288294

289-
public function getCustomColumn(): ?Person
295+
public function getCustomColumn(): Person
290296
{
291297
return $this->customColumn;
292298
}

tests/e2e/original/App/Schema/Entity/Person.php

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -68,19 +68,22 @@ class Person extends Thing
6868
*
6969
* @see https://schema.org/gender
7070
*/
71-
#[ORM\Column(nullable: true)]
71+
#[ORM\Column]
7272
#[ApiProperty(types: ['https://schema.org/gender'])]
73+
#[Assert\NotNull]
7374
#[Assert\Choice(callback: [GenderType::class, 'toArray'])]
74-
private ?string $gender = null;
75+
private string $gender;
7576

7677
/**
7778
* Physical address of the item.
7879
*
7980
* @see https://schema.org/address
8081
*/
81-
#[ORM\ManyToOne(targetEntity: 'App\Schema\Entity\PostalAddress')]
82+
#[ORM\OneToOne(targetEntity: 'App\Schema\Entity\PostalAddress')]
83+
#[ORM\JoinColumn(nullable: false)]
8284
#[ApiProperty(types: ['https://schema.org/address'])]
83-
private ?PostalAddress $address = null;
85+
#[Assert\NotNull]
86+
private PostalAddress $address;
8487

8588
/**
8689
* Date of birth.
@@ -136,15 +139,18 @@ class Person extends Thing
136139
*
137140
* @see https://schema.org/knowsAbout
138141
*/
139-
#[ORM\ManyToOne(targetEntity: 'App\Schema\Entity\Thing')]
142+
#[ORM\OneToOne(targetEntity: 'App\Schema\Entity\Thing')]
143+
#[ORM\JoinColumn(nullable: false)]
140144
#[ApiProperty(types: ['https://schema.org/knowsAbout'])]
141-
private ?Thing $knowsAbout = null;
145+
#[Assert\NotNull]
146+
private Thing $knowsAbout;
142147

143148
/**
144149
* @see _:customColumn
145150
*/
146151
#[ORM\Column(type: 'decimal', precision: 5, scale: 1, options: ['comment' => 'my comment'])]
147-
private ?Person $customColumn = null;
152+
#[Assert\NotNull]
153+
private Person $customColumn;
148154

149155
public function __construct()
150156
{
@@ -181,22 +187,22 @@ public function getAdditionalName(): ?string
181187
return $this->additionalName;
182188
}
183189

184-
public function setGender(?string $gender): void
190+
public function setGender(string $gender): void
185191
{
186192
$this->gender = $gender;
187193
}
188194

189-
public function getGender(): ?string
195+
public function getGender(): string
190196
{
191197
return $this->gender;
192198
}
193199

194-
public function setAddress(?PostalAddress $address): void
200+
public function setAddress(PostalAddress $address): void
195201
{
196202
$this->address = $address;
197203
}
198204

199-
public function getAddress(): ?PostalAddress
205+
public function getAddress(): PostalAddress
200206
{
201207
return $this->address;
202208
}
@@ -259,22 +265,22 @@ public function getSiblings(): Collection
259265
return $this->siblings;
260266
}
261267

262-
public function setKnowsAbout(?Thing $knowsAbout): void
268+
public function setKnowsAbout(Thing $knowsAbout): void
263269
{
264270
$this->knowsAbout = $knowsAbout;
265271
}
266272

267-
public function getKnowsAbout(): ?Thing
273+
public function getKnowsAbout(): Thing
268274
{
269275
return $this->knowsAbout;
270276
}
271277

272-
public function setCustomColumn(?Person $customColumn): void
278+
public function setCustomColumn(Person $customColumn): void
273279
{
274280
$this->customColumn = $customColumn;
275281
}
276282

277-
public function getCustomColumn(): ?Person
283+
public function getCustomColumn(): Person
278284
{
279285
return $this->customColumn;
280286
}

0 commit comments

Comments
 (0)