From a54fd9b8fca834d72c2b293802d88f93bb99687c Mon Sep 17 00:00:00 2001 From: Jan Jakes Date: Thu, 30 Nov 2023 15:09:38 +0100 Subject: [PATCH] Replace deprecated UnitOfWork::clear($entityClassName) with a more granular refresh We removed EntityManager::clear($entityClassName) already, but this one is deprecated as well: https://github.com/doctrine/orm/blob/212edaa80bf0669da6ccd7b4697d696e1ffceac8/lib/Doctrine/ORM/UnitOfWork.php#L2762 [MAILPOET-5745] --- mailpoet/lib/Settings/SettingsRepository.php | 19 +++++-- .../Settings/SettingsRepositoryTest.php | 49 +++++++++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 mailpoet/tests/integration/Settings/SettingsRepositoryTest.php diff --git a/mailpoet/lib/Settings/SettingsRepository.php b/mailpoet/lib/Settings/SettingsRepository.php index 7002faa234..24b7e11350 100644 --- a/mailpoet/lib/Settings/SettingsRepository.php +++ b/mailpoet/lib/Settings/SettingsRepository.php @@ -6,13 +6,22 @@ use MailPoet\Doctrine\Repository; use MailPoet\Entities\SettingEntity; use MailPoet\WP\Functions as WPFunctions; use MailPoetVendor\Carbon\Carbon; +use MailPoetVendor\Doctrine\ORM\Query; /** * @extends Repository */ class SettingsRepository extends Repository { - public function findOneByName($name) { - return $this->doctrineRepository->findOneBy(['name' => $name]); + public function findOneByName(string $name): ?SettingEntity { + // Always fetch fresh entity data (= don't use "findOneBy()"). See also further below. + $result = (array)$this->doctrineRepository->createQueryBuilder('s') + ->where('s.name = :name') + ->setParameter('name', $name) + ->getQuery() + ->setHint(Query::HINT_REFRESH, true) + ->getResult(); + + return isset($result[0]) && $result[0] instanceof SettingEntity ? $result[0] : null; } public function createOrUpdateByName($name, $value) { @@ -30,7 +39,11 @@ class SettingsRepository extends Repository { 'value' => is_array($value) ? serialize($value) : $value, 'now' => $now, ]); - $this->entityManager->getUnitOfWork()->clear(SettingEntity::class); + + // Ensure entity data is up-to-date in memory. + // - We can't use "refresh()"; we don't have the entity instance, and it can be a new record. + // - We can't use "findOneBy()"; it could return a cached entity instance. + $this->findOneByName($name); } protected function getEntityClassName() { diff --git a/mailpoet/tests/integration/Settings/SettingsRepositoryTest.php b/mailpoet/tests/integration/Settings/SettingsRepositoryTest.php new file mode 100644 index 0000000000..290d3fd53d --- /dev/null +++ b/mailpoet/tests/integration/Settings/SettingsRepositoryTest.php @@ -0,0 +1,49 @@ +diContainer->get(SettingsRepository::class); + + $setting = new SettingEntity(); + $setting->setName('name'); + $setting->setValue('value'); + $this->entityManager->persist($setting); + $this->entityManager->flush(); + + $this->assertSame('value', $setting->getValue()); + $this->entityManager->createQueryBuilder() + ->update(SettingEntity::class, 's') + ->set('s.value', ':value') + ->where('s.name = :name') + ->setParameter('value', 'new value') + ->setParameter('name', 'name') + ->getQuery() + ->execute(); + $this->assertSame('value', $setting->getValue()); + + $newSetting = $repository->findOneByName('name'); + $this->assertSame($setting, $newSetting); + $this->assertSame('new value', $setting->getValue()); + $this->assertSame('new value', $newSetting->getValue()); + } + + public function testUpdateRefreshesExistingData(): void { + $repository = $this->diContainer->get(SettingsRepository::class); + + $setting = new SettingEntity(); + $setting->setName('name'); + $setting->setValue('value'); + $this->entityManager->persist($setting); + $this->entityManager->flush(); + + $this->assertSame('value', $setting->getValue()); + $repository->createOrUpdateByName('name', 'new value'); + $this->assertSame('new value', $setting->getValue()); + } +}