Skip to content

Commit e443cf2

Browse files
authored
Merge pull request #2005 from alcaeus/fix-discriminator-map-handling
Fix discriminator handling with partial discriminator maps
2 parents 8a8f3aa + 6545496 commit e443cf2

File tree

3 files changed

+284
-40
lines changed

3 files changed

+284
-40
lines changed

lib/Doctrine/ODM/MongoDB/DocumentManager.php

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -749,53 +749,42 @@ private function getDiscriminatorData(array $referenceMapping, ClassMetadata $cl
749749
{
750750
$discriminatorField = null;
751751
$discriminatorValue = null;
752-
$discriminatorData = [];
752+
$discriminatorMap = null;
753753

754754
if (isset($referenceMapping['discriminatorField'])) {
755755
$discriminatorField = $referenceMapping['discriminatorField'];
756+
756757
if (isset($referenceMapping['discriminatorMap'])) {
757-
$pos = array_search($class->name, $referenceMapping['discriminatorMap']);
758-
if ($pos !== false) {
759-
$discriminatorValue = $pos;
760-
}
761-
} else {
762-
$discriminatorValue = $class->name;
758+
$discriminatorMap = $referenceMapping['discriminatorMap'];
763759
}
764760
} else {
765761
$discriminatorField = $class->discriminatorField;
766-
$discriminatorValue = isset($class->discriminatorValue) ? $class->discriminatorValue : $class->name;
762+
$discriminatorValue = $class->discriminatorValue;
763+
$discriminatorMap = $class->discriminatorMap;
767764
}
768765

769-
if ($discriminatorField !== null) {
770-
if ($discriminatorValue === null) {
771-
@trigger_error(sprintf('Document class "%s" is unlisted in the discriminator map for reference "%s". This is deprecated and will throw an exception in 2.0.', $class->name, $referenceMapping['name']), E_USER_DEPRECATED);
772-
$discriminatorValue = $class->name;
773-
}
774-
775-
$discriminatorData = [$discriminatorField => $discriminatorValue];
776-
} elseif (! isset($referenceMapping['targetDocument'])) {
777-
$discriminatorField = $referenceMapping['discriminatorField'];
778-
779-
$discriminatorMap = null;
780-
if (isset($referenceMapping['discriminatorMap'])) {
781-
$discriminatorMap = $referenceMapping['discriminatorMap'];
782-
}
766+
if ($discriminatorField === null) {
767+
return [];
768+
}
783769

784-
if ($discriminatorMap === null) {
785-
$discriminatorValue = $class->name;
786-
} else {
787-
$discriminatorValue = array_search($class->name, $discriminatorMap);
770+
if ($discriminatorValue === null) {
771+
if (! empty($discriminatorMap)) {
772+
$pos = array_search($class->name, $discriminatorMap);
788773

789-
if ($discriminatorValue === false) {
790-
@trigger_error(sprintf('Document class "%s" is unlisted in the discriminator map for reference "%s". This is deprecated and will throw an exception in 2.0.', $class->name, $referenceMapping['name']), E_USER_DEPRECATED);
791-
$discriminatorValue = $class->name;
774+
if ($pos !== false) {
775+
$discriminatorValue = $pos;
792776
}
777+
} else {
778+
$discriminatorValue = $class->name;
793779
}
780+
}
794781

795-
$discriminatorData = [$discriminatorField => $discriminatorValue];
782+
if ($discriminatorValue === null) {
783+
@trigger_error(sprintf('Document class "%s" is unlisted in the discriminator map for reference "%s". This is deprecated and will throw an exception in doctrine/mongodb-odm 2.0.', $class->name, $referenceMapping['name']), E_USER_DEPRECATED);
784+
$discriminatorValue = $class->name;
796785
}
797786

798-
return $discriminatorData;
787+
return [$discriminatorField => $discriminatorValue];
799788
}
800789

801790
/**

lib/Doctrine/ODM/MongoDB/Persisters/PersistenceBuilder.php

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,17 @@ public function prepareInsertData($document)
114114

115115
// add discriminator if the class has one
116116
if (isset($class->discriminatorField)) {
117-
$insertData[$class->discriminatorField] = isset($class->discriminatorValue)
118-
? $class->discriminatorValue
119-
: $class->name;
117+
$discriminatorValue = $class->discriminatorValue;
118+
119+
if ($discriminatorValue === null) {
120+
if (! empty($class->discriminatorMap)) {
121+
@trigger_error(sprintf('Document class "%s" is unlisted in the discriminator map of its inheritance chain. This is deprecated and will throw an exception in doctrine/mongodb-odm 2.0.', $class->name), E_USER_DEPRECATED);
122+
}
123+
124+
$discriminatorValue = $class->name;
125+
}
126+
127+
$insertData[$class->discriminatorField] = $discriminatorValue;
120128
}
121129

122130
return $insertData;
@@ -293,9 +301,17 @@ public function prepareUpsertData($document)
293301

294302
// add discriminator if the class has one
295303
if (isset($class->discriminatorField)) {
296-
$updateData['$set'][$class->discriminatorField] = isset($class->discriminatorValue)
297-
? $class->discriminatorValue
298-
: $class->name;
304+
$discriminatorValue = $class->discriminatorValue;
305+
306+
if ($discriminatorValue === null) {
307+
if (! empty($class->discriminatorMap)) {
308+
@trigger_error(sprintf('Document class "%s" is unlisted in the discriminator map of its inheritance chain. This is deprecated and will throw an exception in doctrine/mongodb-odm 2.0.', $class->name), E_USER_DEPRECATED);
309+
}
310+
311+
$discriminatorValue = $class->name;
312+
}
313+
314+
$updateData['$set'][$class->discriminatorField] = $discriminatorValue;
299315
}
300316

301317
return $updateData;
@@ -416,9 +432,17 @@ public function prepareEmbeddedDocumentValue(array $embeddedMapping, $embeddedDo
416432
* discriminator field and no value, so default to the full class name.
417433
*/
418434
if (isset($class->discriminatorField)) {
419-
$embeddedDocumentValue[$class->discriminatorField] = isset($class->discriminatorValue)
420-
? $class->discriminatorValue
421-
: $class->name;
435+
$discriminatorValue = $class->discriminatorValue;
436+
437+
if ($discriminatorValue === null) {
438+
if (! empty($class->discriminatorMap)) {
439+
@trigger_error(sprintf('Document class "%s" is unlisted in the discriminator map of its inheritance chain. This is deprecated and will throw an exception in doctrine/mongodb-odm 2.0.', $class->name), E_USER_DEPRECATED);
440+
}
441+
442+
$discriminatorValue = $class->name;
443+
}
444+
445+
$embeddedDocumentValue[$class->discriminatorField] = $discriminatorValue;
422446
}
423447

424448
// Ensure empty embedded documents are stored as BSON objects
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
<?php
2+
3+
namespace Doctrine\ODM\MongoDB\Tests\Functional\Ticket;
4+
5+
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
6+
use Doctrine\ODM\MongoDB\Tests\BaseTest;
7+
8+
class GH2002Test extends BaseTest
9+
{
10+
/**
11+
* @dataProvider getReferenceData
12+
*/
13+
public function testBuildingReferenceCreatesCorrectStructure(array $expectedReference, $document)
14+
{
15+
$this->dm->persist($document);
16+
17+
$metadata = $this->dm->getClassMetadata(get_class($document));
18+
$this->dm->getUnitOfWork()->computeChangeSet($metadata, $document);
19+
20+
$data = $this->dm->getUnitOfWork()->getPersistenceBuilder()->prepareInsertData($document);
21+
22+
self::assertArraySubset($expectedReference, $data['parentDocument']);
23+
}
24+
25+
public function getReferenceData()
26+
{
27+
return [
28+
'discriminatedDocument' => [
29+
'expectedReference' => ['$ref' => 'GH2002DocumentA', 'class' => GH2002DocumentA::class],
30+
'document' => new GH2002DocumentB(new GH2002DocumentA()),
31+
],
32+
'referenceWithoutTargetDocument' => [
33+
'expectedReference' => ['$ref' => 'GH2002DocumentA', '_doctrine_class_name' => GH2002DocumentA::class],
34+
'document' => new GH2002ReferenceWithoutTargetDocument(new GH2002DocumentA()),
35+
],
36+
'referenceWithoutTargetDocumentWithDiscriminatorField' => [
37+
'expectedReference' => ['$ref' => 'GH2002DocumentA', 'referencedClass' => GH2002DocumentA::class],
38+
'document' => new GH2002ReferenceWithoutTargetDocumentWithDiscriminatorField(new GH2002DocumentA()),
39+
],
40+
'referenceWithDiscriminatorField' => [
41+
'expectedReference' => ['$ref' => 'GH2002DocumentA', 'referencedClass' => GH2002DocumentA::class],
42+
'document' => new GH2002ReferenceWithDiscriminatorField(new GH2002DocumentA()),
43+
],
44+
'referenceWithPartialDiscriminatorMapUnlistedDocument' => [
45+
'expectedReference' => ['$ref' => 'GH2002DocumentA', 'referencedClass' => GH2002DocumentA::class],
46+
'document' => new GH2002ReferenceWithPartialDiscriminatorMap(new GH2002DocumentA()),
47+
],
48+
'referenceWithPartialDiscriminatorMapListedDocument' => [
49+
'expectedReference' => ['$ref' => 'GH2002DocumentA', 'referencedClass' => 'B'],
50+
'document' => new GH2002ReferenceWithPartialDiscriminatorMap(new GH2002DocumentB()),
51+
],
52+
'documentWithDiscriminatorMapListedDocument' => [
53+
'expectedReference' => ['$ref' => 'GH2002DocumentWithDiscriminatorMapA', 'type' => 'A'],
54+
'document' => new GH2002DocumentWithDiscriminatorMapA(new GH2002DocumentWithDiscriminatorMapA()),
55+
],
56+
'documentWithDiscriminatorMapUnlistedDocument' => [
57+
'expectedReference' => ['$ref' => 'GH2002DocumentWithDiscriminatorMapA', 'type' => GH2002DocumentWithDiscriminatorMapB::class],
58+
'document' => new GH2002DocumentWithDiscriminatorMapA(new GH2002DocumentWithDiscriminatorMapB()),
59+
],
60+
];
61+
}
62+
}
63+
64+
/**
65+
* @ODM\Document
66+
* @ODM\InheritanceType("SINGLE_COLLECTION")
67+
* @ODM\DiscriminatorField("class")
68+
*/
69+
class GH2002DocumentA
70+
{
71+
/**
72+
* @ODM\Id
73+
*
74+
* @var string
75+
*/
76+
public $id;
77+
78+
/**
79+
* @ODM\ReferenceOne(targetDocument=GH2002DocumentA::class, cascade="all")
80+
*
81+
* @var GH2002DocumentA
82+
*/
83+
public $parentDocument;
84+
85+
public function __construct(GH2002DocumentA $parentDocument = null)
86+
{
87+
$this->parentDocument = $parentDocument;
88+
}
89+
}
90+
91+
/**
92+
* @ODM\Document
93+
*/
94+
class GH2002DocumentB extends GH2002DocumentA
95+
{
96+
}
97+
98+
/**
99+
* @ODM\Document
100+
*/
101+
class GH2002ReferenceWithoutTargetDocument
102+
{
103+
/**
104+
* @ODM\Id
105+
*
106+
* @var string
107+
*/
108+
public $id;
109+
110+
/**
111+
* @ODM\ReferenceOne(cascade="all")
112+
*
113+
* @var GH2002DocumentA
114+
*/
115+
public $parentDocument;
116+
117+
public function __construct(GH2002DocumentA $parentDocument = null)
118+
{
119+
$this->parentDocument = $parentDocument;
120+
}
121+
}
122+
123+
/**
124+
* @ODM\Document
125+
*/
126+
class GH2002ReferenceWithoutTargetDocumentWithDiscriminatorField
127+
{
128+
/**
129+
* @ODM\Id
130+
*
131+
* @var string
132+
*/
133+
public $id;
134+
135+
/**
136+
* @ODM\ReferenceOne(discriminatorField="referencedClass", cascade="all")
137+
*
138+
* @var GH2002DocumentA
139+
*/
140+
public $parentDocument;
141+
142+
public function __construct(GH2002DocumentA $parentDocument = null)
143+
{
144+
$this->parentDocument = $parentDocument;
145+
}
146+
}
147+
148+
/**
149+
* @ODM\Document
150+
*/
151+
class GH2002ReferenceWithDiscriminatorField
152+
{
153+
/**
154+
* @ODM\Id
155+
*
156+
* @var string
157+
*/
158+
public $id;
159+
160+
/**
161+
* @ODM\ReferenceOne(targetDocument=GH2002DocumentA::class, discriminatorField="referencedClass", cascade="all")
162+
*
163+
* @var GH2002DocumentA
164+
*/
165+
public $parentDocument;
166+
167+
public function __construct(GH2002DocumentA $parentDocument = null)
168+
{
169+
$this->parentDocument = $parentDocument;
170+
}
171+
}
172+
173+
/**
174+
* @ODM\Document
175+
*/
176+
class GH2002ReferenceWithPartialDiscriminatorMap
177+
{
178+
/**
179+
* @ODM\Id
180+
*
181+
* @var string
182+
*/
183+
public $id;
184+
185+
/**
186+
* @ODM\ReferenceOne(discriminatorField="referencedClass", discriminatorMap={"B"=GH2002DocumentB::class}, cascade="all")
187+
*
188+
* @var GH2002DocumentA
189+
*/
190+
public $parentDocument;
191+
192+
public function __construct(GH2002DocumentA $parentDocument = null)
193+
{
194+
$this->parentDocument = $parentDocument;
195+
}
196+
}
197+
198+
/**
199+
* @ODM\Document
200+
* @ODM\InheritanceType("SINGLE_COLLECTION")
201+
* @ODM\DiscriminatorField("type")
202+
* @ODM\DiscriminatorMap({"A"=GH2002DocumentWithDiscriminatorMapA::class})
203+
*/
204+
class GH2002DocumentWithDiscriminatorMapA
205+
{
206+
/**
207+
* @ODM\Id
208+
*
209+
* @var string
210+
*/
211+
public $id;
212+
213+
/**
214+
* @ODM\ReferenceOne(targetDocument=GH2002DocumentWithDiscriminatorMapA::class, cascade="all")
215+
*
216+
* @var GH2002DocumentWithDiscriminatorMapA
217+
*/
218+
public $parentDocument;
219+
220+
public function __construct(GH2002DocumentWithDiscriminatorMapA $parentDocument = null)
221+
{
222+
$this->parentDocument = $parentDocument;
223+
}
224+
}
225+
226+
/**
227+
* @ODM\Document
228+
*/
229+
class GH2002DocumentWithDiscriminatorMapB extends GH2002DocumentWithDiscriminatorMapA
230+
{
231+
}

0 commit comments

Comments
 (0)