This commit is contained in:
2025-04-15 14:02:25 +02:00
parent 0581b59dbd
commit 7e2bf91e09
18 changed files with 430 additions and 224 deletions

View File

@@ -12,202 +12,93 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Service\AccompanyingPeriodWork;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkReferrerHistory;
use Doctrine\DBAL\Exception;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
/**
* Service for merging two AccompanyingPeriodWork entities into a single entity.
*/
class AccompanyingPeriodWorkMergeService
{
public function __construct(private readonly EntityManagerInterface $em) {}
/**
* @throws Exception
* Merges two AccompanyingPeriodWork entities into one by transferring relevant data and removing the obsolete entity.
*
* @param AccompanyingPeriodWork $toKeep the entity to retain after the merge
* @param AccompanyingPeriodWork $toDelete the entity to be removed after transferring data
*
* @return AccompanyingPeriodWork the kept accompanying period work
*/
public function merge(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): void
public function merge(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): AccompanyingPeriodWork
{
$conn = $this->em->getConnection();
$conn->beginTransaction();
$this->em->wrapInTransaction(function (EntityManagerInterface $entityManager) use ($toKeep, $toDelete) {
$this->alterStartDate($toKeep, $toDelete);
$this->alterEndDate($toKeep, $toDelete);
$this->concatenateComments($toKeep, $toDelete);
$this->transferWorkflowsSQL($toKeep, $toDelete);
$this->updateReferencesSQL($toKeep, $toDelete);
$entityManager->remove($toDelete);
});
try {
$queries = array_merge(
$this->updateReferencesSQL($toKeep, $toDelete),
$this->transferWorkflowsSQL($toKeep, $toDelete),
$this->generateStartDateSQL($toDelete, $toKeep),
$this->generateEndDateSQL($toDelete, $toKeep),
$this->generateCommentSQL($toDelete, $toKeep),
$this->removeAccompanyingPeriodWork($toDelete)
);
foreach ($queries as $query) {
dump($query);
$conn->executeStatement($query['sql'], $query['params']);
}
$conn->commit();
} catch (\Exception $e) {
dump($e->getMessage());
$conn->rollBack();
throw $e;
}
return $toKeep;
}
private function transferWorkflowsSQL(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): array
private function transferWorkflowsSQL(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): void
{
$queries = [];
$queries[] = [
'sql' => "UPDATE chill_main_workflow_entity w
$this->em->getConnection()->executeQuery(
"UPDATE chill_main_workflow_entity w
SET relatedentityid = :toKeepId
WHERE w.relatedentityid = :toDeleteId
AND w.relatedentityclass = 'Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork'",
'params' => ['toKeepId' => $toKeep->getId(), 'toDeleteId' => $toDelete->getId()],
];
return $queries;
['toKeepId' => $toKeep->getId(), 'toDeleteId' => $toDelete->getId()]
);
}
private function generateStartDateSQL(AccompanyingPeriodWork $toDelete, AccompanyingPeriodWork $toKeep): array
private function alterStartDate(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): void
{
$queries = [];
$queries[] = [
'sql' => 'UPDATE chill_person_accompanying_period_work
SET startdate = LEAST(
COALESCE((SELECT startdate FROM chill_person_accompanying_period_work WHERE id = :toDelete), startdate),
startdate
)
WHERE id = :toKeep',
'params' => ['toDelete' => $toDelete->getId(), 'toKeep' => $toKeep->getId()],
];
return $queries;
$startDate = min($toKeep->getStartDate(), $toDelete->getStartDate());
$toKeep->setStartDate($startDate);
}
private function generateEndDateSQL(AccompanyingPeriodWork $toDelete, AccompanyingPeriodWork $toKeep): array
private function alterEndDate(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): void
{
$queries = [];
$queries[] = [
'sql' => '
UPDATE chill_person_accompanying_period_work
SET enddate =
CASE
WHEN (SELECT enddate FROM chill_person_accompanying_period_work WHERE id = :toDelete) IS NULL
OR enddate IS NULL
THEN NULL
ELSE GREATEST(
COALESCE((SELECT enddate FROM chill_person_accompanying_period_work WHERE id = :toDelete), enddate),
enddate
)
END
WHERE id = :toKeep',
'params' => ['toDelete' => $toDelete->getId(), 'toKeep' => $toKeep->getId()],
if (null === $toKeep->getEndDate() || null === $toDelete->getEndDate()) {
$toKeep->setEndDate(null);
];
return $queries;
}
private function generateCommentSQL(AccompanyingPeriodWork $toDelete, AccompanyingPeriodWork $toKeep): array
{
$queries = [];
$queries[] = [
'sql' => "WITH updated_values AS (
SELECT
acpw1.id AS to_update,
acpw1.note || ' ' || acpw2.note AS new_note,
jsonb_set(
acpw1.privatecomment_comments::jsonb,
'{1}',
to_jsonb((acpw1.privatecomment_comments::jsonb->>'1') || ' ' || (acpw2.privatecomment_comments::jsonb->>'1'))
) AS new_privatecomment_comments
FROM
chill_person_accompanying_period_work acpw1,
chill_person_accompanying_period_work acpw2
WHERE
acpw1.id = :toKeep AND
acpw2.id = :toDelete
)
UPDATE chill_person_accompanying_period_work
SET
note = updated_values.new_note,
privatecomment_comments = updated_values.new_privatecomment_comments
FROM
updated_values
WHERE
chill_person_accompanying_period_work.id = updated_values.to_update",
'params' => ['toDelete' => $toDelete->getId(), 'toKeep' => $toKeep->getId()],
];
return $queries;
}
private function updateReferencesSQL(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): array
{
$queries = [];
$allMeta = $this->em->getMetadataFactory()->getAllMetadata();
foreach ($allMeta as $meta) {
if ($meta->isMappedSuperclass) {
continue;
}
$tableName = $meta->getTableName();
foreach ($meta->getAssociationMappings() as $assoc) {
if (AccompanyingPeriodWork::class !== $assoc['targetEntity'] && AccompanyingPeriodWork::class !== $assoc['sourceEntity']) {
continue;
}
if (($assoc['type'] & ClassMetadata::TO_ONE) !== 0) {
$joinColumn = $meta->getSingleAssociationJoinColumnName($assoc['fieldName']);
if (AccompanyingPeriodWorkReferrerHistory::class === $assoc['sourceEntity']) {
$queries[] = [
'sql' => "DELETE FROM {$tableName} WHERE {$joinColumn} = :toDelete",
'params' => ['toKeep' => $toKeep->getId(), 'toDelete' => $toDelete->getId()],
];
}
$queries[] = [
'sql' => "UPDATE {$tableName} SET {$joinColumn} = :toKeep WHERE {$joinColumn} = :toDelete",
'params' => ['toKeep' => $toKeep->getId(), 'toDelete' => $toDelete->getId()],
];
} elseif (8 === $assoc['type'] && isset($assoc['joinTable'])) {
if ($assoc['isOwningSide']) {
dump($assoc);
$joinTable = $assoc['joinTable']['name'];
$joinColumn = $assoc['joinTable']['joinColumns'][0]['name'];
$relationColumn = $assoc['joinTable']['inverseJoinColumns'][0]['name'];
$queries[] = [
'sql' => "
UPDATE {$joinTable} SET {$joinColumn} = :toKeep
WHERE {$joinColumn} = :toDelete
AND NOT EXISTS (
SELECT 1
FROM {$joinTable} AS t2
WHERE t2.{$joinColumn} = :toKeep
AND t2.{$relationColumn} = {$joinTable}.{$relationColumn}
)
",
'params' => ['toDelete' => $toDelete->getId(), 'toKeep' => $toKeep->getId()],
];
$queries[] = [
'sql' => "DELETE FROM {$joinTable} WHERE {$joinColumn} = :toDelete",
'params' => ['toDelete' => $toDelete->getId()],
];
}
}
}
return;
}
return $queries;
$endDate = max($toKeep->getEndDate(), $toDelete->getEndDate());
$toKeep->setEndDate($endDate);
}
public function removeAccompanyingPeriodWork(AccompanyingPeriodWork $toDelete): array
private function concatenateComments(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): void
{
return [[
'sql' => 'DELETE FROM chill_person_accompanying_period_work WHERE id = :toDelete',
'params' => ['toDelete' => $toDelete->getId()],
]];
$toKeep->setNote($toKeep->getNote()."\n\n-----------------\n\n".$toDelete->getNote());
$toKeep->getPrivateComment()->concatenateComments($toDelete->getPrivateComment());
}
private function updateReferencesSQL(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): void
{
foreach ($toDelete->getAccompanyingPeriodWorkEvaluations() as $evaluation) {
$toKeep->addAccompanyingPeriodWorkEvaluation($evaluation);
}
foreach ($toDelete->getReferrers() as $referrer) {
// we only keep the current referrer
$toKeep->addReferrer($referrer);
}
foreach ($toDelete->getPersons() as $person) {
$toKeep->addPerson($person);
}
if (null === $toKeep->getHandlingThierParty()) {
$toKeep->setHandlingThierParty($toDelete->getHandlingThierParty());
}
foreach ($toDelete->getThirdParties() as $thirdParty) {
$toKeep->addThirdParty($thirdParty);
}
}
}