Code Coverage  | 
     ||||||||||
Classes and Traits  | 
      Functions and Methods  | 
      Lines  | 
     ||||||||
| Total |         | 
      0.00%  | 
      0 / 1  | 
              | 
      0.00%  | 
      0 / 29  | 
      CRAP |         | 
      15.74%  | 
      17 / 108  | 
     
| Migration |         | 
      0.00%  | 
      0 / 1  | 
              | 
      0.00%  | 
      0 / 29  | 
      2070.37 |         | 
      15.74%  | 
      17 / 108  | 
     
| getSourcePlugin |         | 
      0.00%  | 
      0 / 1  | 
      6 |         | 
      0.00%  | 
      0 / 3  | 
     |||
| getProcessPlugins |         | 
      0.00%  | 
      0 / 1  | 
      21.82 |         | 
      40.00%  | 
      6 / 15  | 
     |||
| getProcessNormalized |         | 
      0.00%  | 
      0 / 1  | 
      20 |         | 
      0.00%  | 
      0 / 9  | 
     |||
| getDestinationPlugin |         | 
      0.00%  | 
      0 / 1  | 
      20 |         | 
      0.00%  | 
      0 / 5  | 
     |||
| getIdMap |         | 
      0.00%  | 
      0 / 1  | 
      12 |         | 
      0.00%  | 
      0 / 5  | 
     |||
| getHighWaterStorage |         | 
      0.00%  | 
      0 / 1  | 
      6 |         | 
      0.00%  | 
      0 / 3  | 
     |||
| getHighWater |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 1  | 
     |||
| saveHighWater |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 2  | 
     |||
| checkRequirements |         | 
      0.00%  | 
      0 / 1  | 
      6.02 |         | 
      91.67%  | 
      11 / 12  | 
     |||
| getEntityManager |         | 
      0.00%  | 
      0 / 1  | 
      6 |         | 
      0.00%  | 
      0 / 3  | 
     |||
| setStatus |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 2  | 
     |||
| getStatus |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 1  | 
     |||
| getStatusLabel |         | 
      0.00%  | 
      0 / 1  | 
      6 |         | 
      0.00%  | 
      0 / 4  | 
     |||
| getInterruptionResult |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 1  | 
     |||
| clearInterruptionResult |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 2  | 
     |||
| interruptMigration |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 3  | 
     |||
| allRowsProcessed |         | 
      0.00%  | 
      0 / 1  | 
      6 |         | 
      0.00%  | 
      0 / 5  | 
     |||
| set |         | 
      0.00%  | 
      0 / 1  | 
      12 |         | 
      0.00%  | 
      0 / 5  | 
     |||
| getProcess |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 1  | 
     |||
| setProcess |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 2  | 
     |||
| setProcessOfProperty |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 2  | 
     |||
| mergeProcessOfProperty |         | 
      0.00%  | 
      0 / 1  | 
      6 |         | 
      0.00%  | 
      0 / 5  | 
     |||
| getSystemOfRecord |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 1  | 
     |||
| setSystemOfRecord |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 2  | 
     |||
| isTrackLastImported |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 1  | 
     |||
| setTrackLastImported |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 2  | 
     |||
| getMigrationDependencies |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 1  | 
     |||
| trustData |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 2  | 
     |||
| calculateDependencies |         | 
      0.00%  | 
      0 / 1  | 
      6 |         | 
      0.00%  | 
      0 / 8  | 
     |||
