From e701e96187efffdb77e7a071dcf1e80db468e434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 14 Apr 2025 15:49:51 +0200 Subject: [PATCH] Fix merging: update the thirdparty related column and not the other one --- .../Service/ThirdpartyMergeService.php | 55 ++++++++++--------- .../Service/ThirdpartyMergeServiceTest.php | 12 +++- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/Bundle/ChillThirdPartyBundle/Service/ThirdpartyMergeService.php b/src/Bundle/ChillThirdPartyBundle/Service/ThirdpartyMergeService.php index 650065cc0..6c0014a2d 100644 --- a/src/Bundle/ChillThirdPartyBundle/Service/ThirdpartyMergeService.php +++ b/src/Bundle/ChillThirdPartyBundle/Service/ThirdpartyMergeService.php @@ -25,10 +25,10 @@ class ThirdpartyMergeService $conn->beginTransaction(); try { - $queries = array_merge( - $this->updateReferences($toKeep, $toDelete), - $this->removeThirdparty($toDelete) - ); + $queries = [ + ...$this->updateReferences($toKeep, $toDelete), + ...$this->removeThirdparty($toKeep, $toDelete), + ]; foreach ($queries as $query) { $conn->executeStatement($query['sql'], $query['params']); @@ -53,31 +53,26 @@ class ThirdpartyMergeService $tableName = $meta->getTableName(); foreach ($meta->getAssociationMappings() as $assoc) { - if (ThirdParty::class !== $assoc['targetEntity'] && ThirdParty::class !== $assoc['sourceEntity']) { + if (ThirdParty::class !== $assoc['targetEntity']) { continue; } + // phpstan wants boolean for if condition if (($assoc['type'] & ClassMetadata::TO_ONE) !== 0) { $joinColumn = $meta->getSingleAssociationJoinColumnName($assoc['fieldName']); $suffix = (ThirdParty::class === $assoc['sourceEntity']) ? 'chill_3party.' : ''; - if (ThirdParty::class === $assoc['sourceEntity'] && 'parent_id' === $joinColumn) { - $queries[] = [ - 'sql' => "UPDATE {$suffix}{$tableName} SET parent_id = (SELECT parent_id FROM chill_3party.third_party WHERE id = :toDelete) WHERE id = :toKeep", - 'params' => ['toKeep' => $toKeep->getId(), 'toDelete' => $toDelete->getId()], - ]; - } else { - $queries[] = [ - 'sql' => "UPDATE {$suffix}{$tableName} SET {$joinColumn} = :toKeep WHERE {$joinColumn} = :toDelete", - 'params' => ['toKeep' => $toKeep->getId(), 'toDelete' => $toDelete->getId()], - ]; - } - } elseif (8 === $assoc['type'] && isset($assoc['joinTable'])) { - $joinTable = $assoc['joinTable']['name']; - $joinColumn = $assoc['joinTable']['joinColumns'][0]['name']; $queries[] = [ - 'sql' => "UPDATE {$joinTable} SET {$joinColumn} = :toKeep WHERE {$joinColumn} = :toDelete AND NOT EXISTS (SELECT 1 FROM {$joinTable} WHERE {$joinColumn} = :toKeep)", + 'sql' => "UPDATE {$suffix}{$tableName} SET {$joinColumn} = :toKeep WHERE {$joinColumn} = :toDelete", + 'params' => ['toKeep' => $toKeep->getId(), 'toDelete' => $toDelete->getId()], + ]; + } elseif (ClassMetadata::MANY_TO_MANY === $assoc['type'] && isset($assoc['joinTable'])) { + $joinTable = $assoc['joinTable']['name']; + $prefix = null !== ($assoc['joinTable']['schema'] ?? null) ? $assoc['joinTable']['schema'].'.' : ''; + $joinColumn = $assoc['joinTable']['inverseJoinColumns'][0]['name']; + $queries[] = [ + 'sql' => "UPDATE {$prefix}{$joinTable} SET {$joinColumn} = :toKeep WHERE {$joinColumn} = :toDelete AND NOT EXISTS (SELECT 1 FROM {$prefix}{$joinTable} WHERE {$joinColumn} = :toKeep)", 'params' => ['toDelete' => $toDelete->getId(), 'toKeep' => $toKeep->getId()], ]; @@ -92,11 +87,21 @@ class ThirdpartyMergeService return $queries; } - public function removeThirdparty(ThirdParty $toDelete): array + public function removeThirdparty(ThirdParty $toKeep, ThirdParty $toDelete): array { - return [[ - 'sql' => 'DELETE FROM chill_3party.third_party WHERE id = :toDelete', - 'params' => ['toDelete' => $toDelete->getId()], - ]]; + return [ + [ + 'sql' => 'UPDATE chill_3party.third_party SET parent_id = :toKeep WHERE parent_id = :toDelete', + 'params' => ['toKeep' => $toKeep->getId(), 'toDelete' => $toDelete->getId()], + ], + [ + 'sql' => 'UPDATE chill_3party.thirdparty_category SET thirdparty_id = :toKeep WHERE thirdparty_id = :toDelete AND NOT EXISTS (SELECT 1 FROM chill_3party.thirdparty_category WHERE thirdparty_id = :toKeep)', + 'params' => ['toKeep' => $toKeep->getId(), 'toDelete' => $toDelete->getId()], + ], + [ + 'sql' => 'DELETE FROM chill_3party.third_party WHERE id = :toDelete', + 'params' => ['toDelete' => $toDelete->getId()], + ], + ]; } } diff --git a/src/Bundle/ChillThirdPartyBundle/Tests/Service/ThirdpartyMergeServiceTest.php b/src/Bundle/ChillThirdPartyBundle/Tests/Service/ThirdpartyMergeServiceTest.php index f25da94e9..4b2819751 100644 --- a/src/Bundle/ChillThirdPartyBundle/Tests/Service/ThirdpartyMergeServiceTest.php +++ b/src/Bundle/ChillThirdPartyBundle/Tests/Service/ThirdpartyMergeServiceTest.php @@ -11,6 +11,7 @@ declare(strict_types=1); namespace Chill\ThirdPartyBundle\Tests\Service; +use Chill\ActivityBundle\Entity\Activity; use Chill\ThirdPartyBundle\Entity\ThirdParty; use Chill\ThirdPartyBundle\Entity\ThirdPartyCategory; use Chill\ThirdPartyBundle\Service\ThirdpartyMergeService; @@ -49,9 +50,8 @@ class ThirdpartyMergeServiceTest extends KernelTestCase // Create a related entity with TO_ONE relation (thirdparty parent) $relatedToOneEntity = new ThirdParty(); $relatedToOneEntity->setName('RelatedToOne thirdparty'); + $relatedToOneEntity->setParent($toDelete); $this->em->persist($relatedToOneEntity); - $toDelete->setParent($relatedToOneEntity); - $this->em->persist($toDelete); // Create a related entity with TO_MANY relation (thirdparty category) $thirdpartyCategory = new ThirdPartyCategory(); @@ -60,14 +60,20 @@ class ThirdpartyMergeServiceTest extends KernelTestCase $toDelete->addCategory($thirdpartyCategory); $this->em->persist($toDelete); + $activity = new Activity(); + $activity->setDate(new \DateTime()); + $activity->addThirdParty($toDelete); + $this->em->persist($activity); + $this->em->flush(); // Run merge $this->service->merge($toKeep, $toDelete); $this->em->refresh($toKeep); + $this->em->refresh($relatedToOneEntity); // Check that references were updated - $this->assertEquals($toKeep->getParent()->getId(), $relatedToOneEntity->getId(), 'The parent thirdparty was succesfully merged'); + $this->assertEquals($toKeep->getId(), $relatedToOneEntity->getParent()->getId(), 'The parent thirdparty was succesfully merged'); $updatedRelatedManyEntity = $this->em->find(ThirdPartyCategory::class, $thirdpartyCategory->getId()); $this->assertContains($updatedRelatedManyEntity, $toKeep->getCategories(), 'The thirdparty category was found in the toKeep entity');