Skip to content

Commit f50803c

Browse files
olsavmicderrabus
andauthored
Fix UnitOfWork->originalEntityData is missing not-modified collections after computeChangeSet (#9301)
* Fix original data incomplete after flush * Apply suggestions from code review Co-authored-by: Alexander M. Turek <[email protected]> --------- Co-authored-by: Alexander M. Turek <[email protected]>
1 parent eeefc6b commit f50803c

File tree

5 files changed

+159
-0
lines changed

5 files changed

+159
-0
lines changed

lib/Doctrine/ORM/UnitOfWork.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,7 @@ public function computeChangeSet(ClassMetadata $class, $entity)
692692
if ($class->isCollectionValuedAssociation($name) && $value !== null) {
693693
if ($value instanceof PersistentCollection) {
694694
if ($value->getOwner() === $entity) {
695+
$actualData[$name] = $value;
695696
continue;
696697
}
697698

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\Models\Issue9300;
6+
7+
use Doctrine\Common\Collections\ArrayCollection;
8+
use Doctrine\Common\Collections\Collection;
9+
use Doctrine\ORM\Mapping\Column;
10+
use Doctrine\ORM\Mapping\Entity;
11+
use Doctrine\ORM\Mapping\GeneratedValue;
12+
use Doctrine\ORM\Mapping\Id;
13+
use Doctrine\ORM\Mapping\ManyToMany;
14+
15+
/**
16+
* @Entity
17+
*/
18+
class Issue9300Child
19+
{
20+
/**
21+
* @var int
22+
* @Id
23+
* @Column(type="integer")
24+
* @GeneratedValue
25+
*/
26+
public $id;
27+
28+
/**
29+
* @var Collection<int, Issue9300Parent>
30+
* @ManyToMany(targetEntity="Issue9300Parent")
31+
*/
32+
public $parents;
33+
34+
/**
35+
* @var string
36+
* @Column(type="string")
37+
*/
38+
public $name;
39+
40+
public function __construct()
41+
{
42+
$this->parents = new ArrayCollection();
43+
}
44+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\Models\Issue9300;
6+
7+
use Doctrine\ORM\Mapping\Column;
8+
use Doctrine\ORM\Mapping\Entity;
9+
use Doctrine\ORM\Mapping\GeneratedValue;
10+
use Doctrine\ORM\Mapping\Id;
11+
12+
/**
13+
* @Entity
14+
*/
15+
class Issue9300Parent
16+
{
17+
/**
18+
* @var int
19+
* @Id
20+
* @Column(type="integer")
21+
* @GeneratedValue
22+
*/
23+
public $id;
24+
25+
/**
26+
* @var string
27+
* @Column(type="string")
28+
*/
29+
public $name;
30+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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\Tests\Models\Issue9300\Issue9300Child;
9+
use Doctrine\Tests\Models\Issue9300\Issue9300Parent;
10+
use Doctrine\Tests\OrmFunctionalTestCase;
11+
12+
/**
13+
* @group GH-9300
14+
*/
15+
class Issue9300Test extends OrmFunctionalTestCase
16+
{
17+
protected function setUp(): void
18+
{
19+
$this->useModelSet('issue9300');
20+
21+
parent::setUp();
22+
}
23+
24+
/**
25+
* @group GH-9300
26+
*/
27+
public function testPersistedCollectionIsPresentInOriginalDataAfterFlush(): void
28+
{
29+
$parent = new Issue9300Parent();
30+
$child = new Issue9300Child();
31+
$child->parents->add($parent);
32+
33+
$parent->name = 'abc';
34+
$child->name = 'abc';
35+
36+
$this->_em->persist($parent);
37+
$this->_em->persist($child);
38+
$this->_em->flush();
39+
40+
$parent->name = 'abcd';
41+
$child->name = 'abcd';
42+
43+
$this->_em->flush();
44+
45+
self::assertArrayHasKey('parents', $this->_em->getUnitOfWork()->getOriginalEntityData($child));
46+
}
47+
48+
/**
49+
* @group GH-9300
50+
*/
51+
public function testPersistingCollectionAfterFlushWorksAsExpected(): void
52+
{
53+
$parentOne = new Issue9300Parent();
54+
$parentTwo = new Issue9300Parent();
55+
$childOne = new Issue9300Child();
56+
57+
$parentOne->name = 'abc';
58+
$parentTwo->name = 'abc';
59+
$childOne->name = 'abc';
60+
$childOne->parents = new ArrayCollection([$parentOne]);
61+
62+
$this->_em->persist($parentOne);
63+
$this->_em->persist($parentTwo);
64+
$this->_em->persist($childOne);
65+
$this->_em->flush();
66+
67+
// Recalculate change-set -> new original data
68+
$childOne->name = 'abcd';
69+
$this->_em->flush();
70+
71+
$childOne->parents = new ArrayCollection([$parentTwo]);
72+
73+
$this->_em->flush();
74+
$this->_em->clear();
75+
76+
$childOneFresh = $this->_em->find(Issue9300Child::class, $childOne->id);
77+
self::assertCount(1, $childOneFresh->parents);
78+
self::assertEquals($parentTwo->id, $childOneFresh->parents[0]->id);
79+
}
80+
}

tests/Doctrine/Tests/OrmFunctionalTestCase.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,10 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
338338
Models\Issue5989\Issue5989Employee::class,
339339
Models\Issue5989\Issue5989Manager::class,
340340
],
341+
'issue9300' => [
342+
Models\Issue9300\Issue9300Child::class,
343+
Models\Issue9300\Issue9300Parent::class,
344+
],
341345
];
342346

343347
/** @param class-string ...$models */

0 commit comments

Comments
 (0)