em->getConnection(); $conn->beginTransaction(); 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; } } private function transferWorkflowsSQL(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): array { $queries = []; $queries[] = [ 'sql' => "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; } private function generateStartDateSQL(AccompanyingPeriodWork $toDelete, AccompanyingPeriodWork $toKeep): array { $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; } private function generateEndDateSQL(AccompanyingPeriodWork $toDelete, AccompanyingPeriodWork $toKeep): array { $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()], ]; 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 $queries; } public function removeAccompanyingPeriodWork(AccompanyingPeriodWork $toDelete): array { return [[ 'sql' => 'DELETE FROM chill_person_accompanying_period_work WHERE id = :toDelete', 'params' => ['toDelete' => $toDelete->getId()], ]]; } }