You are here

class CRMCoreMigrateSQLMap in CRM Core 7

@file Defines a CRMCore extention of MigrateSQLMap

Hierarchy

Expanded class hierarchy of CRMCoreMigrateSQLMap

File

modules/crm_core_data_import/includes/controllers/CRMCoreMigrateSQLMap.inc, line 7
Defines a CRMCore extention of MigrateSQLMap

View source
class CRMCoreMigrateSQLMap extends MigrateSQLMap {

  // We need importer to get info about related migrations.
  // This will allow us to add relation_id fields to migrate map table schema.

  /** @var  CRMCoreDataImport */
  protected $importer;
  protected $options;
  public function __construct($machine_name, array $source_key, array $destination_key, $connection_key = 'default', $options = array()) {
    if (!empty($options['importer']) && $options['importer'] instanceof CRMCoreDataImport) {
      $this->importer = $options['importer'];
      unset($options['importer']);
    }
    $this->options = $options;
    parent::__construct($machine_name, $source_key, $destination_key, $connection_key, $options);
  }
  protected function ensureTables() {
    if (!$this->ensured) {
      if (!$this->connection
        ->schema()
        ->tableExists($this->mapTable)) {

        // 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_key_schema = array();
        $pks = array();
        foreach ($this->sourceKey as $field_schema) {
          $mapkey = 'sourceid' . $count++;

          // Make source key case sensitive
          $field_schema['binary'] = TRUE;
          $source_key_schema[$mapkey] = $field_schema;
          $pks[] = $mapkey;
        }
        $fields = $source_key_schema;

        // Add destination keys to map table
        // TODO: How do we discover the destination schema?
        $count = 1;
        foreach ($this->destinationKey as $field_schema) {

          // Allow dest key fields to be NULL (for IGNORED/FAILED cases)
          $field_schema['not null'] = FALSE;
          $mapkey = 'destid' . $count++;
          $fields[$mapkey] = $field_schema;
        }
        $fields['needs_update'] = array(
          'type' => 'int',
          'size' => 'tiny',
          'unsigned' => TRUE,
          'not null' => TRUE,
          'default' => MigrateMap::STATUS_IMPORTED,
          'description' => 'Indicates current status of the source row',
        );
        $fields['rollback_action'] = array(
          'type' => 'int',
          'size' => 'tiny',
          'unsigned' => TRUE,
          'not null' => TRUE,
          'default' => MigrateMap::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' => '32',
          'not null' => FALSE,
          'description' => 'Hash of source row data, for detecting changes',
        );

        // Find out if we need to add relation ids to schema.
        // Add source id for relations that we import.
        // We need source id only for one endpoint of relationship.
        // Let it be source endpoint.
        $destinations = $this->importer
          ->getRelationDestinationEndPoints(implode(':', array(
          $this->options['entity_type'],
          $this->options['entity_bundle'],
          $this->options['delta'],
        )));
        foreach ($destinations as $key => $destination) {
          $fields['relation_id' . ($key + 1)] = array(
            'type' => 'varchar',
            'length' => '32',
            'binary' => TRUE,
            'not null' => FALSE,
            'description' => 'ID of relation endpoint entity',
          );
        }
        $schema = array(
          'description' => t('Mappings from source key to destination key'),
          'fields' => $fields,
          'primary key' => $pks,
        );
        $this->connection
          ->schema()
          ->createTable($this->mapTable, $schema);

        // Now for the message table
        $fields = array();
        $fields['msgid'] = array(
          'type' => 'serial',
          'unsigned' => TRUE,
          'not null' => TRUE,
        );
        $fields += $source_key_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' => t('Messages generated during a migration process'),
          'fields' => $fields,
          'primary key' => array(
            'msgid',
          ),
          'indexes' => array(
            'sourcekey' => $pks,
          ),
        );
        $this->connection
          ->schema()
          ->createTable($this->messageTable, $schema);
      }
      else {

        // Add any missing columns to the map table
        if (!$this->connection
          ->schema()
          ->fieldExists($this->mapTable, 'rollback_action')) {
          $this->connection
            ->schema()
            ->addField($this->mapTable, '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->connection
          ->schema()
          ->fieldExists($this->mapTable, 'hash')) {
          $this->connection
            ->schema()
            ->addField($this->mapTable, 'hash', array(
            'type' => 'varchar',
            'length' => '32',
            'not null' => FALSE,
            'description' => 'Hash of source row data, for detecting changes',
          ));
        }
      }
      $this->ensured = TRUE;
    }
  }

