You are here

class MigrateExecutable in Migrate Tools 8.2

Same name and namespace in other branches
  1. 8.5 src/MigrateExecutable.php \Drupal\migrate_tools\MigrateExecutable
  2. 8 src/MigrateExecutable.php \Drupal\migrate_tools\MigrateExecutable
  3. 8.3 src/MigrateExecutable.php \Drupal\migrate_tools\MigrateExecutable
  4. 8.4 src/MigrateExecutable.php \Drupal\migrate_tools\MigrateExecutable

Hierarchy

Expanded class hierarchy of MigrateExecutable

1 file declares its use of MigrateExecutable
migrate_tools.drush.inc in ./migrate_tools.drush.inc
Command-line tools to aid performing and developing migrations.

File

src/MigrateExecutable.php, line 20

Namespace

Drupal\migrate_tools
View source
class MigrateExecutable extends MigrateExecutableBase {

  /**
   * Counters of map statuses.
   *
   * @var array
   *   Set of counters, keyed by MigrateIdMapInterface::STATUS_* constant.
   */
  protected $saveCounters = array(
    MigrateIdMapInterface::STATUS_FAILED => 0,
    MigrateIdMapInterface::STATUS_IGNORED => 0,
    MigrateIdMapInterface::STATUS_IMPORTED => 0,
    MigrateIdMapInterface::STATUS_NEEDS_UPDATE => 0,
  );

  /**
   * Counter of map deletions.
   *
   * @var int
   */
  protected $deleteCounter = 0;

  /**
   * Maximum number of items to process in this migration. 0 indicates no limit
   * is to be applied.
   *
   * @var int
   */
  protected $itemLimit = 0;

  /**
   * Frequency (in items) at which progress messages should be emitted.
   *
   * @var int
   */
  protected $feedback = 0;

  /**
   * List of specific source IDs to import.
   *
   * @var array
   */
  protected $idlist = [];

  /**
   * Count of number of items processed so far in this migration.
   * @var int
   */
  protected $counter = 0;

  /**
   * Whether the destination item exists before saving.
   *
   * @var bool
   */
  protected $preExistingItem = FALSE;

  /**
   * List of event listeners we have registered.
   *
   * @var array
   */
  protected $listeners = [];

  /**
   * {@inheritdoc}
   */
  public function __construct(MigrationInterface $migration, MigrateMessageInterface $message, array $options = []) {
    parent::__construct($migration, $message);
    if (isset($options['limit'])) {
      $this->itemLimit = $options['limit'];
    }
    if (isset($options['feedback'])) {
      $this->feedback = $options['feedback'];
    }
    if (isset($options['idlist'])) {
      $this->idlist = explode(',', $options['idlist']);
      array_walk($this->idlist, function (&$value, $key) {
        $value = explode(':', $value);
      });
    }
    $this->listeners[MigrateEvents::MAP_SAVE] = [
      $this,
      'onMapSave',
    ];
    $this->listeners[MigrateEvents::MAP_DELETE] = [
      $this,
      'onMapDelete',
    ];
    $this->listeners[MigrateEvents::POST_IMPORT] = [
      $this,
      'onPostImport',
    ];
    $this->listeners[MigrateEvents::POST_ROLLBACK] = [
      $this,
      'onPostRollback',
    ];
    $this->listeners[MigrateEvents::PRE_ROW_SAVE] = [
      $this,
      'onPreRowSave',
    ];
    $this->listeners[MigrateEvents::POST_ROW_DELETE] = [
      $this,
      'onPostRowDelete',
    ];
    $this->listeners[MigratePlusEvents::PREPARE_ROW] = [
      $this,
      'onPrepareRow',
    ];
    foreach ($this->listeners as $event => $listener) {
      \Drupal::service('event_dispatcher')
        ->addListener($event, $listener);
    }
  }

