diff --git a/core/modules/migrate/src/Entity/MigrationInterface.php b/core/modules/migrate/src/Entity/MigrationInterface.php index 7bb4c1a..1c8eb60 100644 --- a/core/modules/migrate/src/Entity/MigrationInterface.php +++ b/core/modules/migrate/src/Entity/MigrationInterface.php @@ -105,6 +105,14 @@ public function id(); /** + * Get the plugin label. + * + * @return string + * The label for this migration. + */ + public function label(); + + /** * Returns the initialized source plugin. * * @return \Drupal\migrate\Plugin\MigrateSourceInterface diff --git a/core/modules/migrate/src/Plugin/Migration.php b/core/modules/migrate/src/Plugin/Migration.php index 180613e..733c27f 100644 --- a/core/modules/migrate/src/Plugin/Migration.php +++ b/core/modules/migrate/src/Plugin/Migration.php @@ -249,6 +249,13 @@ public function id() { } /** + * {@inheritdoc} + */ + public function label() { + return $this->label; + } + + /** * Gets any arbitrary property. * * @param string $property diff --git a/core/modules/migrate/src/Plugin/MigrationPluginManager.php b/core/modules/migrate/src/Plugin/MigrationPluginManager.php index 797a841..26116e3 100644 --- a/core/modules/migrate/src/Plugin/MigrationPluginManager.php +++ b/core/modules/migrate/src/Plugin/MigrationPluginManager.php @@ -7,6 +7,7 @@ namespace Drupal\migrate\Plugin; +use Drupal\Component\Plugin\PluginBase; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Language\LanguageManagerInterface; @@ -78,17 +79,61 @@ protected function getDiscovery() { /** * {@inheritdoc} */ - public function createInstances($id, array $configuration = array()) { + public function createInstances($migration_id, array $configuration = array()) { + if (empty($migration_id)) { + $migration_id = array_keys($this->getDefinitions()); + } + $factory = $this->getFactory(); + $migration_ids = (array) $migration_id; + $plugin_ids = $this->expandPluginIds($migration_ids); + $instances = []; - $plugin_ids = preg_grep('/^' . preg_quote($id, '/') . ':/', array_keys($this->getDefinitions())); - if ($this->hasDefinition($id)) { - $plugin_ids[] = $id; - } foreach ($plugin_ids as $plugin_id) { $instances[$plugin_id] = $factory->createInstance($plugin_id, isset($configuration[$plugin_id]) ? $configuration[$plugin_id] : []); } + return $instances; } + /** + * Create migrations given a tag. + * + * @param string $tag + * A migration tag we want to filter by. + * + * @return array|\Drupal\migrate\Entity\MigrationInterface[] + * An array of migration objects with the given tag. + */ + public function createInstancesByTag($tag) { + $migrations = array_filter($this->getDefinitions(), function($migration) use ($tag) { + return !empty($migration['migration_tags']) && in_array($tag, $migration['migration_tags']); + }); + return $this->createInstances(array_keys($migrations)); + } + + /** + * Expand derivative migration dependencies. + * + * We need to expand any derivative migrations. Derivative migrations are + * calculated by migration derivers such as D6NodeDeriver. This allows + * migrations to depend on the base id and then have a dependency on all + * derived migrations. For example, d6_comment depends on d6_node but after + * we've expanded the dependencies it will depend on d6_node:page, + * d6_node:story and so on, for derived migration. + * + * @return array + * An array of expanded plugin ids. + */ + protected function expandPluginIds(array $migration_ids) { + $plugin_ids = []; + foreach ($migration_ids as $id) { + $plugin_ids += preg_grep('/^' . preg_quote($id, '/') . PluginBase::DERIVATIVE_SEPARATOR . '/', array_keys($this->getDefinitions())); + if ($this->hasDefinition($id)) { + $plugin_ids[] = $id; + } + } + return $plugin_ids; + } + } diff --git a/core/modules/migrate/src/Plugin/MigrationPluginManagerInterface.php b/core/modules/migrate/src/Plugin/MigrationPluginManagerInterface.php index 105d2d4..87ec3c6 100644 --- a/core/modules/migrate/src/Plugin/MigrationPluginManagerInterface.php +++ b/core/modules/migrate/src/Plugin/MigrationPluginManagerInterface.php @@ -17,9 +17,10 @@ /** * Create pre-configured instance of plugin derivatives. * - * @param string $id + * @param array $id * Either the plugin ID or the base plugin ID of the plugins being - * instantiated. + * instantiated. Also accepts an array of plugin ids and an empty array to + * load all plugins. * @param array $configuration * An array of configuration relevant to the plugin instances. Keyed by the * plugin id. diff --git a/core/modules/migrate_drupal/src/MigrationCreationTrait.php b/core/modules/migrate_drupal/src/MigrationCreationTrait.php index 528b3e7..817429b 100644 --- a/core/modules/migrate_drupal/src/MigrationCreationTrait.php +++ b/core/modules/migrate_drupal/src/MigrationCreationTrait.php @@ -64,22 +64,17 @@ protected function getSystemData(array $database) { } /** - * Sets up the relevant migrations for import from a database connection. + * Get the database connection for the source database. * * @param array $database - * Database array representing the source Drupal database. - * @param string $source_base_path - * (Optional) Address of the source Drupal site (e.g., http://example.com/). + * The database connection. * - * @return array - * An array of the migration templates (parsed YAML config arrays) that were - * tagged for the identified source Drupal version. The templates are - * populated with database state key and file source base path information - * for execution. The array is keyed by migration IDs. + * @return \Drupal\Core\Database\Connection + * The database connection. * * @throws \Exception */ - protected function getMigrationTemplates(array $database, $source_base_path = '') { + protected function getSourceDatabaseConnection(array $database) { // Set up the connection. $connection = $this->getConnection($database); if (!$drupal_version = $this->getLegacyDrupalVersion($connection)) { @@ -90,44 +85,45 @@ protected function getMigrationTemplates(array $database, $source_base_path = '' $database_state_key = 'migrate_drupal_' . $drupal_version; \Drupal::state()->set($database_state_key, $database_state); - $version_tag = 'Drupal ' . $drupal_version; - - $template_storage = \Drupal::service('migrate.template_storage'); - $migration_templates = $template_storage->findTemplatesByTag($version_tag); - foreach ($migration_templates as $id => $template) { - $migration_templates[$id]['source']['database_state_key'] = $database_state_key; - // Configure file migrations so they can find the files. - if ($template['destination']['plugin'] == 'entity:file') { - if ($source_base_path) { - // Make sure we have a single trailing slash. - $source_base_path = rtrim($source_base_path, '/') . '/'; - $migration_templates[$id]['destination']['source_base_path'] = $source_base_path; - } - } - } - return $migration_templates; + return $connection; } /** * Gets the migrations for import. * - * Uses the migration template connection to ensure that only the relevant - * migrations are returned. - * - * @param array $migration_templates - * Migration templates (parsed YAML config arrays), keyed by the ID. + * @param string $database_state_key + * The state key. + * @param int $drupal_version + * The version of Drupal we're getting the migrations for. + * @param string $source_base_path + * (optional) Address of the source Drupal site (e.g., http://example.com/). * * @return \Drupal\migrate\Entity\MigrationInterface[] * The migrations for import. */ - protected function getMigrations(array $migration_templates) { - // Let the builder service create our migration configuration entities from - // the templates, expanding them to multiple entities where necessary. - /** @var \Drupal\migrate\MigrationBuilder $builder */ - $builder = \Drupal::service('migrate.migration_builder'); - $initial_migrations = $builder->createMigrations($migration_templates); - $migrations = []; - foreach ($initial_migrations as $migration) { + protected function getMigrations($database_state_key, $drupal_version, $source_base_path = '') { + $version_tag = 'Drupal ' . $drupal_version; + $plugin_manager = \Drupal::service('plugin.manager.migration'); + /** @var \Drupal\migrate\Plugin\Migration[] $migrations */ + $migrations = $plugin_manager->createInstancesByTag($version_tag); + + foreach ($migrations as $migration) { + // Set the state key into the source. + $source = $migration->get('source'); + $source['database_state_key'] = $database_state_key; + $migration->set('source', $source); + + // Setup the destination for the file destination. + $destination = $migration->get('destination'); + if ($destination['plugin'] == 'entity:file') { + if ($source_base_path) { + // Make sure we have a single trailing slash. + $source_base_path = rtrim($source_base_path, '/') . '/'; + $destination['source_base_path'] = $source_base_path; + $migration->set('destination', $destination); + } + } + try { // Any plugin that has specific requirements to check will implement // RequirementsInterface. @@ -141,9 +137,9 @@ protected function getMigrations(array $migration_templates) { } $migrations[] = $migration; } - // Migrations which are not applicable given the source and destination - // site configurations (e.g., what modules are enabled) will be silently - // ignored. + // Migrations which are not applicable given the source and destination + // site configurations (e.g., what modules are enabled) will be silently + // ignored. catch (RequirementsException $e) { } catch (PluginNotFoundException $e) { @@ -154,29 +150,6 @@ protected function getMigrations(array $migration_templates) { } /** - * Saves the migrations for import from the provided template connection. - * - * @param array $migration_templates - * Migration template. - * - * @return array - * The migration IDs sorted in dependency order. - */ - protected function createMigrations(array $migration_templates) { - $migration_ids = []; - $migrations = $this->getMigrations($migration_templates); - foreach ($migrations as $migration) { - // Don't try to resave migrations that already exist. - if (!Migration::load($migration->id())) { - $migration->save(); - } - $migration_ids[] = $migration->id(); - } - // loadMultiple will sort the migrations in dependency order. - return array_keys(Migration::loadMultiple($migration_ids)); - } - - /** * Determines what version of Drupal the source database contains. * * @param \Drupal\Core\Database\Connection $connection diff --git a/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php b/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php index f910601..a94db18 100644 --- a/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php +++ b/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php @@ -8,13 +8,12 @@ namespace Drupal\migrate_drupal_ui\Form; use Drupal\Core\Datetime\DateFormatterInterface; -use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Form\ConfirmFormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Render\RendererInterface; use Drupal\Core\State\StateInterface; use Drupal\Core\Url; -use Drupal\migrate\Entity\Migration; +use Drupal\migrate\Plugin\MigrationPluginManagerInterface; use Drupal\migrate_drupal_ui\MigrateUpgradeRunBatch; use Drupal\migrate_drupal\MigrationCreationTrait; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -618,11 +617,11 @@ class MigrateUpgradeForm extends ConfirmFormBase { protected $renderer; /** - * The migration entity storage. + * The migration plugin manager. * - * @var \Drupal\Core\Entity\EntityStorageInterface + * @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface */ - protected $entityStorage; + protected $pluginManager; /** * Constructs the MigrateUpgradeForm. @@ -633,14 +632,14 @@ class MigrateUpgradeForm extends ConfirmFormBase { * The date formatter service. * @param \Drupal\Core\Render\RendererInterface $renderer * The renderer service. - * @param \Drupal\Core\Entity\EntityStorageInterface $entity_storage - * The migration entity storage. + * @param \Drupal\migrate\Plugin\MigrationPluginManagerInterface $plugin_manager + * The migration plugin manager. */ - public function __construct(StateInterface $state, DateFormatterInterface $date_formatter, RendererInterface $renderer, EntityStorageInterface $entity_storage) { + public function __construct(StateInterface $state, DateFormatterInterface $date_formatter, RendererInterface $renderer, MigrationPluginManagerInterface $plugin_manager) { $this->state = $state; $this->dateFormatter = $date_formatter; $this->renderer = $renderer; - $this->entityStorage = $entity_storage; + $this->pluginManager = $plugin_manager; } /** @@ -651,7 +650,7 @@ public static function create(ContainerInterface $container) { $container->get('state'), $container->get('date.formatter'), $container->get('renderer'), - $container->get('entity_type.manager')->getStorage('migration') + $container->get('plugin.manager.migration') ); } @@ -927,11 +926,10 @@ public function validateCredentialForm(array &$form, FormStateInterface $form_st // version where converted to migration entities. Find one of those // migrations to be able to look up the matching database credentials // from state. - $query = $this->entityStorage->getQuery('OR'); - $ids = $query->execute(); - foreach ($ids as $id) { + $definitions = $this->pluginManager->getDefinitions(); + foreach ($definitions as $id => $definition) { /** @var \Drupal\migrate\Entity\MigrationInterface $migration */ - $migration = Migration::load($id); + $migration = $this->pluginManager->createInstance($id); $is_drupal_migration = FALSE; foreach ($migration->get('migration_tags') as $migration_tag) { if (substr($migration_tag, 0, 7) === 'Drupal ') { @@ -949,11 +947,8 @@ public function validateCredentialForm(array &$form, FormStateInterface $form_st } try { - // Get the template for migration. - $migration_template = $this->getMigrationTemplates($database, $form_state->getValue('source_base_path')); - - // Get a copy of all the relevant migrations so we run them in next step. - $migrations = $this->getMigrations($migration_template); + $connection = $this->getSourceDatabaseConnection($database); + $migrations = $this->getMigrations('migrate_drupal_' . $connection->getKey(), $this->getLegacyDrupalVersion($connection), $form_state->getValue('source_base_path')); // Get the system data from source database. $system_data = $this->getSystemData($database); @@ -962,12 +957,9 @@ public function validateCredentialForm(array &$form, FormStateInterface $form_st // so that it can be stored in form storage. $migration_array = []; foreach ($migrations as $migration) { - $migration_array[] = $migration->toArray(); + $migration_array[$migration->id()] = $migration->label(); } - // Store the retrieved migration templates in form storage. - $form_state->set('migration_template', $migration_template); - // Store the retrieved migration ids in form storage. $form_state->set('migration', $migration_array); @@ -1031,16 +1023,15 @@ public function buildConfirmForm(array $form, FormStateInterface $form_state) { $table_data = []; $system_data = []; - foreach ($form_state->get('migration') as $migration) { - $migration_id = $migration['id']; + foreach ($form_state->get('migration') as $migration_id => $migration_label) { // Fetch the system data at the first opportunity. if (empty($system_data)) { $system_data = $form_state->get('system_data'); } - $template_id = $migration['template']; - $source_module = $this->moduleUpgradePaths[$template_id]['source_module']; - $destination_module = $this->moduleUpgradePaths[$template_id]['destination_module']; - $table_data[$source_module][$destination_module][$migration_id] = $migration['label']; + + $source_module = $this->moduleUpgradePaths[$migration_id]['source_module']; + $destination_module = $this->moduleUpgradePaths[$migration_id]['destination_module']; + $table_data[$source_module][$destination_module][$migration_id] = $migration_label; } // Sort the table by source module names and within that destination // module names. @@ -1125,12 +1116,8 @@ public function buildConfirmForm(array $form, FormStateInterface $form_state) { public function submitConfirmForm(array &$form, FormStateInterface $form_state) { $storage = $form_state->getStorage(); if (isset($storage['upgrade_option']) && $storage['upgrade_option'] == static::MIGRATE_UPGRADE_ROLLBACK) { - $query = $this->entityStorage->getQuery(); - $names = $query->execute(); + $migrations = $this->pluginManager->createInstances([]); - // Order the migrations according to their dependencies. - /** @var \Drupal\migrate\Entity\MigrationInterface[] $migrations */ - $migrations = $this->entityStorage->loadMultiple($names); // Assume we want all those tagged 'Drupal %'. foreach ($migrations as $migration_id => $migration) { $keep = FALSE; @@ -1167,15 +1154,14 @@ public function submitConfirmForm(array &$form, FormStateInterface $form_state) $this->state->delete('migrate_drupal_ui.performed'); } else { - $migration_template = $storage['migration_template']; - $migration_ids = $this->createMigrations($migration_template); + $migrations = $storage['migrations']; $batch = [ 'title' => $this->t('Running upgrade'), 'progress_message' => '', 'operations' => [ [ [MigrateUpgradeRunBatch::class, 'run'], - [$migration_ids, 'import'], + [array_keys($migrations), 'import'], ], ], 'finished' => [ diff --git a/core/modules/migrate_drupal_ui/src/MigrateUpgradeRunBatch.php b/core/modules/migrate_drupal_ui/src/MigrateUpgradeRunBatch.php index 669ec5e..dba824d 100644 --- a/core/modules/migrate_drupal_ui/src/MigrateUpgradeRunBatch.php +++ b/core/modules/migrate_drupal_ui/src/MigrateUpgradeRunBatch.php @@ -9,7 +9,6 @@ use Drupal\Core\Link; use Drupal\Core\Url; -use Drupal\migrate\Entity\Migration; use Drupal\migrate\Entity\MigrationInterface; use Drupal\migrate\Event\MigrateEvents; use Drupal\migrate\Event\MigrateIdMapMessageEvent; @@ -108,8 +107,8 @@ public static function run($initial_ids, $operation, &$context) { static::$numProcessed = 0; $migration_id = reset($context['sandbox']['migration_ids']); - /** @var \Drupal\migrate\Entity\Migration $migration */ - $migration = Migration::load($migration_id); + /** @var \Drupal\migrate\Plugin\Migration $migration */ + $migration = \Drupal::service('plugin.manager.migration')->createInstance($migration_id); if ($migration) { static::$messages = new MigrateMessageCapture(); $executable = new MigrateExecutable($migration, static::$messages); @@ -142,7 +141,6 @@ public static function run($initial_ids, $operation, &$context) { $message = static::getTranslation()->formatPlural( $context['sandbox']['num_processed'], 'Rolled back @migration (processed 1 item total)', 'Rolled back @migration (processed @num_processed items total)', ['@migration' => $migration_name, '@num_processed' => $context['sandbox']['num_processed']]); - $migration->delete(); } $context['sandbox']['messages'][] = $message; static::logger()->notice($message); @@ -203,7 +201,7 @@ public static function run($initial_ids, $operation, &$context) { // that is running while this message is visible). if (!empty($context['sandbox']['migration_ids'])) { $migration_id = reset($context['sandbox']['migration_ids']); - $migration = Migration::load($migration_id); + $migration = \Drupal::service('plugin.manager.migration')->createInstance($migration_id); $migration_name = $migration->label() ? $migration->label() : $migration_id; if ($operation == 'import') { $context['message'] = t('Currently upgrading @migration (@current of @max total tasks)', [