/**
  * Returns the source.
  *
  * Makes sure source is initialized based on migration settings.
  *
  * @return \Drupal\migrate\Plugin\MigrateSourceInterface
  *   The source.
  */
 protected function getSource()
 {
     if (!isset($this->source)) {
         $this->source = $this->migration->getSourcePlugin();
     }
     return $this->source;
 }
 /**
  * {@inheritdoc}
  *
  * The migration iterates over rows returned by the source plugin. This
  * method determines the next row which will be processed and imported into
  * the system.
  *
  * The method tracks the source and destination IDs using the ID map plugin.
  *
  * This also takes care about highwater support. Highwater allows to reimport
  * rows from a previous migration run, which got changed in the meantime.
  * This is done by specifying a highwater field, which is compared with the
  * last time, the migration got executed (originalHighWater).
  */
 public function next()
 {
     $this->currentSourceIds = NULL;
     $this->currentRow = NULL;
     // In order to find the next row we want to process, we ask the source
     // plugin for the next possible row.
     while (!isset($this->currentRow) && $this->getIterator()->valid()) {
         $row_data = $this->getIterator()->current() + $this->configuration;
         $this->getIterator()->next();
         $row = new Row($row_data, $this->migration->getSourcePlugin()->getIds(), $this->migration->get('destinationIds'));
         // Populate the source key for this row.
         $this->currentSourceIds = $row->getSourceIdValues();
         // Pick up the existing map row, if any, unless getNextRow() did it.
         if (!$this->mapRowAdded && ($id_map = $this->idMap->getRowBySource($this->currentSourceIds))) {
             $row->setIdMap($id_map);
         }
         // Clear any previous messages for this row before potentially adding
         // new ones.
         if (!empty($this->currentSourceIds)) {
             $this->idMap->delete($this->currentSourceIds, TRUE);
         }
         // Preparing the row gives source plugins the chance to skip.
         if ($this->prepareRow($row) === FALSE) {
             continue;
         }
         // Check whether the row needs processing.
         // 1. This row has not been imported yet.
         // 2. Explicitly set to update.
         // 3. The row is newer than the current highwater mark.
         // 4. If no such property exists then try by checking the hash of the row.
         if (!$row->getIdMap() || $row->needsUpdate() || $this->aboveHighwater($row) || $this->rowChanged($row)) {
             $this->currentRow = $row->freezeSource();
         }
     }
 }
Example #3
0
 /**
  * Gets the source plugin to test.
  *
  * @param array $configuration
  *   (optional) The source configuration. Defaults to an empty array.
  * @param array $migrate_config
  *   (optional) The migration configuration to be used in
  *   parent::getMigration(). Defaults to an empty array.
  * @param int $status
  *   (optional) The default status for the new rows to be imported. Defaults
  *   to MigrateIdMapInterface::STATUS_NEEDS_UPDATE.
  *
  * @return \Drupal\migrate\Plugin\MigrateSourceInterface
  *   A mocked source plugin.
  */
 protected function getSource($configuration = [], $migrate_config = [], $status = MigrateIdMapInterface::STATUS_NEEDS_UPDATE)
 {
     $this->migrationConfiguration = $this->defaultMigrationConfiguration + $migrate_config;
     $this->migration = parent::getMigration();
     $this->executable = $this->getMigrateExecutable($this->migration);
     // Update the idMap for Source so the default is that the row has already
     // been imported. This allows us to use the highwater mark to decide on the
     // outcome of whether we choose to import the row.
     $id_map_array = ['original_hash' => '', 'hash' => '', 'source_row_status' => $status];
     $this->idMap->expects($this->any())->method('getRowBySource')->willReturn($id_map_array);
     $constructor_args = [$configuration, 'd6_action', [], $this->migration];
     $methods = ['getModuleHandler', 'fields', 'getIds', '__toString', 'getIterator', 'prepareRow', 'initializeIterator', 'calculateDependencies'];
     $source_plugin = $this->getMock('\\Drupal\\migrate\\Plugin\\migrate\\source\\SourcePluginBase', $methods, $constructor_args);
     $source_plugin->expects($this->any())->method('fields')->willReturn([]);
     $source_plugin->expects($this->any())->method('getIds')->willReturn([]);
     $source_plugin->expects($this->any())->method('__toString')->willReturn('');
     $source_plugin->expects($this->any())->method('prepareRow')->willReturn(empty($migrate_config['prepare_row_false']));
     $source_plugin->expects($this->any())->method('initializeIterator')->willReturn([]);
     $iterator = new \ArrayIterator([$this->row]);
     $source_plugin->expects($this->any())->method('getIterator')->willReturn($iterator);
     $module_handler = $this->getMock('\\Drupal\\Core\\Extension\\ModuleHandlerInterface');
     $source_plugin->expects($this->any())->method('getModuleHandler')->willReturn($module_handler);
     $this->migration->expects($this->any())->method('getSourcePlugin')->willReturn($source_plugin);
     return $this->migration->getSourcePlugin();
 }
