Skip to content

Commit 7a8674b

Browse files
authored
Merge pull request #2226 from paxal/fix/doctrine_deferred_explicit_2.3
Persist doctrine entities with DEFERRED_EXPLICIT change tracking policy
2 parents ea4a64c + 9823253 commit 7a8674b

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

src/Bridge/Doctrine/Common/DataPersister.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use ApiPlatform\Core\Util\ClassInfoTrait;
1818
use Doctrine\Common\Persistence\ManagerRegistry;
1919
use Doctrine\Common\Persistence\ObjectManager as DoctrineObjectManager;
20+
use Doctrine\ORM\Mapping\ClassMetadataInfo;
2021

2122
/**
2223
* Data persister for Doctrine.
@@ -51,7 +52,7 @@ public function persist($data)
5152
return $data;
5253
}
5354

54-
if (!$manager->contains($data)) {
55+
if (!$manager->contains($data) || $this->isDeferredExplicit($manager, $data)) {
5556
$manager->persist($data);
5657
}
5758

@@ -84,4 +85,19 @@ private function getManager($data)
8485
{
8586
return \is_object($data) ? $this->managerRegistry->getManagerForClass($this->getObjectClass($data)) : null;
8687
}
88+
89+
/**
90+
* Checks if doctrine does not manage data automatically.
91+
*
92+
* @return bool
93+
*/
94+
private function isDeferredExplicit(DoctrineObjectManager $manager, $data)
95+
{
96+
$classMetadata = $manager->getClassMetadata($this->getObjectClass($data));
97+
if ($classMetadata instanceof ClassMetadataInfo && \method_exists($classMetadata, 'isChangeTrackingDeferredExplicit')) {
98+
return $classMetadata->isChangeTrackingDeferredExplicit();
99+
}
100+
101+
return false;
102+
}
87103
}

tests/Bridge/Doctrine/Common/DataPersisterTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy;
1919
use Doctrine\Common\Persistence\ManagerRegistry;
2020
use Doctrine\Common\Persistence\ObjectManager;
21+
use Doctrine\ORM\Mapping\ClassMetadataInfo;
2122
use PHPUnit\Framework\TestCase;
23+
use Prophecy\Prediction\CallPrediction;
24+
use Prophecy\Prediction\NoCallsPrediction;
2225

2326
/**
2427
* @author Baptiste Meyer <[email protected]>
@@ -69,6 +72,7 @@ public function testPersistIfEntityAlreadyManaged()
6972
$objectManagerProphecy->persist($dummy)->shouldNotBeCalled();
7073
$objectManagerProphecy->flush()->shouldBeCalled();
7174
$objectManagerProphecy->refresh($dummy)->shouldBeCalled();
75+
$objectManagerProphecy->getClassMetadata(Dummy::class)->willReturn(null)->shouldBeCalled();
7276

7377
$managerRegistryProphecy = $this->prophesize(ManagerRegistry::class);
7478
$managerRegistryProphecy->getManagerForClass(Dummy::class)->willReturn($objectManagerProphecy->reveal())->shouldBeCalled();
@@ -109,4 +113,36 @@ public function testRemoveWithNullManager()
109113

110114
(new DataPersister($managerRegistryProphecy->reveal()))->remove(new Dummy());
111115
}
116+
117+
public function getTrackingPolicyParameters()
118+
{
119+
return [
120+
'deferred explicit' => [true, true],
121+
'deferred implicit' => [false, false],
122+
];
123+
}
124+
125+
/**
126+
* @dataProvider getTrackingPolicyParameters
127+
*/
128+
public function testTrackingPolicy($deferredExplicit, $persisted)
129+
{
130+
$dummy = new Dummy();
131+
132+
$classMetadataInfo = $this->prophesize(ClassMetadataInfo::class);
133+
$classMetadataInfo->isChangeTrackingDeferredExplicit()->willReturn($deferredExplicit)->shouldBeCalled();
134+
135+
$objectManagerProphecy = $this->prophesize(ObjectManager::class);
136+
$objectManagerProphecy->getClassMetadata(Dummy::class)->willReturn($classMetadataInfo)->shouldBeCalled();
137+
$objectManagerProphecy->contains($dummy)->willReturn(true);
138+
$objectManagerProphecy->persist($dummy)->should($persisted ? new CallPrediction() : new NoCallsPrediction());
139+
$objectManagerProphecy->flush()->shouldBeCalled();
140+
$objectManagerProphecy->refresh($dummy)->shouldBeCalled();
141+
142+
$managerRegistryProphecy = $this->prophesize(ManagerRegistry::class);
143+
$managerRegistryProphecy->getManagerForClass(Dummy::class)->willReturn($objectManagerProphecy)->shouldBeCalled();
144+
145+
$result = (new DataPersister($managerRegistryProphecy->reveal()))->persist($dummy);
146+
$this->assertSame($dummy, $result);
147+
}
112148
}

0 commit comments

Comments
 (0)