  /**
   * Count up any map save events.
   *
   * @param \Drupal\migrate\Event\MigrateMapSaveEvent $event
   *   The map event.
   */
  public function onMapSave(MigrateMapSaveEvent $event) {

    // Only count saves for this migration.
    if ($event
      ->getMap()
      ->getQualifiedMapTableName() == $this->migration
      ->getIdMap()
      ->getQualifiedMapTableName()) {
      $fields = $event
        ->getFields();

      // Distinguish between creation and update.
      if ($fields['source_row_status'] == MigrateIdMapInterface::STATUS_IMPORTED && $this->preExistingItem) {
        $this->saveCounters[MigrateIdMapInterface::STATUS_NEEDS_UPDATE]++;
      }
      else {
        $this->saveCounters[$fields['source_row_status']]++;
      }
    }
  }

  /**
   * Count up any rollback events.
   *
   * @param \Drupal\migrate\Event\MigrateMapDeleteEvent $event
   *   The map event.
   */
  public function onMapDelete(MigrateMapDeleteEvent $event) {
    $this->deleteCounter++;
  }

  /**
   * Return the number of items created.
   *
   * @return int
   */
  public function getCreatedCount() {
    return $this->saveCounters[MigrateIdMapInterface::STATUS_IMPORTED];
  }

  /**
   * Return the number of items updated.
   *
   * @return int
   */
  public function getUpdatedCount() {
    return $this->saveCounters[MigrateIdMapInterface::STATUS_NEEDS_UPDATE];
  }

  /**
   * Return the number of items ignored.
   *
   * @return int
   */
  public function getIgnoredCount() {
    return $this->saveCounters[MigrateIdMapInterface::STATUS_IGNORED];
  }

  /**
   * Return the number of items that failed.
   *
   * @return int
   */
  public function getFailedCount() {
    return $this->saveCounters[MigrateIdMapInterface::STATUS_FAILED];
  }

  /**
   * Return the total number of items processed. Note that STATUS_NEEDS_UPDATE
   * is not counted, since this is typically set on stubs created as side
   * effects, not on the primary item being imported.
   *
   * @return int
   */
  public function getProcessedCount() {
    return $this->saveCounters[MigrateIdMapInterface::STATUS_IMPORTED] + $this->saveCounters[MigrateIdMapInterface::STATUS_NEEDS_UPDATE] + $this->saveCounters[MigrateIdMapInterface::STATUS_IGNORED] + $this->saveCounters[MigrateIdMapInterface::STATUS_FAILED];
  }

  /**
   * Return the number of items rolled back.
   *
   * @return int
   */
  public function getRollbackCount() {
    return $this->deleteCounter;
  }

  /**
   * Reset all the per-status counters to 0.
   */
  protected function resetCounters() {
    foreach ($this->saveCounters as $status => $count) {
      $this->saveCounters[$status] = 0;
    }
    $this->deleteCounter = 0;
  }

  /**
   * React to migration completion.
   *
   * @param \Drupal\migrate\Event\MigrateImportEvent $event
   *   The map event.
   */
  public function onPostImport(MigrateImportEvent $event) {
    $migrate_last_imported_store = \Drupal::keyValue('migrate_last_imported');
    $migrate_last_imported_store
      ->set($event
      ->getMigration()
      ->id(), round(microtime(TRUE) * 1000));
    $this
      ->progressMessage();
    $this
      ->removeListeners();
  }

  /**
   * Clean up all our event listeners.
   */
  protected function removeListeners() {
    foreach ($this->listeners as $event => $listener) {
      \Drupal::service('event_dispatcher')
        ->removeListener($event, $listener);
    }
  }

  /**
   * Emit information on what we've done since the last feedback (or the
   * beginning of this migration).
   *
   * @param bool $done
   */
  protected function progressMessage($done = TRUE) {
    $processed = $this
      ->getProcessedCount();
    if ($done) {
      $singular_message = "Processed 1 item (@created created, @updated updated, @failures failed, @ignored ignored) - done with '@name'";
      $plural_message = "Processed @numitems items (@created created, @updated updated, @failures failed, @ignored ignored) - done with '@name'";
    }
    else {
      $singular_message = "Processed 1 item (@created created, @updated updated, @failures failed, @ignored ignored) - continuing with '@name'";
      $plural_message = "Processed @numitems items (@created created, @updated updated, @failures failed, @ignored ignored) - continuing with '@name'";
    }
    $this->message
      ->display(\Drupal::translation()
      ->formatPlural($processed, $singular_message, $plural_message, array(
      '@numitems' => $processed,
      '@created' => $this
        ->getCreatedCount(),
      '@updated' => $this
        ->getUpdatedCount(),
      '@failures' => $this
        ->getFailedCount(),
      '@ignored' => $this
        ->getIgnoredCount(),
      '@name' => $this->migration
        ->id(),
    )));
  }

