commit b05792c67df9737595acdfffca2253e72878da17 Author: Lee Rowlands Date: Sat Apr 6 10:05:02 2019 +1000 p222 diff --git a/core/modules/language/language.migrate_drupal.yml b/core/modules/language/language.migrate_drupal.yml index f50f8fdc29..25ac491a22 100644 --- a/core/modules/language/language.migrate_drupal.yml +++ b/core/modules/language/language.migrate_drupal.yml @@ -1,7 +1,11 @@ finished: 6: - locale: language, system + locale: + - language + - system system: language taxonomy: language 7: - locale: language, system + locale: + - language + - system diff --git a/core/modules/migrate_drupal/migrate_drupal.services.yml b/core/modules/migrate_drupal/migrate_drupal.services.yml index a413237900..77a8b59dfd 100644 --- a/core/modules/migrate_drupal/migrate_drupal.services.yml +++ b/core/modules/migrate_drupal/migrate_drupal.services.yml @@ -27,3 +27,4 @@ services: - '@logger.channel.migrate_drupal' migrate_drupal.migration_state: class: Drupal\migrate_drupal\MigrationState + arguments: ['@plugin.manager.migrate.field', '@module_handler', '@messenger', '@string_translation'] diff --git a/core/modules/migrate_drupal/src/MigrationConfigurationTrait.php b/core/modules/migrate_drupal/src/MigrationConfigurationTrait.php index af93c5f471..f17768ef3b 100644 --- a/core/modules/migrate_drupal/src/MigrationConfigurationTrait.php +++ b/core/modules/migrate_drupal/src/MigrationConfigurationTrait.php @@ -210,22 +210,4 @@ protected function getLegacyDrupalVersion(Connection $connection) { return $version_string ? substr($version_string, 0, 1) : FALSE; } - /** - * {@inheritdoc} - */ - protected function getMigrationStates() { - /** @var \Drupal\migrate_drupal\MigrationState $migration_state */ - $migration_state = \Drupal::service('migrate_drupal.migration_state'); - return $migration_state->getMigrationStates(); - } - - /** - * {@inheritdoc} - */ - protected function getUpgradeStates($version, array $source_system_data, array $migrations) { - /** @var \Drupal\migrate_drupal\MigrationState $migration_state */ - $migration_state = \Drupal::service('migrate_drupal.migration_state'); - return $migration_state->getUpgradeStates($version, $source_system_data, $migrations); - } - } diff --git a/core/modules/migrate_drupal/src/MigrationState.php b/core/modules/migrate_drupal/src/MigrationState.php index 788b5d81d0..df1cbe76aa 100644 --- a/core/modules/migrate_drupal/src/MigrationState.php +++ b/core/modules/migrate_drupal/src/MigrationState.php @@ -3,8 +3,12 @@ namespace Drupal\migrate_drupal; use Drupal\Core\Discovery\YamlDiscovery; +use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\Messenger\MessengerTrait; use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\Core\StringTranslation\TranslationInterface; +use Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface; /** * Determines the migrate state for all modules enabled on the source. @@ -22,11 +26,10 @@ * current major version destination modules it is providing migrations for. We * see this in core where the Drupal 6 Menu module is upgraded by having * migrations in three Drupal 8 modules; menu_link_content, menu_ui and system. - * And it is only when all those migrations are complete, in all three modules, - * and menu is enabled on the source, and three destination modules are enabled - * that the Drupal 6 Menu module should be listed as will be upgraded. If any - * one of the conditions are not met then it should be listed as will not be - * upgraded. + * If migrations for any of those three modules are not complete or if any of + * them are not installed on the destination site then the Drupal 6 Menu module + * cannot be listed as upgraded. If any one of the conditions are not met then + * it should be listed as will not be upgraded. * * Another challenge is to ensure that legacy source modules that do not need an * upgrade path are handled correctly. These will not have migrations but should @@ -64,19 +67,26 @@ * finished: * # One or more Drupal legacy version number mappings (i.e. 6 and/or 7). * 6: - * # A mapping of legacy module machine names to a comma separated list of - * # destination module machine names to define this migration set. + * # A mapping of legacy module machine names to either an array of modules + * # or a single destination module machine name to define this migration + * # set. * : - * : , + * : + * - + * - * 7: * : - * : , + * : + * - + * - * # (optional) List of the migration sets that this module provides, or will be * # providing, that are incomplete or do not yet exist. * not_finished: * 6: * : - * : , + * : + * - + * - * * Examples: * @@ -90,6 +100,9 @@ * not_finished: * 7: * commerce_product: commerce_product + * other_module: + * - other_module + * - further_module * @endcode * * In this example the module has completed the upgrade path for data from the @@ -143,19 +156,70 @@ class MigrationState { protected $fieldPluginManager; /** - * Source module that will not be migrated determined using legacy method. + * Source modules that will not be migrated determined using legacy method. * * @var array */ protected $unmigratedSourceModules = []; /** - * Source module that will be migrated determined using legacy method. + * Source modules that will be migrated determined using legacy method, keyed + * by version. * * @var array */ protected $migratedSourceModules = []; + /** + * An array of migration states declared for each source migration. + * + * States are keyed by version. Each value is an array keyed by name of the + * source module and the value is an array of all the states declared for this + * source module. + * + * @var array + */ + protected $stateBySource; + + /** + * An array of destinations declared for each source migration. + * + * Destinations are keyed by version. Each value is an array keyed by the name + * of the source module and the value is an array of the destination modules. + * + * @var array + */ + protected $declaredBySource; + + /** + * An array of migration source and destinations derived from migrations. + * + * The key is the source version and the value is an array where the key is + * the source module and the value is an array of destinations derived from + * migration plugins. + * + * @var array + */ + protected $disoveredBySource; + + /** + * An array of migration source and destinations. + * + * Values are derived from migration plugins and declared states. The key is + * the source version and the value is an array where the key is the source + * module and the value is an array of declared or derived destinations. + * + * @var array + */ + protected $destinations = []; + + /** + * Array of enabled modules. + * + * @var array + */ + protected $enabledModules = []; + /** * List of extensions that do not need an upgrade path. * @@ -260,10 +324,23 @@ class MigrationState { /** * Construct a new MigrationState object. + * + * @param \Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface $fieldPluginManager + * Field plugin manager. + * @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler + * Module handler. + * @param \Drupal\Core\Messenger\MessengerInterface $messenger + * Messenger sevice. + * @param \Drupal\Core\StringTranslation\TranslationInterface $stringTranslation + * String translation service. */ - public function __construct() { - $this->fieldPluginManager = \Drupal::service('plugin.manager.migrate.field'); - $this->moduleHandler = \Drupal::service('module_handler'); + public function __construct(MigrateFieldPluginManagerInterface $fieldPluginManager, ModuleHandlerInterface $moduleHandler, MessengerInterface $messenger, TranslationInterface $stringTranslation) { + $this->fieldPluginManager = $fieldPluginManager; + $this->moduleHandler = $moduleHandler; + $this->enabledModules = array_keys($this->moduleHandler->getModuleList()); + $this->enabledModules[] = 'core'; + $this->messenger = $messenger; + $this->stringTranslation = $stringTranslation; } /** @@ -291,12 +368,10 @@ public function getUpgradeStates($version, array $source_system_data, array $mig * An association array keyed by module of the finished and not_finished * migrations for each module. * */ - public function getMigrationStates() { + protected function getMigrationStates() { // Always instantiate a new YamlDiscovery object so that we always search on // the up-to-date list of modules. - /** @var \Drupal\Core\Extension\ModuleHandlerInterface $module_handler */ - $module_handler = \Drupal::service('module_handler'); - $discovery = new YamlDiscovery('migrate_drupal', $module_handler->getModuleDirectories()); + $discovery = new YamlDiscovery('migrate_drupal', $this->moduleHandler->getModuleDirectories()); return $discovery->findAll(); } @@ -333,67 +408,42 @@ public function getMigrationStates() { * ] * ], * ] - * @nedcode + * @endcode */ protected function buildUpgradeState($version, array $source_system_data, array $migrations) { - $discovered_upgrade_paths = $this->getSourceDestinations($version, $migrations); - list($declared_by_source, $destination_modules_declared) = $this->getDeclaredBySource($version); - // Remove core profiles from the system data. - foreach (['standard', 'minimal'] as $profile) { - unset($source_system_data['module'][$profile]); - } + unset($source_system_data['module']['standard'], $source_system_data['module']['minimal']); + $this->buildDiscoveredDestinationsBySource($version, $migrations, $source_system_data); + $this->buildDeclaredStateBySource($version); $upgrade_state = []; // Loop through every source module that is enabled on the source site. foreach ($source_system_data['module'] as $module) { - $destination_modules = []; - // Assume will not be ungraded unless proven otherwise. - $migration_state = static::NOT_FINISHED; - $source_module = $module['name']; - // If there is not a declared state for this source module then use the - // legacy method for determining the migration state. - if (!isset($declared_by_source[$source_module])) { - $return = $this->getStateLegacyMethod($migrations, $source_module, $version, $source_system_data, $discovered_upgrade_paths); - if ($return) { - list($migration_state, $destination_modules) = $return; - $destination_modules = array_unique($destination_modules); - sort($destination_modules); - $state = $migration_state; - $upgrade_state[$state][$source_module] = implode(', ', $destination_modules); - } - } - else { - // The source plugins check requirements requires that all - // source_modules are enabled so do the same here. - if ($module['status']) { - // The state is finished only when no declarations of 'not_finished' - // were found and each destination module is enabled. Get the - // destination modules for this source module, include what was - // declared and what was discovered. - $destination_modules = isset($discovered_upgrade_paths[$source_module]) ? $discovered_upgrade_paths[$source_module] : []; - if (isset($destination_modules_declared[$source_module])) { - $destination_modules = array_merge($destination_modules, $destination_modules_declared[$source_module]); + // The source plugins check requirements requires that all + // source_modules are enabled so do the same here. + if ($module['status']) { + $source_module = $module['name']; + // If there is not a declared state for this source module then use the + // legacy method for determining the migration state. + if (!isset($this->stateBySource[$version][$source_module])) { + @trigger_error(sprintf("Using migration plugin definitions to determine the migration state of the module '%s' is deprecated in Drupal 8.7. Add the module to a migrate_drupal.yml file. See https://www.drupal.org/node/2929443", $source_module), E_USER_DEPRECATED); + if (array_key_exists($source_module, $this->unmigratedSourceModules[$version])) { + $upgrade_state[static::NOT_FINISHED][$source_module] = ''; + continue; } - $destination_modules = array_unique($destination_modules); - if ($destination_modules) { - if (!in_array('not_finished', $declared_by_source[$source_module]) && in_array('finished', $declared_by_source[$source_module])) { - $migration_state = static::FINISHED; - // Check that the destination modules declared and discovered - // are enabled. If any are not then set to not_finished. - foreach ($destination_modules as $destination_module) { - if ($destination_module != 'core' && !$this->moduleHandler->moduleExists($destination_module)) { - $migration_state = static::NOT_FINISHED; - } - } + if (array_key_exists($source_module, $this->migratedSourceModules[$version])) { + if (array_diff(array_keys($this->migratedSourceModules[$version][$source_module]), $this->enabledModules)) { + $upgrade_state[static::NOT_FINISHED][$source_module] = implode(', ', array_keys($this->migratedSourceModules[$version][$source_module])); + continue; } + $upgrade_state[static::FINISHED][$source_module] = implode(', ', array_keys($this->migratedSourceModules[$version][$source_module])); } - $destination_modules = array_unique($destination_modules); - sort($destination_modules); - $state = $migration_state; - $upgrade_state[$state][$source_module] = implode(', ', $destination_modules); + continue; } + + $upgrade_state[$this->getSourceState($version, $source_module)][$source_module] = implode(', ', $this->getDestinationsForSource($version, $source_module)); } + } foreach ($upgrade_state as $key => $value) { ksort($upgrade_state[$key]); @@ -408,14 +458,12 @@ protected function buildUpgradeState($version, array $source_system_data, array * The legacy Drupal version. * @param array $migrations * The discovered migrations. - * - * @return array - * Array of migrations, keyed by source_module and destination_module. Only - * migrations that have both a source_module and a destination_module - * definition are added to the array. + * @param array $source_system_data + * The data from the source site system table. */ - protected function getSourceDestinations($version, array $migrations) { + protected function buildDiscoveredDestinationsBySource($version, array $migrations, array $source_system_data) { $discovered_upgrade_paths = []; + $table_data = []; foreach ($migrations as $migration) { $migration_id = $migration->getPluginId(); $source_module = $migration->getSourcePlugin()->getSourceModule(); @@ -432,6 +480,7 @@ protected function getSourceDestinations($version, array $migrations) { if ($source_module && $destination_module) { $discovered_upgrade_paths[$source_module][] = $destination_module; + $table_data[$source_module][$destination_module][$migration_id] = $migration->label(); } } @@ -444,14 +493,28 @@ protected function getSourceDestinations($version, array $migrations) { $source_module = $definition['source_module']; $destination_module = $definition['destination_module']; $discovered_upgrade_paths[$source_module][] = $destination_module; + $table_data[$source_module][$destination_module][$definition['id']] = $definition['id']; } } - - // Remove duplicate destination_modules. - foreach ($discovered_upgrade_paths as $key => $destination_modules) { - $discovered_upgrade_paths[$key] = array_unique($destination_modules); + // Add source_module and destination_module for modules that do not need + // an upgrade path and are enabled on the source site. + foreach ($this->noUpgradePaths[$version] as $extension) { + if (isset($source_system_data['module'][$extension]) && $source_system_data['module'][$extension]['status']) { + $table_data[$extension]['core'][$extension] = $extension; + } + } + ksort($table_data); + foreach ($table_data as $source_module => $destination_module_info) { + ksort($table_data[$source_module]); } - return $discovered_upgrade_paths; + $tmp = array_diff_key($source_system_data['module'], $table_data); + foreach ($tmp as $source_module => $module_data) { + if ($module_data['status']) { + $this->unmigratedSourceModules[$version][$source_module] = $module_data; + } + } + $this->migratedSourceModules[$version] = $table_data; + $this->disoveredBySource[$version] = array_map('array_unique', $discovered_upgrade_paths); } /** @@ -459,147 +522,79 @@ protected function getSourceDestinations($version, array $migrations) { * * @param string $version * The legacy Drupal version. - * - * @return array - * An indexed array of declared migration information. The first element - * is an array of migration states declared for each source migration - * The key is the name of the source module and the value is an array of all - * the states declared for this source module. The second element is also - * keyed by the source module but it contains a csv list of all the - * destination modules. */ - protected function getDeclaredBySource($version) { + protected function buildDeclaredStateBySource($version) { $migration_states = $this->getMigrationStates(); $state_by_source = []; $dest_by_source = []; - $states = ['finished', 'not_finished']; + $states = [static::FINISHED, static::NOT_FINISHED]; foreach ($migration_states as $module => $info) { foreach ($states as $state) { - if (isset($info[$state])) { - foreach ($info[$state] as $info_version => $migrate_info) { - if ($info_version == $version) { - foreach ($migrate_info as $source => $destination) { - // Add the state. - $state_by_source[$source][] = $state; - // Add the destination modules. - $dest_by_source[$source] = isset($dest_by_source[$source]) ? $dest_by_source[$source] : []; - $tmp = array_map('trim', explode(',', $destination)); - $dest_by_source[$source] = array_merge($dest_by_source[$source], $tmp); - } - } + if (isset($info[$state][$version])) { + foreach ($info[$state][$version] as $source => $destination) { + // Add the state. + $state_by_source[$source][] = $state; + // Add the destination modules. + $dest_by_source += [$source => []]; + $dest_by_source[$source] = array_merge($dest_by_source[$source], (array) $destination); } } } } - - // Make the arrays unique. - $state_by_source_unique = []; - $dest_by_source_unique = []; - foreach ($state_by_source as $key => $value) { - $state_by_source_unique[$key] = array_unique($state_by_source[$key]); - $dest_by_source_unique[$key] = array_unique($dest_by_source[$key]); - } - - return [$state_by_source_unique, $dest_by_source_unique]; + $this->stateBySource[$version] = array_map('array_unique', $state_by_source); + $this->declaredBySource[$version] = array_map('array_unique', $dest_by_source); } /** - * Determine the state of an upgrade path for a legacy source module. + * Tests if a destination exists for the given source module. * - * @param array $migrations - * The discovered migrations. - * @param string $module - * The legacy source module name. * @param string $version - * The legacy drupal version. - * @param array $source_system_data - * The data from the source site system table. + * Source version of Drupal. + * @param string $source_module + * Source module. * - * @return array|null - * An indexed array where the first element in the migration state and the - * second is a list of destination modules when a state was found, otherwise - * return NULL. + * @return string + * Migration state, either 'finished' or 'not_finished'. + */ + protected function getSourceState($version, $source_module) { + // The state is finished only when no declarations of 'not_finished' + // were found and each destination module is enabled. + if (!$destinations = $this->getDestinationsForSource($version, $source_module)) { + // No discovered or declared state. + return MigrationState::NOT_FINISHED; + } + if (in_array(MigrationState::NOT_FINISHED, $this->stateBySource[$version][$source_module], TRUE) || !in_array(MigrationState::FINISHED, $this->stateBySource[$version][$source_module], TRUE)) { + return MigrationState::NOT_FINISHED; + } + if (array_diff($destinations, $this->enabledModules)) { + return MigrationState::NOT_FINISHED; + } + return MigrationState::FINISHED; + } + + /** + * Get net destinations for source module. * - * @deprecated in Drupal 8.8 and will be removed before Drupal 9.0.0. - * Instead, you should use a migrate_drupal.yml file. + * @param string $version + * Source version. + * @param string $source_module + * Source module. * - * @see https://www.drupal.org/node/2929443 + * @return array + * Destination modules either declared by {modulename}.migrate_drupal.yml + * files or discovered from migration plugins. */ - protected function getStateLegacyMethod(array $migrations, $module, $version, array $source_system_data) { - @trigger_error(sprintf("The legacy module '%s', is not listed in any migrate_drupal.yml file, see https://www.drupal.org/node/2929443", $module), E_USER_DEPRECATED); - - if (empty($this->unmigratedSourceModules) && empty($this->migratedSourceModules)) { - // Get the source_module and destination_module for each migration. - $table_data = []; - foreach ($migrations as $migration) { - $migration_id = $migration->getPluginId(); - $source_module = $migration->getSourcePlugin()->getSourceModule(); - if (!$source_module) { - $this->messenger() - ->addError($this->t('Source module not found for @migration_id.', ['@migration_id' => $migration_id])); - } - $destination_module = $migration->getDestinationPlugin()->getDestinationModule(); - if (!$destination_module) { - $this->messenger() - ->addError($this->t('Destination module not found for @migration_id.', ['@migration_id' => $migration_id])); - } - - if ($source_module && $destination_module) { - $table_data[$source_module][$destination_module][$migration_id] = $migration->label(); - } - } - - // Get the source_module and destination_module from the field plugins. - $definitions = $this->fieldPluginManager->getDefinitions(); - foreach ($definitions as $definition) { - // This is not strict so that we find field plugins with an annotation - // where the Drupal core version is an integer and when it is a string. - if (in_array($version, $definition['core'])) { - $source_module = $definition['source_module']; - $destination_module = $definition['destination_module']; - $table_data[$source_module][$destination_module][$definition['id']] = $definition['id']; - } - } - - // Add source_module and destination_module for modules that do not need - // an upgrade path and are enabled on the source site. - foreach ($this->noUpgradePaths[$version] as $extension) { - if (isset($source_system_data['module'][$extension]) && $source_system_data['module'][$extension]['status']) { - $table_data[$extension]['core'][$extension] = $extension; - } - } - - // Sort the table by source module names and within that destination - // module names. - ksort($table_data); - foreach ($table_data as $source_module => $destination_module_info) { - ksort($table_data[$source_module]); - } - - // Remove core profiles from the system data. - foreach (['standard', 'minimal'] as $profile) { - unset($source_system_data['module'][$profile]); - } - - $tmp = array_diff_key($source_system_data['module'], $table_data); - foreach ($tmp as $source_module => $module_data) { - if ($module_data['status']) { - $this->unmigratedSourceModules[$source_module] = $module_data; - } - } - $this->migratedSourceModules = $table_data; + protected function getDestinationsForSource($version, $source_module) { + if (!isset($this->destinations[$version][$source_module])) { + $this->disoveredBySource[$version] += [$source_module => []]; + $this->declaredBySource[$version] += [$source_module => []]; + $destination = array_unique(array_merge($this->disoveredBySource[$version][$source_module], $this->declaredBySource[$version][$source_module])); + sort($destination); + $this->destinations[$version][$source_module] = $destination; } + return $this->destinations[$version][$source_module]; - if (array_key_exists($module, $this->unmigratedSourceModules)) { - $state = static::NOT_FINISHED; - return [$state, []]; - } - if (array_key_exists($module, $this->migratedSourceModules)) { - $state = static::FINISHED; - $keys = array_keys($this->migratedSourceModules[$module]); - return [$state, $keys]; - } } } diff --git a/core/modules/migrate_drupal/tests/modules/migrate_state_finished_test/migrate_state_finished_test.migrate_drupal.yml b/core/modules/migrate_drupal/tests/modules/migrate_state_finished_test/migrate_state_finished_test.migrate_drupal.yml index 28fcac5a47..28169879d1 100644 --- a/core/modules/migrate_drupal/tests/modules/migrate_state_finished_test/migrate_state_finished_test.migrate_drupal.yml +++ b/core/modules/migrate_drupal/tests/modules/migrate_state_finished_test/migrate_state_finished_test.migrate_drupal.yml @@ -3,13 +3,17 @@ finished: # A field migration # migrate_state_finished_test: migrate_state_finished_test aggregator: migrate_state_finished_test - action: migrate_state_finished_test, migrate_state_not_finished_test + action: + - migrate_state_finished_test + - migrate_state_not_finished_test 7: # A field migration # migrate_state_finished_test: migrate_state_finished_test aggregator: migrate_state_finished_test # Migrations - action: migrate_state_finished_test, migrate_state_not_finished_test + action: + - migrate_state_finished_test + - migrate_state_not_finished_test not_finished: 7: # Migrations diff --git a/core/modules/migrate_drupal/tests/src/Kernel/MigrationStateDeprecationTest.php b/core/modules/migrate_drupal/tests/src/Kernel/MigrationStateDeprecationTest.php new file mode 100644 index 0000000000..ba956fb830 --- /dev/null +++ b/core/modules/migrate_drupal/tests/src/Kernel/MigrationStateDeprecationTest.php @@ -0,0 +1,37 @@ +getUpgradeStates(7, [ + 'module' => [ + 'entity_test' => [ + 'name' => 'entity_test', + 'status' => TRUE, + ], + ], + ], []); + } + +} diff --git a/core/modules/migrate_drupal/tests/src/Kernel/StateFileExists.php b/core/modules/migrate_drupal/tests/src/Kernel/StateFileExists.php index e370512fdd..500ee27e84 100644 --- a/core/modules/migrate_drupal/tests/src/Kernel/StateFileExists.php +++ b/core/modules/migrate_drupal/tests/src/Kernel/StateFileExists.php @@ -2,6 +2,7 @@ namespace Drupal\Tests\migrate_drupal\Kernel; +use Drupal\Component\Discovery\YamlDiscovery; use Drupal\KernelTests\FileSystemModuleDiscoveryDataProviderTrait; use Drupal\migrate_drupal\MigrationConfigurationTrait; @@ -91,7 +92,7 @@ public function testMigrationState() { $this->enableModules($modules_to_enable); // Modules with a migrate_drupal.yml file. - $has_state_file = $this->getMigrationStates(); + $has_state_file = (new YamlDiscovery('migrate_drupal', $module_handler->getModuleDirectories()))->findAll(); foreach ($this->stateFileRequired as $module) { $this->assertArrayHasKey($module, $has_state_file, sprintf("Module '%s' should have a migrate_drupal.yml file", $module)); diff --git a/core/modules/migrate_drupal/tests/src/Kernel/ValidateMigrationStateTest.php b/core/modules/migrate_drupal/tests/src/Kernel/ValidateMigrationStateTest.php index 1a00b77886..913868dd59 100644 --- a/core/modules/migrate_drupal/tests/src/Kernel/ValidateMigrationStateTest.php +++ b/core/modules/migrate_drupal/tests/src/Kernel/ValidateMigrationStateTest.php @@ -2,8 +2,9 @@ namespace Drupal\Tests\migrate_drupal\Kernel; +use Drupal\Component\Discovery\YamlDiscovery; use Drupal\KernelTests\FileSystemModuleDiscoveryDataProviderTrait; -use Drupal\migrate_drupal\MigrationConfigurationTrait; +use Drupal\migrate_drupal\MigrationState; /** * Tests the migration state information in module.migrate_drupal.yml. @@ -17,7 +18,6 @@ class ValidateMigrationStateTest extends MigrateDrupalTestBase { use FileSystemModuleDiscoveryDataProviderTrait; - use MigrationConfigurationTrait; /** * {@inheritdoc} @@ -99,10 +99,10 @@ public function testMigrationState() { // destination is not used yet but can be later for validating the // source/destination pairs with the actual source/destination pairs in the // migrate plugins. - $system_info = $this->getMigrationStates(); + $system_info = (new YamlDiscovery('migrate_drupal', \Drupal::moduleHandler()->getModuleDirectories()))->findAll(); $declared = []; - $states = ['finished', 'not_finished']; + $states = [MigrationState::FINISHED, MigrationState::NOT_FINISHED]; foreach ($system_info as $module => $info) { foreach ($states as $state) { if (isset($info[$state])) { @@ -112,9 +112,7 @@ public function testMigrationState() { // 18n migrations can have up to three source modules but only one // can be handled in the migration. if (($source !== 'i18nstrings') && ($source !== 'i18n_string')) { - // Destination is a CSV. - $tmp = str_getcsv($destination); - foreach ($tmp as $dest) { + foreach ((array) $destination as $dest) { $key = [$info_version, $module, $source, trim($dest)]; $declared[$info_version][$state][] = implode(static::SEPARATOR, $key); } @@ -128,10 +126,10 @@ public function testMigrationState() { $versions = ['6', '7']; foreach ($versions as $version) { // Sort and make the array values unique. - sort($declared[$version]['finished']); - sort($declared[$version]['not_finished']); - $declared_unique[$version]['finished'] = array_unique($declared[$version]['finished']); - $declared_unique[$version]['not_finished'] = array_unique($declared[$version]['not_finished']); + sort($declared[$version][MigrationState::FINISHED]); + sort($declared[$version][MigrationState::NOT_FINISHED]); + $declared_unique[$version][MigrationState::FINISHED] = array_unique($declared[$version][MigrationState::FINISHED]); + $declared_unique[$version][MigrationState::NOT_FINISHED] = array_unique($declared[$version][MigrationState::NOT_FINISHED]); sort($discovered[$version]); $discovered_unique[$version] = array_unique($discovered[$version]); @@ -139,8 +137,8 @@ public function testMigrationState() { // in a migrate_drupal.yml. foreach ($discovered_unique[$version] as $datum) { $data = str_getcsv($datum); - $in_finished = in_array($datum, $declared_unique[$version]['finished']); - $in_not_finished = in_array($datum, $declared_unique[$version]['not_finished']); + $in_finished = in_array($datum, $declared_unique[$version][MigrationState::FINISHED]); + $in_not_finished = in_array($datum, $declared_unique[$version][MigrationState::NOT_FINISHED]); $found = $in_finished || $in_not_finished; $this->assertTrue($found, sprintf("No migration state found for version '%s' with source_module '%s' and destination_module '%s' declared in module '%s'", $data[0], $data[2], $data[3], $data[1])); } @@ -148,10 +146,10 @@ public function testMigrationState() { // Remove the declared finished from the discovered, leaving just the not // finished, if there are any. These should have an entry in the declared // not finished. - $discovered_not_finished = array_diff($discovered_unique[$version], $declared_unique[$version]['finished']); + $discovered_not_finished = array_diff($discovered_unique[$version], $declared_unique[$version][MigrationState::FINISHED]); foreach ($discovered_not_finished as $datum) { $data = str_getcsv($datum); - $this->assertContains($datum, $declared_unique[$version]['not_finished'], sprintf("No migration found for version '%s' with source_module '%s' and destination_module '%s' declared in module '%s'", $data[0], $data[2], $data[3], $data[1])); + $this->assertContains($datum, $declared_unique[$version][MigrationState::NOT_FINISHED], sprintf("No migration found for version '%s' with source_module '%s' and destination_module '%s' declared in module '%s'", $data[0], $data[2], $data[3], $data[1])); } } } diff --git a/core/modules/migrate_drupal/tests/src/Unit/MigrationStateUnitTest.php b/core/modules/migrate_drupal/tests/src/Unit/MigrationStateUnitTest.php new file mode 100644 index 0000000000..1787d130cc --- /dev/null +++ b/core/modules/migrate_drupal/tests/src/Unit/MigrationStateUnitTest.php @@ -0,0 +1,247 @@ +prophesize(MigrateFieldPluginManagerInterface::class); + $fieldPluginManager->getDefinitions()->willReturn([ + 'datetime' => [ + 'id' => 'datetime', + 'core' => [7], + 'source_module' => 'date', + 'destination_module' => 'datetime', + ], + 'link' => [ + 'id' => 'link', + 'core' => [6, 7], + 'source_module' => 'link', + 'destination_module' => 'link', + ], + ]); + $moduleHandler = $this->prophesize(ModuleHandlerInterface::class); + $moduleHandler->getModuleList()->willReturn([ + 'entity_test' => [], + 'node' => [], + 'link' => [], + 'rdf' => [], + ]); + vfsStreamWrapper::register(); + $root = new vfsStreamDirectory('modules'); + vfsStreamWrapper::setRoot($root); + $url = vfsStream::url('modules'); + + $files['node'] = << $contents) { + mkdir($url . '/' . $module); + file_put_contents($url . '/' . $module . '/' . $module . '.migrate_drupal.yml', $contents); + } + $moduleHandler->getModuleDirectories()->willReturn(array_combine(array_keys($files), array_map(function ($module) use ($url) { + return $url . '/' . $module; + }, array_keys($files)))); + $migrationState = new MigrationState($fieldPluginManager->reveal(), $moduleHandler->reveal(), $this->createMock(MessengerInterface::class), $this->getStringTranslationStub()); + $migration1 = $this->prophesize(MigrationInterface::class); + $source = $this->prophesize(MigrateSourceInterface::class); + $destination = $this->prophesize(MigrateDestinationInterface::class); + $source->getSourceModule()->willReturn('rdf'); + $destination->getDestinationModule()->willReturn('rdf'); + $migration1->getSourcePlugin()->willReturn($source->reveal()); + $migration1->getDestinationPlugin()->willReturn($destination->reveal()); + $migration1->getPluginId()->willReturn('rdf'); + $migration1->label()->willReturn('rdf'); + $migration2 = $this->prophesize(MigrationInterface::class); + $source = $this->prophesize(MigrateSourceInterface::class); + $destination = $this->prophesize(MigrateDestinationInterface::class); + $source->getSourceModule()->willReturn('filter'); + $destination->getDestinationModule()->willReturn('filter'); + $migration2->getSourcePlugin()->willReturn($source->reveal()); + $migration2->getDestinationPlugin()->willReturn($destination->reveal()); + $migration2->getPluginId()->willReturn('filter'); + $migration2->label()->willReturn('filter'); + $source_system_data = [ + 'module' => [ + 'entity_test' => [ + 'name' => 'entity_test', + 'status' => TRUE, + ], + 'rdf' => [ + 'name' => 'rdf', + 'status' => TRUE, + ], + 'node' => [ + 'name' => 'node', + 'status' => TRUE, + ], + 'date' => [ + 'name' => 'date', + 'status' => TRUE, + ], + 'link' => [ + 'name' => 'link', + 'status' => TRUE, + ], + 'search' => [ + 'name' => 'search', + 'status' => TRUE, + ], + 'filter' => [ + 'name' => 'filter', + 'status' => TRUE, + ], + 'comment' => [ + 'name' => 'comment', + 'status' => TRUE, + ], + 'standard' => [ + 'name' => 'standard', + 'status' => TRUE, + ], + 'color' => [ + 'name' => 'color', + 'status' => TRUE, + ], + 'user' => [ + 'name' => 'user', + 'status' => TRUE, + ], + 'profile' => [ + 'name' => 'profile', + 'status' => TRUE, + ], + // Disabled, hence ignored. + 'dblog' => [ + 'name' => 'dblog', + 'status' => FALSE, + ], + ], + ]; + $states = $migrationState->getUpgradeStates(7, $source_system_data, [$migration1->reveal(), $migration2->reveal()]); + $this->assertEquals([ + MigrationState::NOT_FINISHED => [ + // Declared not finished. + 'entity_test' => 'entity_test, entity_test_rev', + // Destination module comment is not enabled. + 'comment' => 'comment, node', + // Declared finished by one module but not finished by another. + 'user' => 'user', + // Not finished. + 'profile' => 'user', + // Not enabled and not declared. + 'color' => '', + // Destination module not enabled. + 'date' => 'datetime', + // Destination module not enabled. + 'filter' => 'filter', + // No discovered or declared state. + 'search' => '', + ], + MigrationState::FINISHED => [ + 'node' => 'node', + 'link' => 'link', + 'rdf' => 'rdf', + ], + ], $states); + $source_system_data['module']['content'] = [ + 'name' => 'content', + 'status' => TRUE, + ]; + unset($source_system_data['module']['rdf'], $source_system_data['module']['filter']); + $states = $migrationState->getUpgradeStates(6, $source_system_data, []); + $this->assertEquals([ + MigrationState::NOT_FINISHED => [ + // Declared not finished. + 'entity_test' => 'entity_test', + // Destination module comment is not enabled. + 'comment' => 'comment, node', + 'user' => 'user', + // Not finished. + 'profile' => 'user', + // Not declared and non compatible field plugin. + 'date' => '', + // No discovered or declared state. + 'search' => '', + ], + MigrationState::FINISHED => [ + 'node' => 'node', + 'content' => 'node', + // Update path not needed. + 'color' => 'core', + 'link' => 'link', + ], + ], $states); + } + +} diff --git a/core/modules/migrate_drupal_ui/src/Form/ReviewForm.php b/core/modules/migrate_drupal_ui/src/Form/ReviewForm.php index 23eb2b8614..6dfff3cb7a 100644 --- a/core/modules/migrate_drupal_ui/src/Form/ReviewForm.php +++ b/core/modules/migrate_drupal_ui/src/Form/ReviewForm.php @@ -6,6 +6,7 @@ use Drupal\Core\State\StateInterface; use Drupal\Core\TempStore\PrivateTempStoreFactory; use Drupal\migrate\Plugin\MigrationPluginManagerInterface; +use Drupal\migrate_drupal\MigrationState; use Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface; use Drupal\migrate_drupal_ui\Batch\MigrateUpgradeImportBatch; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -29,21 +30,6 @@ */ class ReviewForm extends MigrateUpgradeFormBase { - /** - * Source modules status for will be upgraded. - * - * @var string - */ - const FINISHED = 'finished'; - - /** - * Source modules status for will not be upgraded. - * - * @var string - */ - const NOT_FINISHED = 'not_finished'; - - /** * The state service. * @@ -72,6 +58,13 @@ class ReviewForm extends MigrateUpgradeFormBase { */ protected $migrations; + /** + * Migration state service. + * + * @var \Drupal\migrate_drupal\MigrationState + */ + protected $migrationState; + /** * ReviewForm constructor. * @@ -83,12 +76,15 @@ class ReviewForm extends MigrateUpgradeFormBase { * The field plugin manager service. * @param \Drupal\Core\TempStore\PrivateTempStoreFactory $tempstore_private * The private tempstore factory. + * @param \Drupal\migrate_drupal\MigrationState $migrationState + * Migration state service. */ - public function __construct(StateInterface $state, MigrationPluginManagerInterface $migration_plugin_manager, MigrateFieldPluginManagerInterface $field_plugin_manager, PrivateTempStoreFactory $tempstore_private) { + public function __construct(StateInterface $state, MigrationPluginManagerInterface $migration_plugin_manager, MigrateFieldPluginManagerInterface $field_plugin_manager, PrivateTempStoreFactory $tempstore_private, MigrationState $migrationState) { parent::__construct($tempstore_private); $this->state = $state; $this->pluginManager = $migration_plugin_manager; $this->fieldPluginManager = $field_plugin_manager; + $this->migrationState = $migrationState; } /** @@ -99,7 +95,8 @@ public static function create(ContainerInterface $container) { $container->get('state'), $container->get('plugin.manager.migration'), $container->get('plugin.manager.migrate.field'), - $container->get('tempstore.private') + $container->get('tempstore.private'), + $container->get('migrate_drupal.migration_state') ); } @@ -132,7 +129,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { $migrations = $this->pluginManager->createInstances(array_keys($this->store->get('migrations'))); // Get the upgrade states for the source modules. - $display = $this->getUpgradeStates($version, $system_data, $migrations); + $display = $this->migrationState->getUpgradeStates($version, $system_data, $migrations); // Missing migrations. $missing_module_list = [ @@ -152,8 +149,8 @@ public function buildForm(array $form, FormStateInterface $form_state) { ]; $missing_count = 0; - if (isset($display[static::NOT_FINISHED])) { - foreach ($display[static::NOT_FINISHED] as $source_module => $destination_modules) { + if (isset($display[MigrationState::NOT_FINISHED])) { + foreach ($display[MigrationState::NOT_FINISHED] as $source_module => $destination_modules) { $missing_count++; // Get the migration status for this $source_module, if a module of the // same name exists on the destination site. @@ -193,8 +190,8 @@ public function buildForm(array $form, FormStateInterface $form_state) { ]; $available_count = 0; - if (isset($display[static::FINISHED])) { - foreach ($display[static::FINISHED] as $source_module => $destination_modules) { + if (isset($display[MigrationState::FINISHED])) { + foreach ($display[MigrationState::FINISHED] as $source_module => $destination_modules) { $available_count++; $available_module_list['module_list'][] = [ 'source_module' => [ diff --git a/core/modules/taxonomy/taxonomy.migrate_drupal.yml b/core/modules/taxonomy/taxonomy.migrate_drupal.yml index cc2bb13e8f..5dd3d6ba85 100644 --- a/core/modules/taxonomy/taxonomy.migrate_drupal.yml +++ b/core/modules/taxonomy/taxonomy.migrate_drupal.yml @@ -1,5 +1,9 @@ finished: 6: - taxonomy: core, taxonomy + taxonomy: + - core + - taxonomy 7: - taxonomy: core, taxonomy + taxonomy: + - core + - taxonomy