/** * 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(); $pks = array(); foreach ($this->migration->getSourcePlugin()->getIds() as $id_definition) { $mapkey = 'sourceid' . $count++; $source_id_schema[$mapkey] = $this->getFieldSchema($id_definition); $pks[] = $mapkey; } $fields = $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); if ($pks) { $schema['primary key'] = $pks; } $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_id_schema; $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')); if ($pks) { $schema['indexes']['sourcekey'] = $pks; } $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')); } } }
/** * Performs an import operation - migrate items from source to destination. */ public function import() { // Knock off migration if the requirements haven't been met. if (!$this->migration->checkRequirements()) { $this->message->display($this->t('Migration @id did not meet the requirements', array('@id' => $this->migration->id())), 'error'); return MigrationInterface::RESULT_FAILED; } $return = MigrationInterface::RESULT_COMPLETED; $source = $this->getSource(); $id_map = $this->migration->getIdMap(); try { $source->rewind(); } catch (\Exception $e) { $this->message->display($this->t('Migration failed with source plugin exception: !e', array('!e' => $e->getMessage())), 'error'); return MigrationInterface::RESULT_FAILED; } $destination = $this->migration->getDestinationPlugin(); while ($source->valid()) { $row = $source->current(); if ($this->sourceIdValues = $row->getSourceIdValues()) { // Wipe old messages, and save any new messages. $id_map->delete($this->sourceIdValues, TRUE); $this->saveQueuedMessages(); } try { $this->processRow($row); $save = TRUE; } catch (MigrateSkipRowException $e) { $id_map->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_IGNORED, $this->rollbackAction); $save = FALSE; } if ($save) { try { $destination_id_values = $destination->import($row, $id_map->lookupDestinationId($this->sourceIdValues)); if ($destination_id_values) { // We do not save an idMap entry for config. if ($destination_id_values !== TRUE) { $id_map->saveIdMapping($row, $destination_id_values, $this->sourceRowStatus, $this->rollbackAction); } $this->successesSinceFeedback++; $this->totalSuccesses++; } else { $id_map->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_FAILED, $this->rollbackAction); if (!$id_map->messageCount()) { $message = $this->t('New object was not saved, no error provided'); $this->saveMessage($message); $this->message->display($message); } } } catch (MigrateException $e) { $this->migration->getIdMap()->saveIdMapping($row, array(), $e->getStatus(), $this->rollbackAction); $this->saveMessage($e->getMessage(), $e->getLevel()); $this->message->display($e->getMessage(), 'error'); } catch (\Exception $e) { $this->migration->getIdMap()->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_FAILED, $this->rollbackAction); $this->handleException($e); } } $this->totalProcessed++; $this->processedSinceFeedback++; if ($highwater_property = $this->migration->get('highwaterProperty')) { $this->migration->saveHighwater($row->getSourceProperty($highwater_property['name'])); } // Reset row properties. unset($sourceValues, $destinationValues); $this->sourceRowStatus = MigrateIdMapInterface::STATUS_IMPORTED; if (($return = $this->checkStatus()) != MigrationInterface::RESULT_COMPLETED) { break; } if ($this->timeOptionExceeded()) { break; } try { $source->next(); } catch (\Exception $e) { $this->message->display($this->t('Migration failed with source plugin exception: !e', array('!e' => $e->getMessage())), 'error'); return MigrationInterface::RESULT_FAILED; } } /** * @TODO uncomment this */ #$this->progressMessage($return); return $return; }