Updated all the contrib modules to their latest versions.
[yaffs-website] / web / modules / contrib / migrate_tools / src / MigrateBatchExecutable.php
diff --git a/web/modules/contrib/migrate_tools/src/MigrateBatchExecutable.php b/web/modules/contrib/migrate_tools/src/MigrateBatchExecutable.php
new file mode 100644 (file)
index 0000000..ee24f64
--- /dev/null
@@ -0,0 +1,295 @@
+<?php
+
+namespace Drupal\migrate_tools;
+
+use Drupal\migrate\MigrateMessage;
+use Drupal\migrate\MigrateMessageInterface;
+use Drupal\migrate\Plugin\Migration;
+use Drupal\migrate\Plugin\MigrationInterface;
+
+/**
+ * Defines a migrate executable class for batch migrations through UI.
+ */
+class MigrateBatchExecutable extends MigrateExecutable {
+
+  /**
+   * Representing a batch import operation.
+   */
+  const BATCH_IMPORT = 1;
+
+  /**
+   * Indicates if we need to update existing rows or skip them.
+   *
+   * @var int
+   */
+  protected $updateExistingRows = 0;
+
+  /**
+   * Indicates if we need import dependent migrations also.
+   *
+   * @var int
+   */
+  protected $checkDependencies = 0;
+
+  /**
+   * The current batch context.
+   *
+   * @var array
+   */
+  protected $batchContext = [];
+
+  /**
+   * Plugin manager for migration plugins.
+   *
+   * @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface
+   */
+  protected $migrationPluginManager;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(MigrationInterface $migration, MigrateMessageInterface $message, array $options = []) {
+
+    if (isset($options['update'])) {
+      $this->updateExistingRows = $options['update'];
+    }
+
+    if (isset($options['force'])) {
+      $this->checkDependencies = $options['force'];
+    }
+
+    parent::__construct($migration, $message, $options);
+    $this->migrationPluginManager = \Drupal::getContainer()->get('plugin.manager.migration');
+  }
+
+  /**
+   * Sets the current batch content so listeners can update the messages.
+   *
+   * @param array $context
+   *   The batch context.
+   */
+  public function setBatchContext(array &$context) {
+    $this->batchContext = &$context;
+  }
+
+  /**
+   * Gets a reference to the current batch context.
+   *
+   * @return array
+   *   The batch context.
+   */
+  public function &getBatchContext() {
+    return $this->batchContext;
+  }
+
+  /**
+   * Setup batch operations for running the migration.
+   */
+  public function batchImport() {
+    // Create the batch operations for each migration that needs to be executed.
+    // This includes the migration for this executable, but also the dependent
+    // migrations.
+    $operations = $this->batchOperations([$this->migration], 'import', [
+      'limit' => $this->itemLimit,
+      'update' => $this->updateExistingRows,
+      'force' => $this->checkDependencies,
+    ]);
+
+    if (count($operations) > 0) {
+      $batch = [
+        'operations' => $operations,
+        'title' => t('Migrating %migrate', ['%migrate' => $this->migration->label()]),
+        'init_message' => t('Start migrating %migrate', ['%migrate' => $this->migration->label()]),
+        'progress_message' => t('Migrating %migrate', ['%migrate' => $this->migration->label()]),
+        'error_message' => t('An error occurred while migrating %migrate.', ['%migrate' => $this->migration->label()]),
+        'finished' => '\Drupal\migrate_tools\MigrateBatchExecutable::batchFinishedImport',
+      ];
+
+      batch_set($batch);
+    }
+  }
+
+  /**
+   * Helper to generate the batch operations for importing migrations.
+   *
+   * @param \Drupal\migrate\Plugin\MigrationInterface[] $migrations
+   *   The migrations.
+   * @param string $operation
+   *   The batch operation to perform.
+   * @param array $options
+   *   The migration options.
+   *
+   * @return array
+   *   The batch operations to perform.
+   */
+  protected function batchOperations(array $migrations, $operation, array $options = []) {
+    $operations = [];
+    foreach ($migrations as $id => $migration) {
+
+      if (!empty($options['update'])) {
+        $migration->getIdMap()->prepareUpdate();
+      }
+
+      if (!empty($options['force'])) {
+        $migration->set('requirements', []);
+      }
+      else {
+        $dependencies = $migration->getMigrationDependencies();
+        if (!empty($dependencies['required'])) {
+          $required_migrations = $this->migrationPluginManager->createInstances($dependencies['required']);
+          // For dependent migrations will need to be migrate all items.
+          $dependent_options = $options;
+          $dependent_options['limit'] = 0;
+          $operations += $this->batchOperations($required_migrations, $operation, [
+            'limit' => 0,
+            'update' => $options['update'],
+            'force' => $options['force'],
+          ]);
+        }
+      }
+
+      $operations[] = [
+        '\Drupal\migrate_tools\MigrateBatchExecutable::batchProcessImport',
+        [$migration->id(), $options],
+      ];
+    }
+
+    return $operations;
+  }
+
+  /**
+   * Batch 'operation' callback.
+   *
+   * @param string $migration_id
+   *   The migration id.
+   * @param array $options
+   *   The batch executable options.
+   * @param array $context
+   *   The sandbox context.
+   */
+  public static function batchProcessImport($migration_id, array $options, array &$context) {
+    if (empty($context['sandbox'])) {
+      $context['finished'] = 0;
+      $context['sandbox'] = [];
+      $context['sandbox']['total'] = 0;
+      $context['sandbox']['counter'] = 0;
+      $context['sandbox']['batch_limit'] = 0;
+      $context['sandbox']['operation'] = MigrateBatchExecutable::BATCH_IMPORT;
+    }
+
+    // Prepare the migration executable.
+    $message = new MigrateMessage();
+    /** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
+    $migration = \Drupal::getContainer()->get('plugin.manager.migration')->createInstance($migration_id);
+    $executable = new MigrateBatchExecutable($migration, $message, $options);
+
+    if (empty($context['sandbox']['total'])) {
+      $context['sandbox']['total'] = $executable->getSource()->count();
+      $context['sandbox']['batch_limit'] = $executable->calculateBatchLimit($context);
+      $context['results'][$migration->id()] = [
+        '@numitems' => 0,
+        '@created' => 0,
+        '@updated' => 0,
+        '@failures' => 0,
+        '@ignored' => 0,
+        '@name' => $migration->id(),
+      ];
+    }
+
+    // Every iteration, we reset out batch counter.
+    $context['sandbox']['batch_counter'] = 0;
+
+    // Make sure we know our batch context.
+    $executable->setBatchContext($context);
+
+    // Do the import.
+    $result = $executable->import();
+
+    // Store the result; will need to combine the results of all our iterations.
+    $context['results'][$migration->id()] = [
+      '@numitems' => $context['results'][$migration->id()]['@numitems'] + $executable->getProcessedCount(),
+      '@created' => $context['results'][$migration->id()]['@created'] + $executable->getCreatedCount(),
+      '@updated' => $context['results'][$migration->id()]['@updated'] + $executable->getUpdatedCount(),
+      '@failures' => $context['results'][$migration->id()]['@failures'] + $executable->getFailedCount(),
+      '@ignored' => $context['results'][$migration->id()]['@ignored'] + $executable->getIgnoredCount(),
+      '@name' => $migration->id(),
+    ];
+
+    // Do some housekeeping.
+    if (
+      $result != MigrationInterface::RESULT_INCOMPLETE
+    ) {
+      $context['finished'] = 1;
+    }
+    else {
+      $context['sandbox']['counter'] = $context['results'][$migration->id()]['@numitems'];
+      if ($context['sandbox']['counter'] <= $context['sandbox']['total']) {
+        $context['finished'] = ((float) $context['sandbox']['counter'] / (float) $context['sandbox']['total']);
+        $context['message'] = t('Importing %migration (@percent%).', [
+          '%migration' => $migration->label(),
+          '@percent' => (int) ($context['finished'] * 100),
+        ]);
+      }
+    }
+
+  }
+
+  /**
+   * Finished callback for import batches.
+   *
+   * @param bool $success
+   *   A boolean indicating whether the batch has completed successfully.
+   * @param array $results
+   *   The value set in $context['results'] by callback_batch_operation().
+   * @param array $operations
+   *   If $success is FALSE, contains the operations that remained unprocessed.
+   */
+  public static function batchFinishedImport($success, array $results, array $operations) {
+    if ($success) {
+      foreach ($results as $migration_id => $result) {
+        $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'";
+        drupal_set_message(\Drupal::translation()->formatPlural($result['@numitems'],
+          $singular_message,
+          $plural_message,
+          $result));
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function checkStatus() {
+    $status = parent::checkStatus();
+
+    if ($status == MigrationInterface::RESULT_COMPLETED) {
+      // Do some batch housekeeping.
+      $context = $this->getBatchContext();
+
+      if (!empty($context['sandbox']) && $context['sandbox']['operation'] == MigrateBatchExecutable::BATCH_IMPORT) {
+        $context['sandbox']['batch_counter']++;
+        if ($context['sandbox']['batch_counter'] >= $context['sandbox']['batch_limit']) {
+          $status = MigrationInterface::RESULT_INCOMPLETE;
+        }
+      }
+    }
+
+    return $status;
+  }
+
+  /**
+   * Calculates how much a single batch iteration will handle.
+   *
+   * @param array $context
+   *   The sandbox context.
+   *
+   * @return float
+   *   The batch limit.
+   */
+  public function calculateBatchLimit(array $context) {
+    // TODO Maybe we need some other more sophisticated logic here?
+    return ceil($context['sandbox']['total'] / 100);
+  }
+
+}