  /**
   * React to rollback completion.
   *
   * @param \Drupal\migrate\Event\MigrateRollbackEvent $event
   *   The map event.
   */
  public function onPostRollback(MigrateRollbackEvent $event) {
    $this
      ->rollbackMessage();
    $this
      ->removeListeners();
  }

  /**
   * Emit information on what we've done since the last feedback (or the
   * beginning of this migration).
   *
   * @param bool $done
   */
  protected function rollbackMessage($done = TRUE) {
    $rolled_back = $this
      ->getRollbackCount();
    if ($done) {
      $singular_message = "Rolled back 1 item - done with '@name'";
      $plural_message = "Rolled back @numitems items - done with '@name'";
    }
    else {
      $singular_message = "Rolled back 1 item - continuing with '@name'";
      $plural_message = "Rolled back @numitems items - continuing with '@name'";
    }
    $this->message
      ->display(\Drupal::translation()
      ->formatPlural($rolled_back, $singular_message, $plural_message, array(
      '@numitems' => $rolled_back,
      '@name' => $this->migration
        ->id(),
    )));
  }

  /**
   * React to an item about to be imported.
   *
   * @param \Drupal\migrate\Event\MigratePreRowSaveEvent $event
   *   The pre-save event.
   */
  public function onPreRowSave(MigratePreRowSaveEvent $event) {
    $id_map = $event
      ->getRow()
      ->getIdMap();
    if (!empty($id_map['destid1'])) {
      $this->preExistingItem = TRUE;
    }
    else {
      $this->preExistingItem = FALSE;
    }
  }

  /**
   * React to item rollback.
   *
   * @param \Drupal\migrate\Event\MigrateRowDeleteEvent $event
   *   The post-save event.
   */
  public function onPostRowDelete(MigrateRowDeleteEvent $event) {
    if ($this->feedback && $this->deleteCounter && $this->deleteCounter % $this->feedback == 0) {
      $this
        ->rollbackMessage(FALSE);
      $this
        ->resetCounters();
    }
  }

