From a562690512ab7ddf1dac79eadb1ec5dd37408d79 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Tue, 4 Feb 2025 18:37:03 +0100 Subject: [PATCH] Create thirdparty merge manager --- .../ThirdpartyMergeManager.php | 125 ++++++++++++++++++ .../ChillThirdPartyExtension.php | 1 + .../config/services/actions.yaml | 6 + 3 files changed, 132 insertions(+) create mode 100644 src/Bundle/ChillThirdPartyBundle/Actions/MergeThirdparty/ThirdpartyMergeManager.php create mode 100644 src/Bundle/ChillThirdPartyBundle/config/services/actions.yaml diff --git a/src/Bundle/ChillThirdPartyBundle/Actions/MergeThirdparty/ThirdpartyMergeManager.php b/src/Bundle/ChillThirdPartyBundle/Actions/MergeThirdparty/ThirdpartyMergeManager.php new file mode 100644 index 000000000..941288367 --- /dev/null +++ b/src/Bundle/ChillThirdPartyBundle/Actions/MergeThirdparty/ThirdpartyMergeManager.php @@ -0,0 +1,125 @@ +transferData($toKeep, $toDelete); + + // Update linked entities + $this->updateReferences($toKeep, $toDelete); + + $this->em->remove($toDelete); + $this->em->flush(); + } + + private function transferData(ThirdParty $toKeep, ThirdParty $toDelete): void + { + $excludedProperties = ['id', 'createdAt']; + $reflection = new \ReflectionClass(ThirdParty::class); + + foreach ($reflection->getProperties() as $property) { + if (in_array($property->getName(), $excludedProperties, true)) { + continue; + } + + $toKeepValue = $property->getValue($toKeep); + $toDeleteValue = $property->getValue($toDelete); + + if (null === $toKeepValue && null !== $toDeleteValue) { + $property->setValue($toKeep, $toDeleteValue); + } + + if ($toKeepValue instanceof \Doctrine\Common\Collections\Collection + && $toDeleteValue instanceof \Doctrine\Common\Collections\Collection) { + foreach ($toDeleteValue as $item) { + if (!$toKeepValue->contains($item)) { + $toKeepValue->add($item); + } + } + } + } + } + + private function updateReferences(ThirdParty $toKeep, ThirdParty $toDelete): void + { + $allMeta = $this->em->getMetadataFactory()->getAllMetadata(); + + foreach ($allMeta as $meta) { + foreach ($meta->getAssociationMappings() as $assoc) { + if (ThirdParty::class !== $assoc['targetEntity']) { + continue; // Skip unrelated associations + } + + $entityClass = $meta->getName(); + $associationField = $assoc['fieldName']; + + if ($assoc['type'] & \Doctrine\ORM\Mapping\ClassMetadata::TO_ONE) { + // Handle ManyToOne or OneToOne + $qb = $this->em->createQueryBuilder(); + $qb->update($entityClass, 'e') + ->set("e.{$associationField}", ':toKeep') + ->where("e.{$associationField} = :toDelete") + ->setParameter('toKeep', $toKeep) + ->setParameter('toDelete', $toDelete) + ->getQuery() + ->execute(); + } + + if ($assoc['type'] & \Doctrine\ORM\Mapping\ClassMetadata::TO_MANY) { + // Handle ManyToMany or OneToMany (inverse side) + $repo = $this->em->getRepository($entityClass); + $linkedEntities = $repo->createQueryBuilder('e') + ->join("e.{$associationField}", 't') + ->where('t = :toDelete') + ->setParameter('toDelete', $toDelete) + ->getQuery() + ->getResult(); + + foreach ($linkedEntities as $entity) { + $getter = 'get'.ucfirst($associationField); + $setter = 'set'.ucfirst($associationField); + $adder = 'add'.ucfirst(rtrim($associationField, 's')); + $remover = 'remove'.ucfirst(rtrim($associationField, 's')); + + if (method_exists($entity, $getter) && method_exists($entity, $setter)) { + // For OneToMany owning side + $collection = $entity->{$getter}(); + if ($collection->contains($toDelete)) { + $collection->removeElement($toDelete); + if (!$collection->contains($toKeep)) { + $collection->add($toKeep); + } + } + } elseif (method_exists($entity, $adder) && method_exists($entity, $remover)) { + // For ManyToMany + $entity->{$remover}($toDelete); + $entity->{$adder}($toKeep); + } + + $this->em->persist($entity); + } + } + } + } + + $this->em->flush(); + } +} diff --git a/src/Bundle/ChillThirdPartyBundle/DependencyInjection/ChillThirdPartyExtension.php b/src/Bundle/ChillThirdPartyBundle/DependencyInjection/ChillThirdPartyExtension.php index 475d22049..e12807819 100644 --- a/src/Bundle/ChillThirdPartyBundle/DependencyInjection/ChillThirdPartyExtension.php +++ b/src/Bundle/ChillThirdPartyBundle/DependencyInjection/ChillThirdPartyExtension.php @@ -51,6 +51,7 @@ class ChillThirdPartyExtension extends Extension implements PrependExtensionInte $loader->load('services/serializer.yaml'); $loader->load('services/repository.yaml'); $loader->load('services/doctrineEventListener.yaml'); + $loader->load('services/actions.yaml'); } public function prepend(ContainerBuilder $container) diff --git a/src/Bundle/ChillThirdPartyBundle/config/services/actions.yaml b/src/Bundle/ChillThirdPartyBundle/config/services/actions.yaml new file mode 100644 index 000000000..e65ed6600 --- /dev/null +++ b/src/Bundle/ChillThirdPartyBundle/config/services/actions.yaml @@ -0,0 +1,6 @@ +services: + _defaults: + autowire: true + autoconfigure: true + + Chill\ThirdPartyBundle\Actions\MergeThirdparty\ThirdpartyMergeManager: ~