From 5d12af3d39bb6f6483d19cebbfea1085d2bac8e8 Mon Sep 17 00:00:00 2001 From: mikeryan <mikeryan@4420.no-reply.drupal.org> Date: Tue, 9 May 2017 14:17:24 -0500 Subject: [PATCH] Issue #2752335 by mikeryan, dpalmer, joelpittet, ckaotik, heddn, Berdir, chx, Wim Leers: Properly integrate configuration-entity-based migrations with the core plugin manager --- README.txt | 9 +--- migrate_example/README.txt | 30 +++++++++--- .../beer_comment.yml} | 0 migrate_plus.info.yml | 2 +- migrate_plus.module | 13 +++++ migrate_plus.services.yml | 3 -- migrations/migration_config_deriver.yml | 6 +++ .../Discovery/ConfigEntityDiscovery.php | 49 ------------------- src/Plugin/MigrationConfigDeriver.php | 28 +++++++++++ .../MigrationConfigEntityPluginManager.php | 25 ---------- .../src/Kernel/MigrationConfigEntityTest.php | 18 +++---- tests/src/Kernel/MigrationGroupTest.php | 2 +- 12 files changed, 82 insertions(+), 103 deletions(-) rename migrate_example/{config/install/migrate_plus.migration.beer_comment.yml => migrations/beer_comment.yml} (100%) create mode 100644 migrations/migration_config_deriver.yml delete mode 100644 src/Plugin/Discovery/ConfigEntityDiscovery.php create mode 100644 src/Plugin/MigrationConfigDeriver.php delete mode 100644 src/Plugin/MigrationConfigEntityPluginManager.php diff --git a/README.txt b/README.txt index af3cafbc..797082e3 100644 --- a/README.txt +++ b/README.txt @@ -5,13 +5,6 @@ Extensions to base API ====================== * A Migration configuration entity is provided, enabling persistance of dynamic migration configuration. -* A ConfigEntityDiscovery class is implemented which enables plugin - configuration to be based on configuration entities. This is fully general - - it can be used for any configuration entity type, not just migrations. -* A MigrationConfigEntityPluginManager class and corresponding - plugin.manager.config_entity_migration service is provided, to enable - discovery and instantiation of migration plugins based on the Migration - configuration entity. * A MigrationGroup configuration entity is provided, which enables migrations to be organized in groups, and to maintain shared configuration in one place. * A MigrateEvents::PREPARE_ROW event is provided to dispatch hook_prepare_row() @@ -73,7 +66,7 @@ Authentication -------------- * The basic authentication plugin provides HTTP Basic authentication. * The digest authentication plugin provides HTTP Digest authentication. -* The oauth2 authencitation plugin provides OAuth2 authentication over HTTP. +* The oauth2 authentication plugin provides OAuth2 authentication over HTTP. Examples ======== diff --git a/migrate_example/README.txt b/migrate_example/README.txt index 125e3b0f..32d77da9 100644 --- a/migrate_example/README.txt +++ b/migrate_example/README.txt @@ -22,12 +22,30 @@ STRUCTURE --------- There are two primary components to this example: -1. Migration configuration, in the config/install directory. These YAML files - describe the migration process and provide the mappings from the source data - to Drupal's destination entities. The YAML file names are prefixed with - 'migrate_plus.migration.' (because, reading from right to left, they define - "migration" configuration entities, and the configuration entity type is - defined by the "migrate_plus" module). +1. Migration configuration, in the migrations and config/install directories. + These YAML files describe the migration process and provide the mappings from + the source data to Drupal's destination entities. The difference between the + two possible directories: + + a. Files in the migrations directory provide configuration directly for the + migration plugins. The filenames are of the form <migration ID>.yml. This + approach is recommended when your migration configuration is fully hardcoded + and does not need to be overridden (e.g., you don't need to change the URL to + a source web service through an admin UI). While developing migrations, + changes to these files require at most a 'drush cr' to load your changes. + + b. Files in the config/install directory provide migration configuration as + configuration entities, and have names of the form + migrate_plus.migration.<migration ID>.yml ("migration" because they define + entities of the "migration" type, and "migrate_plus" because that is the + module which implements the "migration" type). Migrations defined in this way + may have their configuration modified (in particular, through a web UI) by + loading the configuration entity, modifying its configuration, and saving the + entity. When developing, to get edits to the .yml files in config/install to + take effect in active configuration, use the config_devel module. + + Configuration in either type of file is identical - the only differences are + the directories and filenames. 2. Source plugins, in src/Plugin/migrate/source. These are referenced from the configuration files, and provide the source data to the migration processing diff --git a/migrate_example/config/install/migrate_plus.migration.beer_comment.yml b/migrate_example/migrations/beer_comment.yml similarity index 100% rename from migrate_example/config/install/migrate_plus.migration.beer_comment.yml rename to migrate_example/migrations/beer_comment.yml diff --git a/migrate_plus.info.yml b/migrate_plus.info.yml index 2eb2a605..05b5477b 100644 --- a/migrate_plus.info.yml +++ b/migrate_plus.info.yml @@ -4,4 +4,4 @@ description: 'Enhancements to core migration support' package: Migration core: 8.x dependencies: - - drupal:migrate (>=8.2) + - drupal:migrate (>=8.3) diff --git a/migrate_plus.module b/migrate_plus.module index 67efba62..0dbddc47 100644 --- a/migrate_plus.module +++ b/migrate_plus.module @@ -23,6 +23,19 @@ function migrate_plus_migration_plugins_alter(array &$migrations) { $migrations[$id]['class'] = 'Drupal\migrate\Plugin\Migration'; } + // For derived configuration entity-based migrations, strip the deriver + // prefix so we can reference migrations by the IDs they specify (i.e., + // the migration that specifies "id: temp" can be referenced as "temp" + // rather than "migration_config_deriver:temp"). + $prefix = 'migration_config_deriver:'; + if (strpos($id, $prefix) === 0) { + $new_id = substr($id, strlen($prefix)); + $migrations[$new_id] = $migrations[$id]; + unset($migrations[$id]); + $id = $new_id; + } + + // Integrate shared group configuration into the migration. if (empty($migration['migration_group'])) { $migration['migration_group'] = 'default'; } diff --git a/migrate_plus.services.yml b/migrate_plus.services.yml index 4b334456..2ca3363c 100644 --- a/migrate_plus.services.yml +++ b/migrate_plus.services.yml @@ -8,6 +8,3 @@ services: plugin.manager.migrate_plus.data_parser: class: Drupal\migrate_plus\DataParserPluginManager parent: default_plugin_manager - plugin.manager.config_entity_migration: - class: Drupal\migrate_plus\Plugin\MigrationConfigEntityPluginManager - parent: plugin.manager.migration diff --git a/migrations/migration_config_deriver.yml b/migrations/migration_config_deriver.yml new file mode 100644 index 00000000..9fc597e7 --- /dev/null +++ b/migrations/migration_config_deriver.yml @@ -0,0 +1,6 @@ +id: migration_config_deriver +deriver: Drupal\migrate_plus\Plugin\MigrationConfigDeriver +# @todo: Remove if/when https://www.drupal.org/node/2797421 is fixed. +# Unused source configuration must be added to prevent errors. +source: + plugin: embedded_data diff --git a/src/Plugin/Discovery/ConfigEntityDiscovery.php b/src/Plugin/Discovery/ConfigEntityDiscovery.php deleted file mode 100644 index 551c8a7a..00000000 --- a/src/Plugin/Discovery/ConfigEntityDiscovery.php +++ /dev/null @@ -1,49 +0,0 @@ -<?php - -namespace Drupal\migrate_plus\Plugin\Discovery; - -use Drupal\Component\Plugin\Discovery\DiscoveryInterface; -use Drupal\Component\Plugin\Discovery\DiscoveryTrait; - -/** - * Allows configuration entities to define plugin definitions. - */ -class ConfigEntityDiscovery implements DiscoveryInterface { - - use DiscoveryTrait; - - /** - * Entity type to query. - * - * @var string - */ - protected $entityType; - - /** - * Construct a YamlDiscovery object. - * - * @param string $entity_type - * The entity type to query for. - */ - function __construct($entity_type) { - $this->entityType = $entity_type; - } - - /** - * {@inheritdoc} - */ - public function getDefinitions() { - $definition = \Drupal::entityTypeManager()->getDefinition($this->entityType); - $prefix = $definition->getConfigPrefix() . '.'; - $storage = \Drupal::service('config.storage'); - $query = \Drupal::entityQuery($this->entityType); - $ids = $query->execute(); - $definitions = []; - foreach ($ids as $id) { - $definitions[$id] = $storage->read($prefix . $id); - } - - return $definitions; - } - -} diff --git a/src/Plugin/MigrationConfigDeriver.php b/src/Plugin/MigrationConfigDeriver.php new file mode 100644 index 00000000..01354449 --- /dev/null +++ b/src/Plugin/MigrationConfigDeriver.php @@ -0,0 +1,28 @@ +<?php + +namespace Drupal\migrate_plus\Plugin; + +use Drupal\Component\Plugin\Derivative\DeriverBase; +use Drupal\migrate_plus\Entity\Migration; + +/** + * Expose migration entities in the active config store as derivative plugins. + */ +class MigrationConfigDeriver extends DeriverBase { + + /** + * {@inheritdoc} + */ + public function getDerivativeDefinitions($base_plugin_definition) { + // Always rederive from scratch, because changes may have been made without + // clearing our internal cache. + $this->derivatives = []; + $migrations = Migration::loadMultiple(); + /** @var \Drupal\migrate_plus\Entity\MigrationInterface $migration */ + foreach ($migrations as $id => $migration) { + $this->derivatives[$id] = $migration->toArray(); + } + return $this->derivatives; + } + +} diff --git a/src/Plugin/MigrationConfigEntityPluginManager.php b/src/Plugin/MigrationConfigEntityPluginManager.php deleted file mode 100644 index 25009758..00000000 --- a/src/Plugin/MigrationConfigEntityPluginManager.php +++ /dev/null @@ -1,25 +0,0 @@ -<?php - -namespace Drupal\migrate_plus\Plugin; - -use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator; -use Drupal\migrate\Plugin\MigrationPluginManager; -use Drupal\migrate_plus\Plugin\Discovery\ConfigEntityDiscovery; - -/** - * Plugin manager for migration plugins. - */ -class MigrationConfigEntityPluginManager extends MigrationPluginManager { - - /** - * {@inheritdoc} - */ - protected function getDiscovery() { - if (!isset($this->discovery)) { - $discovery = new ConfigEntityDiscovery('migration'); - $this->discovery = new ContainerDerivativeDiscoveryDecorator($discovery); - } - return $this->discovery; - } - -} diff --git a/tests/src/Kernel/MigrationConfigEntityTest.php b/tests/src/Kernel/MigrationConfigEntityTest.php index f309df4a..386363a3 100644 --- a/tests/src/Kernel/MigrationConfigEntityTest.php +++ b/tests/src/Kernel/MigrationConfigEntityTest.php @@ -4,7 +4,6 @@ namespace Drupal\Tests\migrate_plus\Kernel; use Drupal\KernelTests\KernelTestBase; use Drupal\migrate_plus\Entity\Migration; -use Drupal\migrate_plus\Plugin\MigrationConfigEntityPluginManager; /** * Test migration config entity discovery. @@ -16,13 +15,13 @@ class MigrationConfigEntityTest extends KernelTestBase { public static $modules = ['migrate', 'migrate_plus']; /** - * @var MigrationConfigEntityPluginManager + * @var \Drupal\migrate\Plugin\MigrationPluginManager */ - protected $pluginMananger; + protected $pluginManager; protected function setUp() { parent::setUp(); - $this->pluginMananger = \Drupal::service('plugin.manager.config_entity_migration'); + $this->pluginManager = \Drupal::service('plugin.manager.migration'); } public function testCacheInvalidation() { @@ -36,19 +35,18 @@ class MigrationConfigEntityTest extends KernelTestBase { ]); $config->save(); - $this->assertTrue($this->pluginMananger->getDefinition('test')); - $this->assertSame('Label A', $this->pluginMananger->getDefinition('test')['label']); + $this->assertTrue($this->pluginManager->getDefinition('test')); + $this->assertSame('Label A', $this->pluginManager->getDefinition('test')['label']); // Clear static cache in the plugin manager, the cache tag take care of the // persistent cache. - $this->pluginMananger->useCaches(FALSE); - $this->pluginMananger->useCaches(TRUE); + $this->pluginManager->useCaches(FALSE); + $this->pluginManager->useCaches(TRUE); $config->set('label', 'Label B'); $config->save(); - $this->assertSame('Label B', $this->pluginMananger->getDefinition('test')['label']); - $this->assertSame('Label B', \Drupal::service('plugin.manager.migration')->getDefinition('test')['label']); + $this->assertSame('Label B', $this->pluginManager->getDefinition('test')['label']); } } diff --git a/tests/src/Kernel/MigrationGroupTest.php b/tests/src/Kernel/MigrationGroupTest.php index 42c1f9f8..4cdd5525 100644 --- a/tests/src/Kernel/MigrationGroupTest.php +++ b/tests/src/Kernel/MigrationGroupTest.php @@ -76,7 +76,7 @@ class MigrationGroupTest extends KernelTestBase { 'destination' => ['plugin' => 'field_storage_config'], ]; /** @var \Drupal\migrate\Plugin\MigrationInterface $loaded_migration */ - $loaded_migration = $this->container->get('plugin.manager.config_entity_migration') + $loaded_migration = $this->container->get('plugin.manager.migration') ->createInstance('specific_migration'); foreach ($expected_config as $key => $expected_value) { $actual_value = $loaded_migration->get($key); -- GitLab