Skip to content

Commit

Permalink
Fix UnitOfWork->originalEntityData is missing not-modified collection…
Browse files Browse the repository at this point in the history
…s after computeChangeSet (#9301)

* Fix original data incomplete after flush

* Apply suggestions from code review

Co-authored-by: Alexander M. Turek <me@derrabus.de>

---------

Co-authored-by: Alexander M. Turek <me@derrabus.de>
  • Loading branch information
olsavmic and derrabus authored Aug 2, 2023
1 parent eeefc6b commit f50803c
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/Doctrine/ORM/UnitOfWork.php
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,7 @@ public function computeChangeSet(ClassMetadata $class, $entity)
if ($class->isCollectionValuedAssociation($name) && $value !== null) {
if ($value instanceof PersistentCollection) {
if ($value->getOwner() === $entity) {
$actualData[$name] = $value;
continue;
}

Expand Down
44 changes: 44 additions & 0 deletions tests/Doctrine/Tests/Models/Issue9300/Issue9300Child.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\Models\Issue9300;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\ManyToMany;

/**
* @Entity
*/
class Issue9300Child
{
/**
* @var int
* @Id
* @Column(type="integer")
* @GeneratedValue
*/
public $id;

/**
* @var Collection<int, Issue9300Parent>
* @ManyToMany(targetEntity="Issue9300Parent")
*/
public $parents;

/**
* @var string
* @Column(type="string")
*/
public $name;

public function __construct()
{
$this->parents = new ArrayCollection();
}
}
30 changes: 30 additions & 0 deletions tests/Doctrine/Tests/Models/Issue9300/Issue9300Parent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\Models\Issue9300;

use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;

/**
* @Entity
*/
class Issue9300Parent
{
/**
* @var int
* @Id
* @Column(type="integer")
* @GeneratedValue
*/
public $id;

/**
* @var string
* @Column(type="string")
*/
public $name;
}
80 changes: 80 additions & 0 deletions tests/Doctrine/Tests/ORM/Functional/Ticket/Issue9300Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Tests\Models\Issue9300\Issue9300Child;
use Doctrine\Tests\Models\Issue9300\Issue9300Parent;
use Doctrine\Tests\OrmFunctionalTestCase;

/**
* @group GH-9300
*/
class Issue9300Test extends OrmFunctionalTestCase
{
protected function setUp(): void
{
$this->useModelSet('issue9300');

parent::setUp();
}

/**
* @group GH-9300
*/
public function testPersistedCollectionIsPresentInOriginalDataAfterFlush(): void
{
$parent = new Issue9300Parent();
$child = new Issue9300Child();
$child->parents->add($parent);

$parent->name = 'abc';
$child->name = 'abc';

$this->_em->persist($parent);
$this->_em->persist($child);
$this->_em->flush();

$parent->name = 'abcd';
$child->name = 'abcd';

$this->_em->flush();

self::assertArrayHasKey('parents', $this->_em->getUnitOfWork()->getOriginalEntityData($child));
}

/**
* @group GH-9300
*/
public function testPersistingCollectionAfterFlushWorksAsExpected(): void
{
$parentOne = new Issue9300Parent();
$parentTwo = new Issue9300Parent();
$childOne = new Issue9300Child();

$parentOne->name = 'abc';
$parentTwo->name = 'abc';
$childOne->name = 'abc';
$childOne->parents = new ArrayCollection([$parentOne]);

$this->_em->persist($parentOne);
$this->_em->persist($parentTwo);
$this->_em->persist($childOne);
$this->_em->flush();

// Recalculate change-set -> new original data
$childOne->name = 'abcd';
$this->_em->flush();

$childOne->parents = new ArrayCollection([$parentTwo]);

$this->_em->flush();
$this->_em->clear();

$childOneFresh = $this->_em->find(Issue9300Child::class, $childOne->id);
self::assertCount(1, $childOneFresh->parents);
self::assertEquals($parentTwo->id, $childOneFresh->parents[0]->id);
}
}
4 changes: 4 additions & 0 deletions tests/Doctrine/Tests/OrmFunctionalTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,10 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
Models\Issue5989\Issue5989Employee::class,
Models\Issue5989\Issue5989Manager::class,
],
'issue9300' => [
Models\Issue9300\Issue9300Child::class,
Models\Issue9300\Issue9300Parent::class,
],
];

/** @param class-string ...$models */
Expand Down

0 comments on commit f50803c

Please sign in to comment.