  /**
   * Called upon import of one record, we record a mapping from the source key
   * to the destination key. Also may be called, setting the third parameter to
   * NEEDS_UPDATE, to signal an existing record should be remigrated.
   *
   * @param stdClass $source_row
   *  The raw source data. We use the key map derived from the source object
   *  to get the source key values.
   * @param array $dest_ids
   *  The destination key values.
   * @param int $needs_update
   *  Status of the source row in the map. Defaults to STATUS_IMPORTED.
   * @param int $rollback_action
   *  How to handle the destination object on rollback. Defaults to
   *  ROLLBACK_DELETE.
   * $param string $hash
   *  If hashing is enabled, the hash of the raw source row.
   */
  public function saveIDMapping(stdClass $source_row, array $dest_ids, $needs_update = MigrateMap::STATUS_IMPORTED, $rollback_action = MigrateMap::ROLLBACK_DELETE, $hash = NULL) {
    migrate_instrument_start('saveIDMapping');

    // Construct the source key
    $keys = array();
    foreach ($this->sourceKeyMap as $field_name => $key_name) {

      // A NULL key value will fail.
      if (is_null($source_row->{$field_name})) {
        Migration::displayMessage(t('Could not save to map table due to NULL value for key field !field', array(
          '!field' => $field_name,
        )));
        migrate_instrument_stop('saveIDMapping');
        return;
      }
      $keys[$key_name] = $source_row->{$field_name};
    }
    $fields = array(
      'needs_update' => (int) $needs_update,
      'rollback_action' => (int) $rollback_action,
      'hash' => $hash,
    );

    // Add relation ids when present.
    foreach ($this->importer
      ->getRelationDestinationEndPoints(implode(':', array(
      $this->options['entity_type'],
      $this->options['entity_bundle'],
      $this->options['delta'],
    ))) as $key => $ep) {
      list($ep_entity_type, $ep_bundle, $ep_importer_id) = explode(':', $ep);
      $endpoint_machine_name = _crm_core_data_import_migration_machine_name($ep_importer_id, $ep_entity_type, $ep_bundle, $this->options['delta']);
      $endpoint_migration = Migration::getInstance($endpoint_machine_name);
      $ep_source_map = array_keys($endpoint_migration
        ->getMap()
        ->getSourceKeyMap());
      $fields['relation_id' . ($key + 1)] = $source_row->{$ep_source_map[0]};
    }
    $count = 1;
    if (!empty($dest_ids)) {
      foreach ($dest_ids as $dest_id) {
        $fields['destid' . $count++] = $dest_id;
      }
    }
    if ($this->trackLastImported) {
      $fields['last_imported'] = time();
    }
    $this->connection
      ->merge($this->mapTable)
      ->key($keys)
      ->fields($fields)
      ->execute();
    migrate_instrument_stop('saveIDMapping');
  }

}

Members

