Skip to content

Commit 8ac6a13

Browse files
authored
Merge pull request #11564 from gitbugr/GH11501_fix_o2m_persister_single_inheritence_parent_relation_bugfix
GH11551 - fix OneToManyPersister::deleteEntityCollection case where single-inheritence table parent entity is targetEntity.
2 parents 51ad860 + 2707b09 commit 8ac6a13

File tree

2 files changed

+129
-3
lines changed

2 files changed

+129
-3
lines changed

src/Persisters/Collection/OneToManyPersister.php

+9-3
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,13 @@
1313
use Doctrine\ORM\PersistentCollection;
1414
use Doctrine\ORM\Utility\PersisterHelper;
1515

16+
use function array_fill;
17+
use function array_keys;
1618
use function array_merge;
1719
use function array_reverse;
1820
use function array_values;
1921
use function assert;
22+
use function count;
2023
use function implode;
2124
use function is_int;
2225
use function is_string;
@@ -194,9 +197,12 @@ private function deleteEntityCollection(PersistentCollection $collection): int
194197

195198
if ($targetClass->isInheritanceTypeSingleTable()) {
196199
$discriminatorColumn = $targetClass->getDiscriminatorColumn();
197-
$statement .= ' AND ' . $discriminatorColumn['name'] . ' = ?';
198-
$parameters[] = $targetClass->discriminatorValue;
199-
$types[] = $discriminatorColumn['type'];
200+
$discriminatorValues = $targetClass->discriminatorValue ? [$targetClass->discriminatorValue] : array_keys($targetClass->discriminatorMap);
201+
$statement .= ' AND ' . $discriminatorColumn['name'] . ' IN (' . implode(', ', array_fill(0, count($discriminatorValues), '?')) . ')';
202+
foreach ($discriminatorValues as $discriminatorValue) {
203+
$parameters[] = $discriminatorValue;
204+
$types[] = $discriminatorColumn['type'];
205+
}
200206
}
201207

202208
$numAffected = $this->conn->executeStatement($statement, $parameters, $types);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\ORM\Functional\Ticket;
6+
7+
use Doctrine\Common\Collections\ArrayCollection;
8+
use Doctrine\Common\Collections\Collection;
9+
use Doctrine\ORM\Exception\ORMException;
10+
use Doctrine\ORM\Mapping as ORM;
11+
use Doctrine\Tests\OrmFunctionalTestCase;
12+
13+
class GH11501Test extends OrmFunctionalTestCase
14+
{
15+
protected function setUp(): void
16+
{
17+
parent::setUp();
18+
19+
$this->setUpEntitySchema([
20+
GH11501AbstractTestEntity::class,
21+
GH11501TestEntityOne::class,
22+
GH11501TestEntityTwo::class,
23+
GH11501TestEntityHolder::class,
24+
]);
25+
}
26+
27+
/**
28+
* @throws ORMException
29+
*/
30+
public function testDeleteOneToManyCollectionWithSingleTableInheritance(): void
31+
{
32+
$testEntityOne = new GH11501TestEntityOne();
33+
$testEntityTwo = new GH11501TestEntityTwo();
34+
$testEntityHolder = new GH11501TestEntityHolder();
35+
36+
$testEntityOne->testEntityHolder = $testEntityHolder;
37+
$testEntityHolder->testEntities->add($testEntityOne);
38+
39+
$testEntityTwo->testEntityHolder = $testEntityHolder;
40+
$testEntityHolder->testEntities->add($testEntityTwo);
41+
42+
$em = $this->getEntityManager();
43+
$em->persist($testEntityOne);
44+
$em->persist($testEntityTwo);
45+
$em->persist($testEntityHolder);
46+
$em->flush();
47+
48+
$testEntityHolder->testEntities = new ArrayCollection();
49+
$em->persist($testEntityHolder);
50+
$em->flush();
51+
$em->refresh($testEntityHolder);
52+
53+
static::assertEmpty($testEntityHolder->testEntities->toArray(), 'All records should have been deleted');
54+
}
55+
}
56+
57+
58+
59+
/**
60+
* @ORM\Entity
61+
* @ORM\Table(name="one_to_many_single_table_inheritance_test_entities_parent_join")
62+
* @ORM\InheritanceType("SINGLE_TABLE")
63+
* @ORM\DiscriminatorColumn(name="type", type="string")
64+
* @ORM\DiscriminatorMap({"test_entity_one"="GH11501TestEntityOne", "test_entity_two"="GH11501TestEntityTwo"})
65+
*/
66+
class GH11501AbstractTestEntity
67+
{
68+
/**
69+
* @ORM\Id
70+
* @ORM\Column(type="integer")
71+
* @ORM\GeneratedValue
72+
*
73+
* @var int
74+
*/
75+
public $id;
76+
77+
/**
78+
* @ORM\ManyToOne(targetEntity="GH11501TestEntityHolder", inversedBy="testEntities")
79+
* @ORM\JoinColumn(name="test_entity_holder_id", referencedColumnName="id")
80+
*
81+
* @var GH11501TestEntityHolder
82+
*/
83+
public $testEntityHolder;
84+
}
85+
86+
87+
/** @ORM\Entity */
88+
class GH11501TestEntityOne extends GH11501AbstractTestEntity
89+
{
90+
}
91+
92+
/** @ORM\Entity */
93+
class GH11501TestEntityTwo extends GH11501AbstractTestEntity
94+
{
95+
}
96+
97+
/** @ORM\Entity */
98+
class GH11501TestEntityHolder
99+
{
100+
/**
101+
* @ORM\Id
102+
* @ORM\Column(type="integer")
103+
* @ORM\GeneratedValue
104+
*
105+
* @var int
106+
*/
107+
public $id;
108+
109+
/**
110+
* @ORM\OneToMany(targetEntity="GH11501AbstractTestEntity", mappedBy="testEntityHolder", orphanRemoval=true)
111+
*
112+
* @var Collection
113+
*/
114+
public $testEntities;
115+
116+
public function __construct()
117+
{
118+
$this->testEntities = new ArrayCollection();
119+
}
120+
}

0 commit comments

Comments
 (0)