  /**
   * React to a new row.
   *
   * @param \Drupal\migrate_plus\Event\MigratePrepareRowEvent $event
   *   The prepare-row event.
   *
   * @throws \Drupal\migrate\MigrateSkipRowException
   *
   */
  public function onPrepareRow(MigratePrepareRowEvent $event) {
    if (!empty($this->idlist)) {
      $row = $event
        ->getRow();

      /**
       * @TODO replace for $source_id = $row->getSourceIdValues(); when https://www.drupal.org/node/2698023 is fixed
       */
      $migration = $event
        ->getMigration();
      $source_id = array_merge(array_flip(array_keys($migration
        ->getSourcePlugin()
        ->getIds())), $row
        ->getSourceIdValues());
      $skip = TRUE;
      foreach ($this->idlist as $item) {
        if (array_values($source_id) === $item) {
          $skip = FALSE;
          break;
        }
      }
      if ($skip) {
        throw new MigrateSkipRowException(NULL, FALSE);
      }
    }
    if ($this->feedback && $this->counter && $this->counter % $this->feedback == 0) {
      $this
        ->progressMessage(FALSE);
      $this
        ->resetCounters();
    }
    $this->counter++;
    if ($this->itemLimit && $this
      ->getProcessedCount() + 1 >= $this->itemLimit) {
      $event
        ->getMigration()
        ->interruptMigration(MigrationInterface::RESULT_COMPLETED);
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
MigrateExecutable::$counter protected property Count of number of items processed so far in this migration.
MigrateExecutable::$counts protected property An array of counts. Initially used for cache hit/miss tracking.
MigrateExecutable::$deleteCounter protected property Counter of map deletions.
MigrateExecutable::$eventDispatcher protected property The event dispatcher.
MigrateExecutable::$feedback protected property Frequency (in items) at which progress messages should be emitted.
MigrateExecutable::$idlist protected property List of specific source IDs to import.
MigrateExecutable::$itemLimit protected property Maximum number of items to process in this migration. 0 indicates no limit is to be applied.
MigrateExecutable::$listeners protected property List of event listeners we have registered.
MigrateExecutable::$memoryLimit protected property The PHP memory_limit expressed in bytes.
MigrateExecutable::$memoryThreshold protected property The ratio of the memory limit at which an operation will be interrupted.
MigrateExecutable::$message public property Migration message service.
MigrateExecutable::$migration protected property The configuration of the migration to do.
MigrateExecutable::$preExistingItem protected property Whether the destination item exists before saving.
MigrateExecutable::$saveCounters protected property Counters of map statuses.
MigrateExecutable::$source protected property The source.
MigrateExecutable::$sourceIdValues protected property The configuration values of the source.
MigrateExecutable::$sourceRowStatus protected property Status of one row.
MigrateExecutable::attemptMemoryReclaim protected function Tries to reclaim memory. 1
MigrateExecutable::checkStatus protected function Checks for exceptional conditions, and display feedback.
MigrateExecutable::currentSourceIds protected function Fetches the key array for the current source record.
MigrateExecutable::formatSize protected function Generates a string representation for the given byte count. 1
MigrateExecutable::getCreatedCount public function Return the number of items created.
MigrateExecutable::getEventDispatcher protected function Gets the event dispatcher.
MigrateExecutable::getFailedCount public function Return the number of items that failed.
MigrateExecutable::getIdMap protected function Get the ID map from the current migration. 1
MigrateExecutable::getIgnoredCount public function Return the number of items ignored.
MigrateExecutable::getMemoryUsage protected function Returns the memory usage so far. 1
MigrateExecutable::getProcessedCount public function Return the total number of items processed. Note that STATUS_NEEDS_UPDATE is not counted, since this is typically set on stubs created as side effects, not on the primary item being imported.
MigrateExecutable::getRollbackCount public function Return the number of items rolled back.
MigrateExecutable::getSource protected function Returns the source. 1
MigrateExecutable::getUpdatedCount public function Return the number of items updated.
MigrateExecutable::handleException protected function Takes an Exception object and both saves and displays it. 1
MigrateExecutable::import public function Performs an import operation - migrate items from source to destination. Overrides MigrateExecutableInterface::import
MigrateExecutable::memoryExceeded protected function Tests whether we've exceeded the desired memory threshold. 1
MigrateExecutable::onMapDelete public function Count up any rollback events.
MigrateExecutable::onMapSave public function Count up any map save events.
MigrateExecutable::onPostImport public function React to migration completion.
MigrateExecutable::onPostRollback public function React to rollback completion.
MigrateExecutable::onPostRowDelete public function React to item rollback.
MigrateExecutable::onPrepareRow public function React to a new row.
MigrateExecutable::onPreRowSave public function React to an item about to be imported.
MigrateExecutable::processRow public function Processes a row. Overrides MigrateExecutableInterface::processRow
MigrateExecutable::progressMessage protected function Emit information on what we've done since the last feedback (or the beginning of this migration).
MigrateExecutable::removeListeners protected function Clean up all our event listeners.
MigrateExecutable::resetCounters protected function Reset all the per-status counters to 0.
MigrateExecutable::rollback public function Performs a rollback operation - remove previously-imported items. Overrides MigrateExecutableInterface::rollback
MigrateExecutable::rollbackMessage protected function Emit information on what we've done since the last feedback (or the beginning of this migration).
MigrateExecutable::saveMessage public function Passes messages through to the map class. Overrides MigrateExecutableInterface::saveMessage
MigrateExecutable::__construct public function Constructs a MigrateExecutable and verifies and sets the memory limit. Overrides MigrateExecutable::__construct
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.