Example #4
0
 /**
  * Create the map and message tables if they don't already exist.
  */
 protected function ensureTables()
 {
     if (!$this->getDatabase()->schema()->tableExists($this->mapTableName)) {
         // Generate appropriate schema info for the map and message tables,
         // and map from the source field names to the map/msg field names.
         $count = 1;
         $source_id_schema = array();
         foreach ($this->migration->getSourcePlugin()->getIds() as $id_definition) {
             $mapkey = 'sourceid' . $count++;
             $source_id_schema[$mapkey] = $this->getFieldSchema($id_definition);
             $source_id_schema[$mapkey]['not null'] = TRUE;
         }
         $source_ids_hash[static::SOURCE_IDS_HASH] = array('type' => 'varchar', 'length' => '64', 'not null' => TRUE, 'description' => 'Hash of source ids. Used as primary key');
         $fields = $source_ids_hash + $source_id_schema;
         // Add destination identifiers to map table.
         // @todo How do we discover the destination schema?
         $count = 1;
         foreach ($this->migration->getDestinationPlugin()->getIds() as $id_definition) {
             // Allow dest identifier fields to be NULL (for IGNORED/FAILED cases).
             $mapkey = 'destid' . $count++;
             $fields[$mapkey] = $this->getFieldSchema($id_definition);
             $fields[$mapkey]['not null'] = FALSE;
         }
         $fields['source_row_status'] = array('type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => MigrateIdMapInterface::STATUS_IMPORTED, 'description' => 'Indicates current status of the source row');
         $fields['rollback_action'] = array('type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => MigrateIdMapInterface::ROLLBACK_DELETE, 'description' => 'Flag indicating what to do for this item on rollback');
         $fields['last_imported'] = array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, 'description' => 'UNIX timestamp of the last time this row was imported');
         $fields['hash'] = array('type' => 'varchar', 'length' => '64', 'not null' => FALSE, 'description' => 'Hash of source row data, for detecting changes');
         $schema = array('description' => 'Mappings from source identifier value(s) to destination identifier value(s).', 'fields' => $fields, 'primary key' => array(static::SOURCE_IDS_HASH));
         $this->getDatabase()->schema()->createTable($this->mapTableName, $schema);
         // Now do the message table.
         if (!$this->getDatabase()->schema()->tableExists($this->messageTableName())) {
             $fields = array();
             $fields['msgid'] = array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE);
             $fields += $source_ids_hash;
             $fields['level'] = array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 1);
             $fields['message'] = array('type' => 'text', 'size' => 'medium', 'not null' => TRUE);
             $schema = array('description' => 'Messages generated during a migration process', 'fields' => $fields, 'primary key' => array('msgid'));
             $this->getDatabase()->schema()->createTable($this->messageTableName(), $schema);
         }
     } else {
         // Add any missing columns to the map table.
         if (!$this->getDatabase()->schema()->fieldExists($this->mapTableName, 'rollback_action')) {
             $this->getDatabase()->schema()->addField($this->mapTableName, 'rollback_action', array('type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, 'description' => 'Flag indicating what to do for this item on rollback'));
         }
         if (!$this->getDatabase()->schema()->fieldExists($this->mapTableName, 'hash')) {
             $this->getDatabase()->schema()->addField($this->mapTableName, 'hash', array('type' => 'varchar', 'length' => '64', 'not null' => FALSE, 'description' => 'Hash of source row data, for detecting changes'));
         }
         if (!$this->getDatabase()->schema()->fieldExists($this->mapTableName, static::SOURCE_IDS_HASH)) {
             $this->getDatabase()->schema()->addField($this->mapTableName, static::SOURCE_IDS_HASH, array('type' => 'varchar', 'length' => '64', 'not null' => TRUE, 'description' => 'Hash of source ids. Used as primary key'));
         }
     }
 }
 /**
  * Instantiates the source plugin under test.
  *
  * @param array $configuration
  *   The source plugin configuration.
  *
  * @return \Drupal\migrate\Plugin\MigrateSourceInterface|object
  *   The fully configured source plugin.
  */
 protected function getPlugin(array $configuration)
 {
     // Only create the plugin once per test.
     if ($this->plugin) {
         return $this->plugin;
     }
     $class = ltrim($this->getPluginClass(), '\\');
     /** @var \Drupal\migrate\Plugin\MigratePluginManager $plugin_manager */
     $plugin_manager = $this->container->get('plugin.manager.migrate.source');
     foreach ($plugin_manager->getDefinitions() as $id => $definition) {
         if (ltrim($definition['class'], '\\') == $class) {
             $this->plugin = $plugin_manager->createInstance($id, $configuration, $this->migration->reveal());
             $this->migration->getSourcePlugin()->willReturn($this->plugin);
             return $this->plugin;
         }
     }
     $this->fail('No plugin found for class ' . $class);
 }