diff --git a/app/plugins/Transmogrify/README.md b/app/plugins/Transmogrify/README.md index c5a13dbbe..0826dad97 100644 --- a/app/plugins/Transmogrify/README.md +++ b/app/plugins/Transmogrify/README.md @@ -206,8 +206,14 @@ Optional remediation helper (opt‑in): colon replacement - By default, Transmogrify does not change group names and will error on invalid Standard names. - You can opt in to replace “:” in Standard group names with a safer character or string during migration. The special name “CO” remains invalid and is not auto‑renamed. -Example (replace ":" with "-"): +Example (replace ":" with "-"), shorthand when passing a lone "-" is problematic: ```bash -bin/cake transmogrify --groups-colon-replacement '-' +bin/cake transmogrify --groups-colon-replacement-dash +``` + +For every other character, use the full option: + +```bash +bin/cake transmogrify --groups-colon-replacement '@' ``` diff --git a/app/plugins/Transmogrify/src/Command/TransmogrifyCommand.php b/app/plugins/Transmogrify/src/Command/TransmogrifyCommand.php index 27519b25f..57df6ae87 100644 --- a/app/plugins/Transmogrify/src/Command/TransmogrifyCommand.php +++ b/app/plugins/Transmogrify/src/Command/TransmogrifyCommand.php @@ -31,6 +31,7 @@ use App\Lib\Traits\LabeledLogTrait; use App\Lib\Util\DBALConnection; +use App\Lib\Util\StringUtilities; use App\Model\Table\MetaTable; use App\Service\ConfigLoaderService; use App\Service\DbInfoService; @@ -364,6 +365,21 @@ public function execute(Arguments $args, ConsoleIo $io): int $qualifiedTableName = $this->outconn->qualifyTableName($t); if($modeltableEmpty && !$notSelected) { + $fkQualifiedTableName = StringUtilities::classNameToForeignKey($qualifiedTableName); + if ( + isset($this->cache['rejected']) + && !empty($this->cache['rejected'][$qualifiedTableName][$row[$fkQualifiedTableName]]) + ) { + // This row will be rejected because it references a parent record that does not exist. + // The parent record has been rejected before, so we can't insert this record. + $this->cache['rejected'][$qualifiedTableName][$row['id']] = $row; + $io->warning(sprintf( + 'Skipping record %d in table %s - parent record does not exist', + $row['id'] ?? 0, + $t + )); + continue; + } $this->outconn->insert($qualifiedTableName, $row); // Step 8: Execute any post-processing hooks after successful insertion $this->runPostRowHook($t, $origRow, $row); diff --git a/app/plugins/Transmogrify/src/Lib/Traits/HookRunnersTrait.php b/app/plugins/Transmogrify/src/Lib/Traits/HookRunnersTrait.php index 9e139c230..757e6bc5b 100644 --- a/app/plugins/Transmogrify/src/Lib/Traits/HookRunnersTrait.php +++ b/app/plugins/Transmogrify/src/Lib/Traits/HookRunnersTrait.php @@ -44,7 +44,7 @@ private function runPreTableHook(string $table): void { throw new \RuntimeException("Unknown preTable hook: $method"); } - $this->io->info('Running pre-table hook: ' . ucfirst(preg_replace('/([A-Z])/', ' $1', $method))); + $this->io->verbose('Running pre-table hook: ' . ucfirst(preg_replace('/([A-Z])/', ' $1', $method))); $this->{$method}(); } @@ -62,7 +62,7 @@ private function runPostTableHook(string $table): void { if(!method_exists($this, $method)) { throw new \RuntimeException("Unknown postTable hook: $method"); } - $this->io->info('Running post-table hook: ' . ucfirst(preg_replace('/([A-Z])/', ' $1', $method))); + $this->io->verbose('Running post-table hook: ' . ucfirst(preg_replace('/([A-Z])/', ' $1', $method))); $this->{$method}(); } @@ -82,7 +82,7 @@ private function runPreRowHook(string $table, array &$origRow, array &$row): voi if(!method_exists($this, $method)) { throw new \RuntimeException("Unknown preRow hook: $method"); } - $this->io->info('Running pre-row hook: ' . ucfirst(preg_replace('/([A-Z])/', ' $1', $method))); + $this->io->verbose('Running pre-row hook: ' . ucfirst(preg_replace('/([A-Z])/', ' $1', $method))); $this->{$method}($origRow, $row); } @@ -102,7 +102,7 @@ private function runPostRowHook(string $table, array &$origRow, array &$row): vo if(!method_exists($this, $method)) { throw new \RuntimeException("Unknown postRow hook: $method"); } - $this->io->info('Running post-row hook: ' . ucfirst(preg_replace('/([A-Z])/', ' $1', $method))); + $this->io->verbose('Running post-row hook: ' . ucfirst(preg_replace('/([A-Z])/', ' $1', $method))); $this->{$method}($origRow, $row); } @@ -123,7 +123,7 @@ private function runSqlSelectHook(string $table, string $qualifiedTableName): st if(!method_exists(RawSqlQueries::class, $method)) { throw new \RuntimeException("Unknown sqlSelect hook: $method"); } - $this->io->info('Running SQL select hook: ' . ucfirst(preg_replace('/([A-Z])/', ' $1', $method))); + $this->io->verbose('Running SQL select hook: ' . ucfirst(preg_replace('/([A-Z])/', ' $1', $method))); return RawSqlQueries::{$method}($qualifiedTableName, $this->inconn->isMySQL()); } } \ No newline at end of file diff --git a/app/plugins/Transmogrify/src/Lib/Traits/RowTransformationTrait.php b/app/plugins/Transmogrify/src/Lib/Traits/RowTransformationTrait.php index b0065913a..5516bbda1 100644 --- a/app/plugins/Transmogrify/src/Lib/Traits/RowTransformationTrait.php +++ b/app/plugins/Transmogrify/src/Lib/Traits/RowTransformationTrait.php @@ -103,6 +103,7 @@ protected function reconcileGroupMembershipOwnership(array $origRow, array &$row // in invalid membership // (3) Otherwise just return so the Membership gets created + $tableName = 'group_members'; if($origRow['owner'] && !$origRow['deleted'] && !$origRow['co_group_member_id']) { // Create a membership in the appropriate owners group, but not // on changelog entries @@ -119,7 +120,6 @@ protected function reconcileGroupMembershipOwnership(array $origRow, array &$row 'actor_identifier' => $origRow['actor_identifier'] ]; - $tableName = 'group_members'; $qualifiedTableName = $this->outconn->qualifyTableName($tableName); $this->outconn->insert($qualifiedTableName, $ownerRow); } else { @@ -128,6 +128,8 @@ protected function reconcileGroupMembershipOwnership(array $origRow, array &$row } if(!$row['member'] && !$row['owner']) { + // we are caching the rejected rows so we can reject the rows that reference them as well. + $this->cache['rejected'][$tableName][$row['id']] = $row; throw new \InvalidArgumentException('member not set on GroupMember'); } }