diff --git a/core/modules/migrate/src/MigrateExecutable.php b/core/modules/migrate/src/MigrateExecutable.php index c0b3537..ef5b86c 100644 --- a/core/modules/migrate/src/MigrateExecutable.php +++ b/core/modules/migrate/src/MigrateExecutable.php @@ -329,6 +329,12 @@ public function rollback() { // We're now done with this row, so remove it from the map. $id_map->deleteDestination($destination_key); } + else { + // If there is no destination key the import probably failed and we can + // remove the row without further action. + $source_key = $id_map->currentSource(); + $id_map->delete($source_key); + } // Check for memory exhaustion. if (($return = $this->checkStatus()) != MigrationInterface::RESULT_COMPLETED) { diff --git a/core/modules/migrate/src/Plugin/MigrateIdMapInterface.php b/core/modules/migrate/src/Plugin/MigrateIdMapInterface.php index d3bdb89..eafac29 100644 --- a/core/modules/migrate/src/Plugin/MigrateIdMapInterface.php +++ b/core/modules/migrate/src/Plugin/MigrateIdMapInterface.php @@ -244,6 +244,14 @@ public function lookupDestinationIds(array $source_id_values); public function currentDestination(); /** + * Looks up the source identifier(s) currently being iterated. + * + * @return array + * The source identifier values of the record, or NULL on failure. + */ + public function currentSource(); + + /** * Removes any persistent storage used by this map. * * For example, remove the map and message tables. diff --git a/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php b/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php index cf39275..cbf4a9f 100644 --- a/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php +++ b/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php @@ -845,7 +845,25 @@ public function currentDestination() { if ($this->valid()) { $result = array(); foreach ($this->destinationIdFields() as $destination_field_name => $idmap_field_name) { - $result[$destination_field_name] = $this->currentRow[$idmap_field_name]; + if (!is_null($this->currentRow[$idmap_field_name])) { + $result[$destination_field_name] = $this->currentRow[$idmap_field_name]; + } + } + return $result; + } + else { + return NULL; + } + } + + /** + * @inheritdoc + */ + public function currentSource() { + if ($this->valid()) { + $result = array(); + foreach ($this->sourceIdFields() as $field_name => $source_id) { + $result[$field_name] = $this->currentKey[$source_id]; } return $result; } diff --git a/core/modules/migrate/tests/src/Kernel/MigrateRollbackTest.php b/core/modules/migrate/tests/src/Kernel/MigrateRollbackTest.php index 9ec0c65..4b78e65 100644 --- a/core/modules/migrate/tests/src/Kernel/MigrateRollbackTest.php +++ b/core/modules/migrate/tests/src/Kernel/MigrateRollbackTest.php @@ -128,6 +128,9 @@ public function testRollback() { $this->assertNotNull($map_row['destid1']); } + // Add a failed row to test if this can be rolled back without errors. + $this->mockFailure($term_migration, ['id' => '4', 'vocab' => '2', 'name' => 'FAIL']); + // Rollback and verify the entities are gone. $term_executable->rollback(); foreach ($term_data_rows as $row) { diff --git a/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapTest.php b/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapTest.php index a9d1313..739a807 100644 --- a/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapTest.php +++ b/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapTest.php @@ -641,6 +641,28 @@ public function testLookupSourceIDMapping($num_source_fields, $num_destination_f } /** + * Tests currentDestination() and currentSource(). + */ + public function testCurrentDestinationAndSource() { + // Simple map with one source and one destination ID. + $id_map = $this->setupRows(['nid'], ['nid'], [ + [1, 101], + [2, 102], + [3, 103], + ]); + + $id_map->rewind(); + $this->assertEquals(['nid' => 101], $id_map->currentDestination()); + $this->assertEquals(['nid' => 1], $id_map->currentSource()); + $id_map->next(); + $this->assertEquals(['nid' => 102], $id_map->currentDestination()); + $this->assertEquals(['nid' => 2], $id_map->currentSource()); + $id_map->next(); + $this->assertEquals(['nid' => 103], $id_map->currentDestination()); + $this->assertEquals(['nid' => 3], $id_map->currentSource()); + } + + /** * Tests the imported count method. * * Scenarios to test for: