From 076ee6d5de2446f343f44e46b14fe4a647aa233b Mon Sep 17 00:00:00 2001 From: Jan Jakes Date: Tue, 28 Nov 2023 15:59:27 +0100 Subject: [PATCH] Add a helper method to detach all (or some) entities of a given class from entity manager [MAILPOET-5745] --- mailpoet/lib/Doctrine/Repository.php | 18 ++++ .../integration/Doctrine/RepositoryTest.php | 84 +++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 mailpoet/tests/integration/Doctrine/RepositoryTest.php diff --git a/mailpoet/lib/Doctrine/Repository.php b/mailpoet/lib/Doctrine/Repository.php index 39fa04fb60..3486a01a62 100644 --- a/mailpoet/lib/Doctrine/Repository.php +++ b/mailpoet/lib/Doctrine/Repository.php @@ -126,6 +126,24 @@ abstract class Repository { $this->entityManager->detach($entity); } + /** + * @param callable(T): bool|null $filter + */ + public function detachAll(callable $filter = null): void { + $className = $this->getEntityClassName(); + $rootClassName = $this->entityManager->getClassMetadata($className)->rootEntityName; + $entities = $this->entityManager->getUnitOfWork()->getIdentityMap()[$rootClassName] ?? []; + foreach ($entities as $entity) { + if (!($entity instanceof $className)) { + continue; + } + if ($filter && !$filter($entity)) { + continue; + } + $this->entityManager->detach($entity); + } + } + /** * @return class-string */ diff --git a/mailpoet/tests/integration/Doctrine/RepositoryTest.php b/mailpoet/tests/integration/Doctrine/RepositoryTest.php new file mode 100644 index 0000000000..48f5a34e70 --- /dev/null +++ b/mailpoet/tests/integration/Doctrine/RepositoryTest.php @@ -0,0 +1,84 @@ +createRepository(); + + $setting = new SettingEntity(); + $setting->setName('name'); + $setting->setValue('value'); + $repository->persist($setting); + $repository->flush(); + + $this->assertSame($this->getEntityFromIdentityMap($setting->getId()), $setting); + } + + public function testItCanDetachAll(): void { + $repository = $this->createRepository(); + + $setting1 = $this->createSetting('name-1', 'value-1'); + $setting2 = $this->createSetting('name-2', 'value-2'); + $setting3 = $this->createSetting('name-3', 'value-3'); + + $this->assertSame($this->getEntityFromIdentityMap($setting1->getId()), $setting1); + $this->assertSame($this->getEntityFromIdentityMap($setting2->getId()), $setting2); + $this->assertSame($this->getEntityFromIdentityMap($setting3->getId()), $setting3); + + $repository->detachAll(); + + $this->assertNull($this->getEntityFromIdentityMap($setting1->getId())); + $this->assertNull($this->getEntityFromIdentityMap($setting2->getId())); + $this->assertNull($this->getEntityFromIdentityMap($setting3->getId())); + } + + public function testItCanDetachSelectively(): void { + $repository = $this->createRepository(); + + $setting1 = $this->createSetting('name-1', 'value-1'); + $setting2 = $this->createSetting('name-2', 'value-2'); + $setting3 = $this->createSetting('name-3', 'value-3'); + + $this->assertSame($this->getEntityFromIdentityMap($setting1->getId()), $setting1); + $this->assertSame($this->getEntityFromIdentityMap($setting2->getId()), $setting2); + $this->assertSame($this->getEntityFromIdentityMap($setting3->getId()), $setting3); + + $repository->detachAll(function (SettingEntity $setting) use ($setting1, $setting3) { + return !in_array($setting->getId(), [$setting1->getId(), $setting3->getId()], true); + }); + + $this->assertSame($this->getEntityFromIdentityMap($setting1->getId()), $setting1); + $this->assertNull($this->getEntityFromIdentityMap($setting2->getId())); + $this->assertSame($this->getEntityFromIdentityMap($setting3->getId()), $setting3); + } + + private function createSetting(string $name, string $value): SettingEntity { + $setting = new SettingEntity(); + $setting->setName($name); + $setting->setValue($value); + $this->entityManager->persist($setting); + $this->entityManager->flush(); + return $setting; + } + + /** @return Repository */ + private function createRepository(): Repository { + /** @var Repository $repository */ + $repository = new class($this->entityManager) extends Repository { + protected function getEntityClassName(): string { + return SettingEntity::class; + } + }; + return $repository; + } + + private function getEntityFromIdentityMap(?int $id): ?SettingEntity { + /** @var SettingEntity|false $entity */ + $entity = $this->entityManager->getUnitOfWork()->tryGetById($id, SettingEntity::class); + return $entity ?: null; + } +}