/** * Tests the embedded_data source plugin. */ public function testEmbeddedData() { $data_rows = [['key' => '1', 'field1' => 'f1value1', 'field2' => 'f2value1'], ['key' => '2', 'field1' => 'f1value2', 'field2' => 'f2value2']]; $ids = ['key' => ['type' => 'integer']]; $definition = ['migration_tags' => ['Embedded data test'], 'source' => ['plugin' => 'embedded_data', 'data_rows' => $data_rows, 'ids' => $ids], 'process' => [], 'destination' => ['plugin' => 'null']]; $migration = new Migration([], uniqid(), $definition); $source = $migration->getSourcePlugin(); // Validate the plugin returns the source data that was provided. $results = []; /** @var \Drupal\migrate\Row $row */ foreach ($source as $row) { $data_row = $row->getSource(); // The "data" row returned by getSource() also includes all source // configuration - we remove it so we see only the data itself. unset($data_row['plugin']); unset($data_row['data_rows']); unset($data_row['ids']); $results[] = $data_row; } $this->assertIdentical($results, $data_rows); // Validate the public APIs. $this->assertIdentical($source->count(), count($data_rows)); $this->assertIdentical($source->getIds(), $ids); $expected_fields = ['key' => 'key', 'field1' => 'field1', 'field2' => 'field2']; $this->assertIdentical($source->fields(), $expected_fields); }
/** * {@inheritdoc} */ public function getProcess() { if (!$this->init) { $this->init = TRUE; $definition['source'] = ['entity_type' => 'user', 'ignore_map' => TRUE] + $this->source; $definition['destination']['plugin'] = 'null'; if (\Drupal::moduleHandler()->moduleExists('field')) { $definition['source']['plugin'] = 'd7_field_instance'; $field_migration = new Migration([], uniqid(), $definition); foreach ($field_migration->getSourcePlugin() as $row) { $field_name = $row->getSourceProperty('field_name'); $this->process[$field_name] = $field_name; } } try { $definition['source']['plugin'] = 'profile_field'; $profile_migration = new Migration([], uniqid(), $definition); // Ensure that Profile is enabled in the source DB. $profile_migration->checkRequirements(); foreach ($profile_migration->getSourcePlugin() as $row) { $name = $row->getSourceProperty('name'); $this->process[$name] = $name; } } catch (RequirementsException $e) { // The checkRequirements() call will fail when the profile module does // not exist on the source site. } } return parent::getProcess(); }
/** * Create a stub of the given entity type. * * @param string $entity_type_id * The entity type we are stubbing. * * @return int * ID of the created entity. */ protected function createStub($entity_type_id) { // Create a dummy migration to pass to the destination plugin. $definition = ['migration_tags' => ['Stub test'], 'source' => ['plugin' => 'empty'], 'process' => [], 'destination' => ['plugin' => 'entity:' . $entity_type_id]]; $migration = new Migration([], uniqid(), $definition); $destination_plugin = $migration->getDestinationPlugin(TRUE); $stub_row = new Row([], [], TRUE); $destination_ids = $destination_plugin->import($stub_row); return reset($destination_ids); }
/** * Tests migration interruptions. */ public function testMigrateEvents() { // Run a simple little migration, which should trigger one of each event // other than map_delete. $definition = ['migration_tags' => ['Interruption test'], 'source' => ['plugin' => 'embedded_data', 'data_rows' => [['data' => 'dummy value'], ['data' => 'dummy value2']], 'ids' => ['data' => ['type' => 'string']]], 'process' => ['value' => 'data'], 'destination' => ['plugin' => 'dummy']]; $migration = new Migration([], uniqid(), $definition); $executable = new MigrateExecutable($migration, new MigrateMessage()); // When the import runs, the first row imported will trigger an // interruption. $result = $executable->import(); $this->assertEqual($result, MigrationInterface::RESULT_INCOMPLETE); // The status should have been reset to IDLE. $this->assertEqual($migration->getStatus(), MigrationInterface::STATUS_IDLE); }
/** * Tests different connection types. */ public function testStatus() { // Create a minimally valid migration. $definition = ['id' => 'migration_status_test', 'migration_tags' => ['Testing'], 'source' => ['plugin' => 'empty'], 'destination' => ['plugin' => 'config', 'config_name' => 'migrate_test.settings'], 'process' => ['foo' => 'bar']]; $migration = new Migration([], uniqid(), $definition); // Default status is idle. $status = $migration->getStatus(); $this->assertIdentical($status, MigrationInterface::STATUS_IDLE); // Test setting and retrieving all known status values. $status_list = array(MigrationInterface::STATUS_IDLE, MigrationInterface::STATUS_IMPORTING, MigrationInterface::STATUS_ROLLING_BACK, MigrationInterface::STATUS_STOPPING, MigrationInterface::STATUS_DISABLED); foreach ($status_list as $status) { $migration->setStatus($status); $this->assertIdentical($migration->getStatus(), $status); } }
/** * Displays a listing of migration messages. * * Messages are truncated at 56 chars. * * @return array * A render array as expected by drupal_render(). */ public function overview($migration_group, $migration) { $rows = []; $classes = static::getLogLevelClassMap(); /** @var MigrationInterface $migration */ $migration = Migration::load($migration); $source_id_field_names = array_keys($migration->getSourcePlugin()->getIds()); $column_number = 1; foreach ($source_id_field_names as $source_id_field_name) { $header[] = ['data' => $source_id_field_name, 'field' => 'sourceid' . $column_number++, 'class' => [RESPONSIVE_PRIORITY_MEDIUM]]; } $header[] = ['data' => $this->t('Severity level'), 'field' => 'level', 'class' => [RESPONSIVE_PRIORITY_LOW]]; $header[] = ['data' => $this->t('Message'), 'field' => 'message']; $message_table = $migration->getIdMap()->messageTableName(); $query = $this->database->select($message_table, 'm')->extend('\\Drupal\\Core\\Database\\Query\\PagerSelectExtender')->extend('\\Drupal\\Core\\Database\\Query\\TableSortExtender'); $query->fields('m'); $result = $query->limit(50)->orderByHeader($header)->execute(); foreach ($result as $message_row) { $column_number = 1; foreach ($source_id_field_names as $source_id_field_name) { $column_name = 'sourceid' . $column_number++; $row[$column_name] = $message_row->{$column_name}; } $row['level'] = $message_row->level; $row['message'] = $message_row->message; $row['class'] = [Html::getClass('migrate-message-' . $message_row->level), $classes[$message_row->level]]; $rows[] = $row; } $build['message_table'] = ['#type' => 'table', '#header' => $header, '#rows' => $rows, '#attributes' => ['id' => $message_table, 'class' => [$message_table]], '#empty' => $this->t('No messages for this migration.')]; $build['message_pager'] = ['#type' => 'pager']; return $build; }
/** * Tests configurability of file migration name. * * @covers ::__construct */ public function testConfigurableFileMigration() { $migration = Migration::create($this->container, [], 'custom_migration', []); $cck_file_migration = CckFile::create($this->container, ['migration' => 'custom_file'], 'custom_file', [], $migration); $migration_plugin = $this->readAttribute($cck_file_migration, 'migrationPlugin'); $config = $this->readAttribute($migration_plugin, 'configuration'); $this->assertEquals($config['migration'], 'custom_file'); }
/** * Tests migration interruptions. */ public function testPrepareRowSkip() { // Run a simple little migration with two data rows which should be skipped // in different ways. $definition = ['migration_tags' => ['prepare_row test'], 'source' => ['plugin' => 'embedded_data', 'data_rows' => [['id' => '1', 'data' => 'skip_and_record'], ['id' => '2', 'data' => 'skip_and_dont_record']], 'ids' => ['id' => ['type' => 'string']]], 'process' => ['value' => 'data'], 'destination' => ['plugin' => 'config', 'config_name' => 'migrate_test.settings'], 'load' => ['plugin' => 'null']]; $migration = new Migration([], uniqid(), $definition); $executable = new MigrateExecutable($migration, new MigrateMessage()); $result = $executable->import(); $this->assertEqual($result, MigrationInterface::RESULT_COMPLETED); $id_map_plugin = $migration->getIdMap(); // The first row is recorded in the map as ignored. $map_row = $id_map_plugin->getRowBySource(['id' => 1]); $this->assertEqual(MigrateIdMapInterface::STATUS_IGNORED, $map_row['source_row_status']); // The second row is not recorded in the map. $map_row = $id_map_plugin->getRowBySource(['id' => 2]); $this->assertFalse($map_row); }
/** * Tests migration events. */ public function testMigrateEvents() { // Run a simple little migration, which should trigger one of each event // other than map_delete. $definition = ['migration_tags' => ['Event test'], 'source' => ['plugin' => 'embedded_data', 'data_rows' => [['data' => 'dummy value']], 'ids' => ['data' => ['type' => 'string']]], 'process' => ['value' => 'data'], 'destination' => ['plugin' => 'dummy']]; $migration = new Migration([], uniqid(), $definition); $executable = new MigrateExecutable($migration, new MigrateMessage()); // As the import runs, events will be dispatched, recording the received // information in state. $executable->import(); // Validate from the recorded state that the events were received. $event = $this->state->get('migrate_events_test.pre_import_event', []); $this->assertIdentical($event['event_name'], MigrateEvents::PRE_IMPORT); $this->assertIdentical($event['migration']->id(), $migration->id()); $event = $this->state->get('migrate_events_test.post_import_event', []); $this->assertIdentical($event['event_name'], MigrateEvents::POST_IMPORT); $this->assertIdentical($event['migration']->id(), $migration->id()); $event = $this->state->get('migrate_events_test.map_save_event', []); $this->assertIdentical($event['event_name'], MigrateEvents::MAP_SAVE); // Validating the last row processed. $this->assertIdentical($event['fields']['sourceid1'], 'dummy value'); $this->assertIdentical($event['fields']['destid1'], 'dummy value'); $this->assertIdentical($event['fields']['source_row_status'], 0); $event = $this->state->get('migrate_events_test.map_delete_event', []); $this->assertIdentical($event, []); $event = $this->state->get('migrate_events_test.pre_row_save_event', []); $this->assertIdentical($event['event_name'], MigrateEvents::PRE_ROW_SAVE); $this->assertIdentical($event['migration']->id(), $migration->id()); // Validating the last row processed. $this->assertIdentical($event['row']->getSourceProperty('data'), 'dummy value'); $event = $this->state->get('migrate_events_test.post_row_save_event', []); $this->assertIdentical($event['event_name'], MigrateEvents::POST_ROW_SAVE); $this->assertIdentical($event['migration']->id(), $migration->id()); // Validating the last row processed. $this->assertIdentical($event['row']->getSourceProperty('data'), 'dummy value'); $this->assertIdentical($event['destination_id_values']['value'], 'dummy value'); // Generate a map delete event. $migration->getIdMap()->delete(['data' => 'dummy value']); $event = $this->state->get('migrate_events_test.map_delete_event', []); $this->assertIdentical($event['event_name'], MigrateEvents::MAP_DELETE); $this->assertIdentical($event['source_id'], ['data' => 'dummy value']); }
/** * {@inheritdoc} */ public function getProcess() { if (!$this->init) { $this->init = TRUE; $definition['source'] = ['plugin' => 'profile_field', 'ignore_map' => TRUE] + $this->source; $definition['destination']['plugin'] = 'null'; try { $profile_field_migration = new Migration([], uniqid(), $definition); $source_plugin = $profile_field_migration->getSourcePlugin(); $source_plugin->checkRequirements(); foreach ($source_plugin as $row) { $name = $row->getSourceProperty('name'); $this->process[$name] = $name; } } catch (RequirementsException $e) { // The checkRequirements() call will fail when the profile module does // not exist on the source site. } } return parent::getProcess(); }
/** * Tests Migration::set(). * * @covers ::set */ public function testSetInvalidation() { $migration = new Migration([], uniqid(), ['source' => ['plugin' => 'empty'], 'destination' => ['plugin' => 'entity:entity_view_mode']]); $this->assertEqual('empty', $migration->getSourcePlugin()->getPluginId()); $this->assertEqual('entity:entity_view_mode', $migration->getDestinationPlugin()->getPluginId()); // Test the source plugin is invalidated. $migration->set('source', ['plugin' => 'd6_field']); $this->assertEqual('d6_field', $migration->getSourcePlugin()->getPluginId()); // Test the destination plugin is invalidated. $migration->set('destination', ['plugin' => 'null']); $this->assertEqual('null', $migration->getDestinationPlugin()->getPluginId()); }
/** * Tests rolling back configuration and content entities. */ public function testRollback() { // We use vocabularies to demonstrate importing and rolling back // configuration entities. $vocabulary_data_rows = [['id' => '1', 'name' => 'categories', 'weight' => '2'], ['id' => '2', 'name' => 'tags', 'weight' => '1']]; $ids = ['id' => ['type' => 'integer']]; $definition = ['id' => 'vocabularies', 'migration_tags' => ['Import and rollback test'], 'source' => ['plugin' => 'embedded_data', 'data_rows' => $vocabulary_data_rows, 'ids' => $ids], 'process' => ['vid' => 'id', 'name' => 'name', 'weight' => 'weight'], 'destination' => ['plugin' => 'entity:taxonomy_vocabulary']]; $vocabulary_migration = new Migration([], uniqid(), $definition); $vocabulary_id_map = $vocabulary_migration->getIdMap(); $this->assertTrue($vocabulary_migration->getDestinationPlugin()->supportsRollback()); // Import and validate vocabulary config entities were created. $vocabulary_executable = new MigrateExecutable($vocabulary_migration, $this); $vocabulary_executable->import(); foreach ($vocabulary_data_rows as $row) { /** @var Vocabulary $vocabulary */ $vocabulary = Vocabulary::load($row['id']); $this->assertTrue($vocabulary); $map_row = $vocabulary_id_map->getRowBySource(['id' => $row['id']]); $this->assertNotNull($map_row['destid1']); } // We use taxonomy terms to demonstrate importing and rolling back content // entities. $term_data_rows = [['id' => '1', 'vocab' => '1', 'name' => 'music'], ['id' => '2', 'vocab' => '2', 'name' => 'Bach'], ['id' => '3', 'vocab' => '2', 'name' => 'Beethoven']]; $ids = ['id' => ['type' => 'integer']]; $definition = ['id' => 'terms', 'migration_tags' => ['Import and rollback test'], 'source' => ['plugin' => 'embedded_data', 'data_rows' => $term_data_rows, 'ids' => $ids], 'process' => ['tid' => 'id', 'vid' => 'vocab', 'name' => 'name'], 'destination' => ['plugin' => 'entity:taxonomy_term'], 'migration_dependencies' => ['required' => ['vocabularies']]]; $term_migration = new Migration([], uniqid(), $definition); $term_id_map = $term_migration->getIdMap(); $this->assertTrue($term_migration->getDestinationPlugin()->supportsRollback()); // Pre-create a term, to make sure it isn't deleted on rollback. $preserved_term_ids[] = 1; $new_term = Term::create(['tid' => 1, 'vid' => 1, 'name' => 'music']); $new_term->save(); // Import and validate term entities were created. $term_executable = new MigrateExecutable($term_migration, $this); $term_executable->import(); // Also explicitly mark one row to be preserved on rollback. $preserved_term_ids[] = 2; $map_row = $term_id_map->getRowBySource(['id' => 2]); $dummy_row = new Row(['id' => 2], $ids); $term_id_map->saveIdMapping($dummy_row, [$map_row['destid1']], $map_row['source_row_status'], MigrateIdMapInterface::ROLLBACK_PRESERVE); foreach ($term_data_rows as $row) { /** @var Term $term */ $term = Term::load($row['id']); $this->assertTrue($term); $map_row = $term_id_map->getRowBySource(['id' => $row['id']]); $this->assertNotNull($map_row['destid1']); } // Rollback and verify the entities are gone. $term_executable->rollback(); foreach ($term_data_rows as $row) { $term = Term::load($row['id']); if (in_array($row['id'], $preserved_term_ids)) { $this->assertNotNull($term); } else { $this->assertNull($term); } $map_row = $term_id_map->getRowBySource(['id' => $row['id']]); $this->assertFalse($map_row); } $vocabulary_executable->rollback(); foreach ($vocabulary_data_rows as $row) { $term = Vocabulary::load($row['id']); $this->assertNull($term); $map_row = $vocabulary_id_map->getRowBySource(['id' => $row['id']]); $this->assertFalse($map_row); } // Test that simple configuration is not rollbackable. $term_setting_rows = [['id' => 1, 'override_selector' => '0', 'terms_per_page_admin' => '10']]; $ids = ['id' => ['type' => 'integer']]; $definition = ['id' => 'taxonomy_settings', 'migration_tags' => ['Import and rollback test'], 'source' => ['plugin' => 'embedded_data', 'data_rows' => $term_setting_rows, 'ids' => $ids], 'process' => ['override_selector' => 'override_selector', 'terms_per_page_admin' => 'terms_per_page_admin'], 'destination' => ['plugin' => 'config', 'config_name' => 'taxonomy.settings'], 'migration_dependencies' => ['required' => ['vocabularies']]]; $settings_migration = new Migration([], uniqid(), $definition); $this->assertFalse($settings_migration->getDestinationPlugin()->supportsRollback()); }
/** * {@inheritdoc} */ public function getProcess() { if (!$this->init) { $this->init = TRUE; $source_plugin = $this->migrationPluginManager->createInstance($this->pluginId)->getSourcePlugin(); if ($source_plugin instanceof RequirementsInterface) { try { $source_plugin->checkRequirements(); } catch (RequirementsException $e) { // Kill the rest of the method. $source_plugin = []; } } foreach ($source_plugin as $row) { $field_type = $row->getSourceProperty('type'); if (!isset($this->processedFieldTypes[$field_type]) && $this->cckPluginManager->hasDefinition($field_type)) { $this->processedFieldTypes[$field_type] = TRUE; // Allow the cckfield plugin to alter the migration as necessary so // that it knows how to handle fields of this type. if (!isset($this->cckPluginCache[$field_type])) { $this->cckPluginCache[$field_type] = $this->cckPluginManager->createInstance($field_type, [], $this); } call_user_func([$this->cckPluginCache[$field_type], $this->pluginDefinition['cck_plugin_method']], $this); } } } return parent::getProcess(); }
/** * Tests Migration::getProcessPlugins() * * @covers ::getProcessPlugins */ public function testGetProcessPlugins() { $migration = new Migration([], uniqid(), []); $this->assertEquals([], $migration->getProcessPlugins([])); }
/** * {@inheritdoc} */ public function createStubMigration(array $definition) { $id = isset($definition['id']) ? $definition['id'] : uniqid(); return Migration::create(\Drupal::getContainer(), [], $id, $definition); }