diff --git a/app/plugins/Transmogrify/config/schema/tables.json b/app/plugins/Transmogrify/config/schema/tables.json index 256ec205..294f4ffe 100644 --- a/app/plugins/Transmogrify/config/schema/tables.json +++ b/app/plugins/Transmogrify/config/schema/tables.json @@ -550,5 +550,29 @@ "co_petition_attribute_id": null }, "addChangelog": true + }, + "pipelines": { + "source": "cm_co_pipelines", + "displayField": "description", + "cache": ["co_id"], + "fieldMap": { + "name": "description", + "sync_on_add": null, + "sync_on_update": null, + "sync_on_delete": null, + "sync_coperson_status": null, + "sync_coperson_attributes": null, + "create_role": null, + "match_type": null, + "sync_affiliation": null, + "sync_identifier_type": null, + "sync_affiliation_type_id": "&mapAffiliationType", + "sync_identifier_type_id": "&mapIdentifierType", + "match_identifier_type_id": "&mapIdentifierType", + "match_email_address_type_id": "&mapEmailType", + "establish_clusters": null, + "co_enrollment_flow_id": null, + "co_pipeline_id": "pipeline_id" + } } } diff --git a/app/plugins/Transmogrify/src/Lib/Traits/RowTransformationTrait.php b/app/plugins/Transmogrify/src/Lib/Traits/RowTransformationTrait.php index 2c4f5962..e1c60a46 100644 --- a/app/plugins/Transmogrify/src/Lib/Traits/RowTransformationTrait.php +++ b/app/plugins/Transmogrify/src/Lib/Traits/RowTransformationTrait.php @@ -518,6 +518,12 @@ private function performFunctionMapping(array &$row, string $oldname, string $fu 'mapHistoricPetitionViewerId', ]; + // The pipelines table allows the identifier and email types to be null + if ($table === "pipelines") { + $nullableFuncs[] = "mapIdentifierType"; + $nullableFuncs[] = "mapEmailType"; + } + if (!$row[$oldname] && !in_array($funcName, $nullableFuncs, true)) { throw new \InvalidArgumentException("Could not find value for {$table} {$oldname}"); } diff --git a/app/plugins/Transmogrify/src/Lib/Traits/TypeMapperTrait.php b/app/plugins/Transmogrify/src/Lib/Traits/TypeMapperTrait.php index 47e7d195..a65a7ded 100644 --- a/app/plugins/Transmogrify/src/Lib/Traits/TypeMapperTrait.php +++ b/app/plugins/Transmogrify/src/Lib/Traits/TypeMapperTrait.php @@ -316,16 +316,42 @@ protected function mapLoginIdentifiers(array $origRow, array &$row): void { 'modified' => $origRow['modified'] ]; - // Set up changelog and fix booleans + // Set up the changelog and fix booleans $this->populateChangelogDefaults('identifiers', $copiedRow, true); $this->normalizeBooleanFieldsForDb('identifiers', $copiedRow); try { $tableName = 'identifiers'; $qualifiedTableName = $this->outconn->qualifyTableName($tableName); + + // Check if the identifier already exists + $identifierLookupSql = "SELECT id FROM {$qualifiedTableName} + WHERE person_id = ? + AND type_id = ? + AND identifier = ? + AND login = ? + AND source_identifier_id IS NULL + LIMIT 1"; + $identifierLookupData = [ + $copiedRow['person_id'], + $copiedRow['type_id'], + $copiedRow['identifier'], + true + ]; + $this->normalizeBooleanFieldsForDb('identifiers', $identifierLookupData); + $existingIdentifierId = $this->outconn->fetchOne($identifierLookupSql, $identifierLookupData); + + if ($existingIdentifierId) { + // Already present; skip insert regardless of differing metadata + $this->cmdPrinter?->verbose("Duplicate login Identifier detected for person_id={$copiedRow['person_id']} type_id={$copiedRow['type_id']} identifier={$copiedRow['identifier']}; skipping copy."); + return; + } + $this->outconn->insert($qualifiedTableName, $copiedRow); } catch (UniqueConstraintViolationException $e) { $this->cmdPrinter->warning("record already exists: " . print_r($copiedRow, true)); + } catch (\Doctrine\DBAL\Exception $e) { + throw new \InvalidArgumentException("Failed to fetch identifier record: " . $e->getMessage()); } } }