| <?php | |
| /** | |
| * @file | |
| * Contains \Drupal\migrate\Entity\Migration. | |
| */ | |
| namespace Drupal\migrate\Entity; | |
| use Drupal\Core\Config\Entity\ConfigEntityBase; | |
| use Drupal\migrate\Exception\RequirementsException; | |
| use Drupal\migrate\MigrateException; | |
| use Drupal\migrate\MigrateSkipRowException; | |
| use Drupal\migrate\Plugin\MigrateIdMapInterface; | |
| use Drupal\migrate\Plugin\RequirementsInterface; | |
| use Drupal\Component\Utility\NestedArray; | |
| /** | |
| * Defines the Migration entity. | |
| * | |
| * The migration entity stores the information about a single migration, like | |
| * the source, process and destination plugins. | |
| * | |
| * @ConfigEntityType( | |
| * id = "migration", | |
| * label = @Translation("Migration"), | |
| * handlers = { | |
| * "storage" = "Drupal\migrate\MigrationStorage" | |
| * }, | |
| * entity_keys = { | |
| * "id" = "id", | |
| * "label" = "label", | |
| * "weight" = "weight" | |
| * } | |
| * ) | |
| */ | |
| class Migration extends ConfigEntityBase implements MigrationInterface, RequirementsInterface { | |
| /** | |
| * The migration ID (machine name). | |
| * | |
| * @var string | |
| */ | |
| protected $id; | |
| /** | |
| * The human-readable label for the migration. | |
| * | |
| * @var string | |
| */ | |
| protected $label; | |
| /** | |
| * The plugin ID for the row. | |
| * | |
| * @var string | |
| */ | |
| protected $row; | |
| /** | |
| * The source configuration, with at least a 'plugin' key. | |
| * | |
| * Used to initialize the $sourcePlugin. | |
| * | |
| * @var array | |
| */ | |
| protected $source; | |
| /** | |
| * The source plugin. | |
| * | |
| * @var \Drupal\migrate\Plugin\MigrateSourceInterface | |
| */ | |
| protected $sourcePlugin; | |
| /** | |
| * The configuration describing the process plugins. | |
| * | |
| * This is a strictly internal property and should not returned to calling | |
| * code, use getProcess() instead. | |
| * | |
| * @var array | |
| */ | |
| protected $process = []; | |
| /** | |
| * The cached process plugins. | |
| * | |
| * @var array | |
| */ | |
| protected $processPlugins = []; | |
| /** | |
| * The destination configuration, with at least a 'plugin' key. | |
| * | |
| * Used to initialize $destinationPlugin. | |
| * | |
| * @var array | |
| */ | |
| protected $destination; | |
| /** | |
| * The destination plugin. | |
| * | |
| * @var \Drupal\migrate\Plugin\MigrateDestinationInterface | |
| */ | |
| protected $destinationPlugin; | |
| /** | |
| * The identifier map data. | |
| * | |
| * Used to initialize $idMapPlugin. | |
| * | |
| * @var string | |
| */ | |
| protected $idMap = []; | |
| /** | |
| * The identifier map. | |
| * | |
| * @var \Drupal\migrate\Plugin\MigrateIdMapInterface | |
| */ | |
| protected $idMapPlugin; | |
| /** | |
| * The source identifiers. | |
| * | |
| * An array of source identifiers: the keys are the name of the properties, | |
| * the values are dependent on the ID map plugin. | |
| * | |
| * @var array | |
| */ | |
| protected $sourceIds = []; | |
| /** | |
| * The destination identifiers. | |
| * | |
| * An array of destination identifiers: the keys are the name of the | |
| * properties, the values are dependent on the ID map plugin. | |
| * | |
| * @var array | |
| */ | |
| protected $destinationIds = []; | |
| /** | |
| * Information on the high water mark. | |
| * | |
| * @var array | |
| */ | |
| protected $highWaterProperty; | |
| /** | |
| * Indicate whether the primary system of record for this migration is the | |
| * source, or the destination (Drupal). In the source case, migration of | |
| * an existing object will completely replace the Drupal object with data from | |
| * the source side. In the destination case, the existing Drupal object will | |
| * be loaded, then changes from the source applied; also, rollback will not be | |
| * supported. | |
| * | |
| * @var string | |
| */ | |
| protected $systemOfRecord = self::SOURCE; | |
| /** | |
| * Specify value of source_row_status for current map row. Usually set by | |
| * MigrateFieldHandler implementations. | |
| * | |
| * @var int | |
| */ | |
| protected $sourceRowStatus = MigrateIdMapInterface::STATUS_IMPORTED; | |
| /** | |
| * @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface | |
| */ | |
| protected $highWaterStorage; | |
| /** | |
| * Track time of last import if TRUE. | |
| * | |
| * @var bool | |
| */ | |
| protected $trackLastImported = FALSE; | |
| /** | |
| * These migrations must be already executed before this migration can run. | |
| * | |
| * @var array | |
| */ | |
| protected $requirements = []; | |
| /** | |
| * These migrations, if run, must be executed before this migration. | |
| * | |
| * These are different from the configuration dependencies. Migration | |
| * dependencies are only used to store relationships between migrations. | |
| * | |
| * The migration_dependencies value is structured like this: | |
| * @code | |
| * array( | |
| * 'required' => array( | |
| * // An array of migration IDs that must be run before this migration. | |
| * ), | |
| * 'optional' => array( | |
| * // An array of migration IDs that, if they exist, must be run before | |
| * // this migration. | |
| * ), | |
| * ); | |
| * @endcode | |
| * | |
| * @var array | |
| */ | |
| protected $migration_dependencies = []; | |
| /** | |
| * The migration's configuration dependencies. | |
| * | |
| * These store any dependencies on modules or other configuration (including | |
| * other migrations) that must be available before the migration can be | |
| * created. | |
| * | |
| * @see \Drupal\Core\Config\Entity\ConfigDependencyManager | |
| * | |
| * @var array | |
| */ | |
| protected $dependencies = []; | |
| /** | |
| * The ID of the template from which this migration was derived, if any. | |
| * | |
| * @var string|NULL | |
| */ | |
| protected $template; | |
| /** | |
| * The entity manager. | |
| * | |
| * @var \Drupal\Core\Entity\EntityManagerInterface | |
| */ | |
| protected $entityManager; | |
| /** | |
| * Labels corresponding to each defined status. | |
| * | |
| * @var array | |
| */ | |
| protected $statusLabels = [ | |
| self::STATUS_IDLE => 'Idle', | |
| self::STATUS_IMPORTING => 'Importing', | |
| self::STATUS_ROLLING_BACK => 'Rolling back', | |
| self::STATUS_STOPPING => 'Stopping', | |
| self::STATUS_DISABLED => 'Disabled', | |
| ]; | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getSourcePlugin() { | |
| if (!isset($this->sourcePlugin)) { | |
| $this->sourcePlugin = \Drupal::service('plugin.manager.migrate.source')->createInstance($this->source['plugin'], $this->source, $this); | |
| } | |
| return $this->sourcePlugin; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getProcessPlugins(array $process = NULL) { | |
| if (!isset($process)) { | |
| $process = $this->process; | |
| } | |
| $index = serialize($process); | |
| if (!isset($this->processPlugins[$index])) { | |
| $this->processPlugins[$index] = array(); | |
| foreach ($this->getProcessNormalized($process) as $property => $configurations) { | |
| $this->processPlugins[$index][$property] = array(); | |
| foreach ($configurations as $configuration) { | |
| if (isset($configuration['source'])) { | |
| $this->processPlugins[$index][$property][] = \Drupal::service('plugin.manager.migrate.process')->createInstance('get', $configuration, $this); | |
| } | |
| // Get is already handled. | |
| if ($configuration['plugin'] != 'get') { | |
| $this->processPlugins[$index][$property][] = \Drupal::service('plugin.manager.migrate.process')->createInstance($configuration['plugin'], $configuration, $this); | |
| } | |
| if (!$this->processPlugins[$index][$property]) { | |
| throw new MigrateException("Invalid process configuration for $property"); | |
| } | |
| } | |
| } | |
| } | |
| return $this->processPlugins[$index]; | |
| } | |
| /** | |
| * Resolve shorthands into a list of plugin configurations. | |
| * | |
| * @param array $process | |
| * A process configuration array. | |
| * | |
| * @return array | |
| * The normalized process configuration. | |
| */ | |
| protected function getProcessNormalized(array $process) { | |
| $normalized_configurations = array(); | |
| foreach ($process as $destination => $configuration) { | |
| if (is_string($configuration)) { | |
| $configuration = array( | |
| 'plugin' => 'get', | |
| 'source' => $configuration, | |
| ); | |
| } | |
| if (isset($configuration['plugin'])) { | |
| $configuration = array($configuration); | |
| } | |
| $normalized_configurations[$destination] = $configuration; | |
| } | |
| return $normalized_configurations; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getDestinationPlugin($stub_being_requested = FALSE) { | |
| if ($stub_being_requested && !empty($this->destination['no_stub'])) { | |
| throw new MigrateSkipRowException; | |
| } | |
| if (!isset($this->destinationPlugin)) { | |
| $this->destinationPlugin = \Drupal::service('plugin.manager.migrate.destination')->createInstance($this->destination['plugin'], $this->destination, $this); | |
| } | |
| return $this->destinationPlugin; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getIdMap() { | |
| if (!isset($this->idMapPlugin)) { | |
| $configuration = $this->idMap; | |
| $plugin = isset($configuration['plugin']) ? $configuration['plugin'] : 'sql'; | |
| $this->idMapPlugin = \Drupal::service('plugin.manager.migrate.id_map')->createInstance($plugin, $configuration, $this); | |
| } | |
| return $this->idMapPlugin; | |
| } | |
| /** | |
| * Get the high water storage object. | |
| * | |
| * @return \Drupal\Core\KeyValueStore\KeyValueStoreInterface | |
| * The storage object. | |
| */ | |
| protected function getHighWaterStorage() { | |
| if (!isset($this->highWaterStorage)) { | |
| $this->highWaterStorage = \Drupal::keyValue('migrate:high_water'); | |
| } | |
| return $this->highWaterStorage; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getHighWater() { | |
| return $this->getHighWaterStorage()->get($this->id()); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function saveHighWater($high_water) { | |
| $this->getHighWaterStorage()->set($this->id(), $high_water); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function checkRequirements() { | |
| // Check whether the current migration source and destination plugin | |
| // requirements are met or not. | |
| if ($this->getSourcePlugin() instanceof RequirementsInterface) { | |
| $this->getSourcePlugin()->checkRequirements(); | |
| } | |
| if ($this->getDestinationPlugin() instanceof RequirementsInterface) { | |
| $this->getDestinationPlugin()->checkRequirements(); | |
| } | |
| /** @var \Drupal\migrate\Entity\MigrationInterface[] $required_migrations */ | |
| $required_migrations = $this->getEntityManager()->getStorage('migration')->loadMultiple($this->requirements); | |
| $missing_migrations = array_diff($this->requirements, array_keys($required_migrations)); | |
| // Check if the dependencies are in good shape. | |
| foreach ($required_migrations as $migration_id => $required_migration) { | |
| if (!$required_migration->allRowsProcessed()) { | |
| $missing_migrations[] = $migration_id; | |
| } | |
| } | |
| if ($missing_migrations) { | |
| throw new RequirementsException('Missing migrations ' . implode(', ', $missing_migrations) . '.', ['requirements' => $missing_migrations]); | |
| } | |
| } | |
| /** | |
| * Get the entity manager. | |
| * | |
| * @return \Drupal\Core\Entity\EntityManagerInterface | |
| * The entity manager. | |
| */ | |
| protected function getEntityManager() { | |
| if (!isset($this->entityManager)) { | |
| $this->entityManager = \Drupal::entityManager(); | |
| } | |
| return $this->entityManager; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function setStatus($status) { | |
| \Drupal::keyValue('migrate_status')->set($this->id(), $status); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getStatus() { | |
| return \Drupal::keyValue('migrate_status')->get($this->id(), static::STATUS_IDLE); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getStatusLabel() { | |
| $status = $this->getStatus(); | |
| if (isset($this->statusLabels[$status])) { | |
| return $this->statusLabels[$status]; | |
| } | |
| else { | |
| return ''; | |
| } | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getInterruptionResult() { | |
| return \Drupal::keyValue('migrate_interruption_result')->get($this->id(), static::RESULT_INCOMPLETE); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function clearInterruptionResult() { | |
| \Drupal::keyValue('migrate_interruption_result')->delete($this->id()); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function interruptMigration($result) { | |
| $this->setStatus(MigrationInterface::STATUS_STOPPING); | |
| \Drupal::keyValue('migrate_interruption_result')->set($this->id(), $result); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function allRowsProcessed() { | |
| $source_count = $this->getSourcePlugin()->count(); | |
| // If the source is uncountable, we have no way of knowing if it's | |
| // complete, so stipulate that it is. | |
| if ($source_count < 0) { | |
| return TRUE; | |
| } | |
| $processed_count = $this->getIdMap()->processedCount(); | |
| // We don't use == because in some circumstances (like unresolved stubs | |
| // being created), the processed count may be higher than the available | |
| // source rows. | |
| return $source_count <= $processed_count; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function set($property_name, $value) { | |
| if ($property_name == 'source') { | |
| // Invalidate the source plugin. | |
| unset($this->sourcePlugin); | |
| } | |
| elseif ($property_name === 'destination') { | |
| // Invalidate the destination plugin. | |
| unset($this->destinationPlugin); | |
| } | |
| return parent::set($property_name, $value); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getProcess() { | |
| return $this->getProcessNormalized($this->process); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function setProcess(array $process) { | |
| $this->process = $process; | |
| return $this; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function setProcessOfProperty($property, $process_of_property) { | |
| $this->process[$property] = $process_of_property; | |
| return $this; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function mergeProcessOfProperty($property, array $process_of_property) { | |
| // If we already have a process value then merge the incoming process array | |
| //otherwise simply set it. | |
| $current_process = $this->getProcess(); | |
| if (isset($current_process[$property])) { | |
| $this->process = NestedArray::mergeDeepArray([$current_process, $this->getProcessNormalized([$property => $process_of_property])], TRUE); | |
| } | |
| else { | |
| $this->setProcessOfProperty($property, $process_of_property); | |
| } | |
| return $this; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getSystemOfRecord() { | |
| return $this->systemOfRecord; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function setSystemOfRecord($system_of_record) { | |
| $this->systemOfRecord = $system_of_record; | |
| return $this; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function isTrackLastImported() { | |
| return $this->trackLastImported; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function setTrackLastImported($track_last_imported) { | |
| $this->trackLastImported = (bool) $track_last_imported; | |
| return $this; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getMigrationDependencies() { | |
| return $this->migration_dependencies + ['required' => [], 'optional' => []]; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function trustData() { | |
| // Migrations cannot be trusted since they are often written by hand and not | |
| // through a UI. | |
| $this->trustedData = FALSE; | |
| return $this; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function calculateDependencies() { | |
| parent::calculateDependencies(); | |
| $this->calculatePluginDependencies($this->getSourcePlugin()); | |
| $this->calculatePluginDependencies($this->getDestinationPlugin()); | |
| // Add hard dependencies on required migrations. | |
| $dependencies = $this->getEntityManager()->getStorage($this->entityTypeId) | |
| ->getVariantIds($this->getMigrationDependencies()['required']); | |
| foreach ($dependencies as $dependency) { | |
| $this->addDependency('config', $this->getEntityType()->getConfigPrefix() . '.' . $dependency); | |
| } | |
| return $this; | |
| } | |
| } |