Skip to content

Commit 92b0d2f

Browse files
authored
Validate that targetDocument can be resolved (#2577)
* fix: Validate that targetDocument can be resolved * refactor: Use exception factory * fix: Validate that all values in a discriminatorMap can be resolved * fix: PHPStan errors for intentionally missing class * fix: psalm/phpunit CI tests
1 parent d6f1686 commit 92b0d2f

File tree

4 files changed

+151
-55
lines changed

4 files changed

+151
-55
lines changed

lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadata.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
use function extension_loaded;
4343
use function get_class;
4444
use function in_array;
45+
use function interface_exists;
4546
use function is_array;
4647
use function is_string;
4748
use function is_subclass_of;
@@ -2309,6 +2310,22 @@ public function mapField(array $mapping): array
23092310
$mapping['discriminatorField'] = self::DEFAULT_DISCRIMINATOR_FIELD;
23102311
}
23112312

2313+
if (isset($mapping['targetDocument']) && ! class_exists($mapping['targetDocument']) && ! interface_exists($mapping['targetDocument'])) {
2314+
throw MappingException::invalidTargetDocument(
2315+
$mapping['targetDocument'],
2316+
$this->name,
2317+
$mapping['fieldName'],
2318+
);
2319+
}
2320+
2321+
if (isset($mapping['discriminatorMap'])) {
2322+
foreach ($mapping['discriminatorMap'] as $value => $class) {
2323+
if (! class_exists($class) && ! interface_exists($class)) {
2324+
throw MappingException::invalidClassInReferenceDiscriminatorMap($class, $this->name, $mapping['fieldName']);
2325+
}
2326+
}
2327+
}
2328+
23122329
if (isset($mapping['version'])) {
23132330
$mapping['notSaved'] = true;
23142331
$this->setVersionMapping($mapping);

lib/Doctrine/ODM/MongoDB/Mapping/MappingException.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ public static function invalidClassInDiscriminatorMap(string $className, string
7777
return new self(sprintf("Document class '%s' used in the discriminator map of class '%s' does not exist.", $className, $owningClass));
7878
}
7979

80+
public static function invalidClassInReferenceDiscriminatorMap(string $className, string $owningClass, string $fieldName): self
81+
{
82+
return new self(sprintf("Document class '%s' used in the discriminator map of field '%s' in class '%s' does not exist.", $className, $fieldName, $owningClass));
83+
}
84+
8085
public static function unlistedClassInDiscriminatorMap(string $className): self
8186
{
8287
return new self(sprintf('Document class "%s" is unlisted in the discriminator map.', $className));
@@ -87,6 +92,11 @@ public static function invalidDiscriminatorValue(string $value, string $owningCl
8792
return new self(sprintf("Discriminator value '%s' used in the declaration of class '%s' does not exist.", $value, $owningClass));
8893
}
8994

95+
public static function invalidTargetDocument(string $targetDocument, string $owningClass, string $owningField): self
96+
{
97+
return new self(sprintf("Target document class '%s' used in field '%s' of class '%s' does not exist.", $targetDocument, $owningField, $owningClass));
98+
}
99+
90100
public static function missingFieldName(string $className): self
91101
{
92102
return new self(sprintf("The Document class '%s' field mapping misses the 'fieldName' attribute.", $className));
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\ODM\MongoDB\Tests\Functional;
6+
7+
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
8+
use Doctrine\ODM\MongoDB\Mapping\MappingException;
9+
use Doctrine\ODM\MongoDB\Tests\BaseTestCase;
10+
use stdClass;
11+
12+
class TargetDocumentTest extends BaseTestCase
13+
{
14+
/** @doesNotPerformAssertions */
15+
public function testMappedSuperClassAsTargetDocument(): void
16+
{
17+
$test = new TargetDocumentTestDocument();
18+
$test->reference = new TargetDocumentTestReference();
19+
$this->dm->persist($test);
20+
$this->dm->persist($test->reference);
21+
$this->dm->flush();
22+
}
23+
24+
public function testTargetDocumentIsResolvable(): void
25+
{
26+
self::expectExceptionObject(
27+
MappingException::invalidTargetDocument(
28+
'Doctrine\ODM\MongoDB\Tests\Functional\SomeInvalidClass',
29+
InvalidTargetDocumentTestDocument::class,
30+
'reference',
31+
),
32+
);
33+
34+
$test = new InvalidTargetDocumentTestDocument();
35+
$test->reference = new stdClass();
36+
$this->dm->persist($test);
37+
}
38+
39+
public function testDiscriminatorTargetIsResolvable(): void
40+
{
41+
self::expectExceptionObject(
42+
MappingException::invalidClassInReferenceDiscriminatorMap(
43+
'Doctrine\ODM\MongoDB\Tests\Functional\SomeInvalidClass',
44+
InvalidDiscriminatorTargetsTestDocument::class,
45+
'reference',
46+
),
47+
);
48+
49+
$test = new InvalidDiscriminatorTargetsTestDocument();
50+
$test->reference = new stdClass();
51+
$this->dm->persist($test);
52+
}
53+
}
54+
55+
/** @ODM\Document */
56+
class TargetDocumentTestDocument
57+
{
58+
/**
59+
* @ODM\Id
60+
*
61+
* @var string|null
62+
*/
63+
public $id;
64+
65+
/**
66+
* @ODM\ReferenceOne(targetDocument=Doctrine\ODM\MongoDB\Tests\Functional\TargetDocumentTestReference::class)
67+
*
68+
* @var TargetDocumentTestReference|null
69+
*/
70+
public $reference;
71+
}
72+
73+
/** @ODM\MappedSuperclass */
74+
abstract class AbstractTargetDocumentTestReference
75+
{
76+
/**
77+
* @ODM\Id
78+
*
79+
* @var string|null
80+
*/
81+
public $id;
82+
}
83+
84+
/** @ODM\Document */
85+
class TargetDocumentTestReference extends AbstractTargetDocumentTestReference
86+
{
87+
}
88+
89+
/** @ODM\Document */
90+
class InvalidTargetDocumentTestDocument
91+
{
92+
/**
93+
* @ODM\Id
94+
*
95+
* @var string|null
96+
*/
97+
public $id;
98+
99+
/**
100+
* @ODM\ReferenceOne(targetDocument="Doctrine\ODM\MongoDB\Tests\Functional\SomeInvalidClass")
101+
*
102+
* @var object|null
103+
*/
104+
public $reference;
105+
}
106+
107+
108+
/** @ODM\Document */
109+
class InvalidDiscriminatorTargetsTestDocument
110+
{
111+
/**
112+
* @ODM\Id
113+
*
114+
* @var string|null
115+
*/
116+
public $id;
117+
118+
/**
119+
* @ODM\ReferenceOne(discriminatorField="referencedClass", discriminatorMap={"Foo"="Doctrine\ODM\MongoDB\Tests\Functional\SomeInvalidClass"})
120+
*
121+
* @var object|null
122+
*/
123+
public $reference;
124+
}

tests/Doctrine/ODM/MongoDB/Tests/Functional/TestTargetDocument.php

Lines changed: 0 additions & 55 deletions
This file was deleted.

0 commit comments

Comments
 (0)