em->getConnection(); $conn->beginTransaction(); try { $queries = array_merge( $this->transferData($toKeep, $toDelete), $this->updateReferences($toKeep, $toDelete), $this->removeThirdparty($toDelete) ); foreach ($queries as $query) { $conn->executeStatement($query['sql'], $query['params']); } $conn->commit(); } catch (\Exception $e) { $conn->rollBack(); throw $e; } } /** * @throws Exception */ private function transferData(ThirdParty $toKeep, ThirdParty $toDelete): array { $queries = []; $columns = ['profession', 'firstname', 'name', 'email', 'telephone', 'comment', 'kind', 'contact_data_anonymous', 'types', 'active', 'name_company']; $metadata = $this->em->getClassMetadata(ThirdParty::class); foreach ($columns as $column) { $columnType = $metadata->getTypeOfField($column); $condition = ('string' === $columnType || 'text' === $columnType) ? "({$column} IS NULL OR {$column} = '')" : "{$column} IS NULL"; $queries[] = [ 'sql' => " UPDATE chill_3party.third_party SET {$column} = COALESCE((SELECT {$column} FROM chill_3party.third_party WHERE id = :toDelete), {$column}) WHERE id = :toKeep AND {$condition}", 'params' => ['toDelete' => $toDelete->getId(), 'toKeep' => $toKeep->getId()], ]; } return $queries; } private function updateReferences(ThirdParty $toKeep, ThirdParty $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 (ThirdParty::class !== $assoc['targetEntity'] && ThirdParty::class !== $assoc['sourceEntity']) { continue; } if (ClassMetadata::TO_ONE === $assoc['type']) { $joinColumn = $meta->getSingleAssociationJoinColumnName($assoc['fieldName']); if (ThirdParty::class === $assoc['sourceEntity'] && 'parent_id' !== $joinColumn) { // TODO what with 'address_id' and 'civility_id'? This condition also contains columns like updatedBy_id which we want to ignore... continue; } $schemaPrefix = (ThirdParty::class === $assoc['sourceEntity'] && 'parent_id' === $joinColumn) ? 'chill_3party.' : ''; $queries[] = [ 'sql' => "UPDATE {$schemaPrefix}{$tableName} SET {$joinColumn} = :toKeep WHERE {$joinColumn} = :toDelete", 'params' => ['toKeep' => $toKeep->getId(), 'toDelete' => $toDelete->getId()], ]; } if (ClassMetadata::TO_MANY === $assoc['type'] && isset($assoc['joinTable'])) { $joinTable = $assoc['joinTable']['name']; $joinColumn = $assoc['joinTable']['joinColumns'][0]['name']; if ('thirdparty_id' === $joinColumn) { $queries[] = [ 'sql' => "DELETE FROM {$joinTable} WHERE {$joinColumn} = :toDelete", 'params' => ['toDelete' => $toDelete->getId()], ]; } else { $queries[] = [ 'sql' => "UPDATE {$joinTable} SET {$joinColumn} = :toKeep WHERE {$joinColumn} = :toDelete", 'params' => ['toKeep' => $toKeep->getId(), 'toDelete' => $toDelete->getId()], ]; } } } } return $queries; } public function removeThirdparty(ThirdParty $toDelete): array { return [[ 'sql' => 'DELETE FROM chill_3party.third_party WHERE id = :toDelete', 'params' => ['toDelete' => $toDelete->getId()], ]]; } }