Namesort descending Modifiers Type Description Overrides
CRMCoreMigrateSQLMap::$importer protected property @var CRMCoreDataImport
CRMCoreMigrateSQLMap::$options protected property
CRMCoreMigrateSQLMap::ensureTables protected function Create the map and message tables if they don't already exist. Overrides MigrateSQLMap::ensureTables
CRMCoreMigrateSQLMap::saveIDMapping public function Called upon import of one record, we record a mapping from the source key to the destination key. Also may be called, setting the third parameter to NEEDS_UPDATE, to signal an existing record should be remigrated. Overrides MigrateSQLMap::saveIDMapping
CRMCoreMigrateSQLMap::__construct public function Constructor. Overrides MigrateSQLMap::__construct
MigrateMap::$sourceKey protected property Arrays of key fields for the source and destination. Array keys are the field names - array values are specific to the concrete map class.
MigrateMap::$sourceKeyMap protected property Mapping from field names to the map/message table key names (e.g., from input_field to sourceid1, or from nid to destid1)
MigrateMap::$trackLastImported protected property Boolean determining whether to track last_imported times in map tables
MigrateMap::getSourceKeyMap public function Get the source key map.
MigrateMap::getTrackLastImported public function
MigrateMap::ROLLBACK_DELETE constant Codes reflecting how to handle the destination item on rollback.
MigrateMap::ROLLBACK_PRESERVE constant
MigrateMap::setTrackLastImported public function
MigrateMap::STATUS_FAILED constant
MigrateMap::STATUS_IGNORED constant
MigrateMap::STATUS_IMPORTED constant Codes reflecting the current status of a map row.
MigrateMap::STATUS_NEEDS_UPDATE constant
MigrateSQLMap::$cacheMapLookups protected property Provide caching for Source or Desination Map Lookups.
MigrateSQLMap::$connection protected property Drupal connection object on which to create the map/message tables.
MigrateSQLMap::$currentKey protected property
MigrateSQLMap::$currentRow protected property
MigrateSQLMap::$ensured protected property We don't need to check the tables more than once per request.
MigrateSQLMap::$mapTable protected property Names of tables created for tracking the migration.
MigrateSQLMap::$result protected property
MigrateSQLMap::clearMessages public function Clear all messages from the message table. Overrides MigrateMap::clearMessages
MigrateSQLMap::current public function Implementation of Iterator::current() - called when entering a loop iteration, returning the current row.
MigrateSQLMap::delete public function Delete the map entry and any message table entries for the specified source row. Overrides MigrateMap::delete
MigrateSQLMap::deleteBulk public function Delete all map and message table entries specified. Overrides MigrateMap::deleteBulk
MigrateSQLMap::deleteDestination public function Delete the map entry and any message table entries for the specified destination row. Overrides MigrateMap::deleteDestination
MigrateSQLMap::destroy public function Remove the associated map and message tables. Overrides MigrateMap::destroy
MigrateSQLMap::errorCount public function Get the number of source records which failed to import. Overrides MigrateMap::errorCount
MigrateSQLMap::getConnection public function
MigrateSQLMap::getCurrentKey public function
MigrateSQLMap::getDestinationKey public function Overrides MigrateMap::getDestinationKey
MigrateSQLMap::getMapTable public function
MigrateSQLMap::getMessageTable public function
MigrateSQLMap::getQualifiedMapTable public function Qualifying the map table name with the database name makes cross-db joins possible. Note that, because prefixes are applied after we do this (i.e., it will prefix the string we return), we do not qualify the table if it has a prefix. This will work…
MigrateSQLMap::getRowByDestination public function Retrieve a row from the map table, given a destination ID. Overrides MigrateMap::getRowByDestination
MigrateSQLMap::getRowBySource public function Retrieve a row from the map table, given a source ID. Overrides MigrateMap::getRowBySource
MigrateSQLMap::getRowsNeedingUpdate public function Retrieve an array of map rows marked as needing update. Overrides MigrateMap::getRowsNeedingUpdate
MigrateSQLMap::getSourceKey public function sourceKey and destinationKey arrays are keyed by the field names; values are the Drupal schema definition for the field. Overrides MigrateMap::getSourceKey
MigrateSQLMap::importedCount public function Returns a count of imported records in the map table. Overrides MigrateMap::importedCount
MigrateSQLMap::key public function Implementation of Iterator::key - called when entering a loop iteration, returning the key of the current row. It must be a scalar - we will serialize to fulfill the requirement, but using getCurrentKey() is preferable.
MigrateSQLMap::lookupDestinationID public function Given a (possibly multi-field) source key, return the (possibly multi-field) destination key it is mapped to. Overrides MigrateMap::lookupDestinationID
MigrateSQLMap::lookupSourceID public function Given a (possibly multi-field) destination key, return the (possibly multi-field) source key mapped to it. Overrides MigrateMap::lookupSourceID
MigrateSQLMap::messageCount public function Get the number of messages saved. Overrides MigrateMap::messageCount
MigrateSQLMap::next public function Implementation of Iterator::next() - called at the bottom of the loop implicitly, as well as explicitly from rewind().
MigrateSQLMap::prepareUpdate public function Prepares this migration to run as an update - that is, in addition to unmigrated content (source records not in the map table) being imported, previously-migrated content will also be updated in place. Overrides MigrateMap::prepareUpdate
MigrateSQLMap::processedCount public function Returns a count of records in the map table (i.e., the number of source records which have been processed for this migration). Overrides MigrateMap::processedCount
MigrateSQLMap::rewind public function Implementation of Iterator::rewind() - called before beginning a foreach loop. TODO: Support idlist, itemlimit.
MigrateSQLMap::saveMessage public function Record a message in the migration's message table. Overrides MigrateMap::saveMessage
MigrateSQLMap::setUpdate public function Set the specified row to be updated, if it exists.
MigrateSQLMap::updateCount public function Returns a count of records which are marked as needing update.
MigrateSQLMap::valid public function Implementation of Iterator::valid() - called at the top of the loop, returning TRUE to process the loop and FALSE to terminate it.