Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 48ca06b

Browse files
committed
Add embedded class mapping array shape
This should be replaced with a DTO in the next major. To be able to have something usable, I had to move the validation of the DTO (checking that it has a "class" attribute) to mapEmbedded, which happens earlier than doLoadMetadata(). It is unclear to me why it was not put here in the first place.
1 parent 9857cf9 commit 48ca06b

4 files changed

Lines changed: 63 additions & 21 deletions

File tree

lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@
4747
* to a relational database.
4848
*
4949
* @extends AbstractClassMetadataFactory<ClassMetadata>
50+
* @psalm-import-type AssociationMapping from ClassMetadataInfo
51+
* @psalm-import-type EmbeddedClassMapping from ClassMetadataInfo
52+
* @psalm-import-type FieldMapping from ClassMetadataInfo
5053
*/
5154
class ClassMetadataFactory extends AbstractClassMetadataFactory
5255
{
@@ -150,10 +153,6 @@ protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonS
150153
continue;
151154
}
152155

153-
if (! (isset($embeddableClass['class']) && $embeddableClass['class'])) {
154-
throw MappingException::missingEmbeddedClass($property);
155-
}
156-
157156
if (isset($this->embeddablesActiveNesting[$embeddableClass['class']])) {
158157
throw MappingException::infiniteEmbeddableNesting($class->name, $property);
159158
}
@@ -415,7 +414,7 @@ private function getShortName(string $className): string
415414
* Puts the `inherited` and `declared` values into mapping information for fields, associations
416415
* and embedded classes.
417416
*
418-
* @param mixed[] $mapping
417+
* @param AssociationMapping|EmbeddedClassMapping|FieldMapping $mapping
419418
*/
420419
private function addMappingInheritanceInformation(array &$mapping, ClassMetadata $parentClass): void
421420
{

lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,14 @@
147147
* columnDefinition?: string|null,
148148
* enumType?: class-string<BackedEnum>|null,
149149
* }
150+
* @psalm-type EmbeddedClassMapping = array{
151+
* class: class-string,
152+
* columnPrefix: string|null,
153+
* declaredField: string|null,
154+
* originalField: string|null,
155+
* inherited?: class-string,
156+
* declared?: class-string,
157+
* }
150158
*/
151159
class ClassMetadataInfo implements ClassMetadata
152160
{
@@ -447,7 +455,7 @@ class ClassMetadataInfo implements ClassMetadata
447455
* declared in another parent <em>entity or mapped superclass</em>. The value is the FQCN
448456
* of the topmost non-transient class that contains mapping information for this field.
449457
*
450-
* @psalm-var array<string, mixed[]>
458+
* @psalm-var array<string, EmbeddedClassMapping>
451459
*/
452460
public $embeddedClasses = [];
453461

@@ -1171,6 +1179,7 @@ public function wakeupReflection($reflService)
11711179

11721180
foreach ($this->embeddedClasses as $property => $embeddedClass) {
11731181
if (isset($embeddedClass['declaredField'])) {
1182+
assert($embeddedClass['originalField'] !== null);
11741183
$childProperty = $this->getAccessibleProperty(
11751184
$reflService,
11761185
$this->embeddedClasses[$embeddedClass['declaredField']]['class'],
@@ -3883,8 +3892,16 @@ public function mapEmbedded(array $mapping)
38833892
}
38843893
}
38853894

3895+
if (! (isset($mapping['class']) && $mapping['class'])) {
3896+
throw MappingException::missingEmbeddedClass($mapping['fieldName']);
3897+
}
3898+
3899+
$fqcn = $this->fullyQualifiedClassName($mapping['class']);
3900+
3901+
assert($fqcn !== null);
3902+
38863903
$this->embeddedClasses[$mapping['fieldName']] = [
3887-
'class' => $this->fullyQualifiedClassName($mapping['class']),
3904+
'class' => $fqcn,
38883905
'columnPrefix' => $mapping['columnPrefix'] ?? null,
38893906
'declaredField' => $mapping['declaredField'] ?? null,
38903907
'originalField' => $mapping['originalField'] ?? null,

psalm.xml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,18 @@
121121
<referencedFunction name="Doctrine\ORM\Mapping\ClassMetadata::addInheritedAssociationMapping"/>
122122
</errorLevel>
123123
</InvalidArgument>
124+
<InvalidArrayAccess>
125+
<errorLevel type="suppress">
126+
<!-- https://github.com/vimeo/psalm/issues/9160 -->
127+
<file name="lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php"/>
128+
</errorLevel>
129+
</InvalidArrayAccess>
130+
<InvalidArrayAssignment>
131+
<errorLevel type="suppress">
132+
<!-- https://github.com/vimeo/psalm/issues/9160 -->
133+
<file name="lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php"/>
134+
</errorLevel>
135+
</InvalidArrayAssignment>
124136
<InvalidClass>
125137
<errorLevel type="suppress">
126138
<!-- Class name changes in DBAL 3. -->
@@ -133,6 +145,12 @@
133145
<file name="lib/Doctrine/ORM/Query/AST/InstanceOfExpression.php"/>
134146
</errorLevel>
135147
</InvalidParamDefault>
148+
<InvalidPropertyAssignmentValue>
149+
<errorLevel type="suppress">
150+
<!-- https://github.com/vimeo/psalm/issues/9155 -->
151+
<file name="lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php"/>
152+
</errorLevel>
153+
</InvalidPropertyAssignmentValue>
136154
<MethodSignatureMismatch>
137155
<errorLevel type="suppress">
138156
<!-- See https://github.com/vimeo/psalm/issues/7357 -->
@@ -162,6 +180,12 @@
162180
<file name="lib/Doctrine/ORM/Query/AST/InSubselectExpression.php"/>
163181
</errorLevel>
164182
</NonInvariantDocblockPropertyType>
183+
<PossiblyInvalidArgument>
184+
<errorLevel type="suppress">
185+
<!-- https://github.com/vimeo/psalm/issues/9155 -->
186+
<file name="lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php"/>
187+
</errorLevel>
188+
</PossiblyInvalidArgument>
165189
<PropertyNotSetInConstructor>
166190
<errorLevel type="suppress">
167191
<!-- Remove on 3.0.x -->
@@ -171,6 +195,11 @@
171195
<directory name="lib/Doctrine/ORM/Query/AST" />
172196
</errorLevel>
173197
</PropertyNotSetInConstructor>
198+
<PropertyTypeCoercion>
199+
<errorLevel type="suppress">
200+
<file name="lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php"/>
201+
</errorLevel>
202+
</PropertyTypeCoercion>
174203
<RedundantCastGivenDocblockType>
175204
<errorLevel type="suppress">
176205
<!-- Can be removed once the "getMaxResults" methods of those classes have native parameter types -->
@@ -184,6 +213,12 @@
184213
<file name="lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php"/>
185214
</errorLevel>
186215
</RedundantCondition>
216+
<ReferenceConstraintViolation>
217+
<errorLevel type="suppress">
218+
<!-- https://github.com/vimeo/psalm/issues/9155 -->
219+
<file name="lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php"/>
220+
</errorLevel>
221+
</ReferenceConstraintViolation>
187222
<TooManyArguments>
188223
<errorLevel type="suppress">
189224
<!-- Symfony cache supports passing a key prefix to the clear method. -->

tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -469,22 +469,13 @@ public function testRejectsEmbeddableWithoutValidClassName(): void
469469
{
470470
$metadata = $this->createValidClassMetadata();
471471

472-
$metadata->mapEmbedded(
473-
[
474-
'fieldName' => 'embedded',
475-
'class' => '',
476-
'columnPrefix' => false,
477-
]
478-
);
479-
480-
$cmf = $this->createTestFactory();
481-
482-
$cmf->setMetadataForClass($metadata->name, $metadata);
483-
484472
$this->expectException(MappingException::class);
485473
$this->expectExceptionMessage('The embed mapping \'embedded\' misses the \'class\' attribute.');
486-
487-
$cmf->getMetadataFor($metadata->name);
474+
$metadata->mapEmbedded([
475+
'fieldName' => 'embedded',
476+
'class' => '',
477+
'columnPrefix' => false,
478+
]);
488479
}
489480

490481
/** @group DDC-4006 */

0 commit comments

Comments
 (0)