Skip to content
Snippets Groups Projects
Commit 5d12af3d authored by Mike Ryan's avatar Mike Ryan Committed by Mike Ryan
Browse files

Issue #2752335 by mikeryan, dpalmer, joelpittet, ckaotik, heddn, Berdir, chx,...

Issue #2752335 by mikeryan, dpalmer, joelpittet, ckaotik, heddn, Berdir, chx, Wim Leers: Properly integrate configuration-entity-based migrations with the core plugin manager
parent 171758e9
No related branches found
No related tags found
No related merge requests found
...@@ -5,13 +5,6 @@ Extensions to base API ...@@ -5,13 +5,6 @@ Extensions to base API
====================== ======================
* A Migration configuration entity is provided, enabling persistance of dynamic * A Migration configuration entity is provided, enabling persistance of dynamic
migration configuration. 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 * A MigrationGroup configuration entity is provided, which enables migrations to
be organized in groups, and to maintain shared configuration in one place. be organized in groups, and to maintain shared configuration in one place.
* A MigrateEvents::PREPARE_ROW event is provided to dispatch hook_prepare_row() * A MigrateEvents::PREPARE_ROW event is provided to dispatch hook_prepare_row()
...@@ -73,7 +66,7 @@ Authentication ...@@ -73,7 +66,7 @@ Authentication
-------------- --------------
* The basic authentication plugin provides HTTP Basic authentication. * The basic authentication plugin provides HTTP Basic authentication.
* The digest authentication plugin provides HTTP Digest 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 Examples
======== ========
......
...@@ -22,12 +22,30 @@ STRUCTURE ...@@ -22,12 +22,30 @@ STRUCTURE
--------- ---------
There are two primary components to this example: There are two primary components to this example:
1. Migration configuration, in the config/install directory. These YAML files 1. Migration configuration, in the migrations and config/install directories.
describe the migration process and provide the mappings from the source data These YAML files describe the migration process and provide the mappings from
to Drupal's destination entities. The YAML file names are prefixed with the source data to Drupal's destination entities. The difference between the
'migrate_plus.migration.' (because, reading from right to left, they define two possible directories:
"migration" configuration entities, and the configuration entity type is
defined by the "migrate_plus" module). 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 2. Source plugins, in src/Plugin/migrate/source. These are referenced from the
configuration files, and provide the source data to the migration processing configuration files, and provide the source data to the migration processing
......
...@@ -4,4 +4,4 @@ description: 'Enhancements to core migration support' ...@@ -4,4 +4,4 @@ description: 'Enhancements to core migration support'
package: Migration package: Migration
core: 8.x core: 8.x
dependencies: dependencies:
- drupal:migrate (>=8.2) - drupal:migrate (>=8.3)
...@@ -23,6 +23,19 @@ function migrate_plus_migration_plugins_alter(array &$migrations) { ...@@ -23,6 +23,19 @@ function migrate_plus_migration_plugins_alter(array &$migrations) {
$migrations[$id]['class'] = 'Drupal\migrate\Plugin\Migration'; $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'])) { if (empty($migration['migration_group'])) {
$migration['migration_group'] = 'default'; $migration['migration_group'] = 'default';
} }
......
...@@ -8,6 +8,3 @@ services: ...@@ -8,6 +8,3 @@ services:
plugin.manager.migrate_plus.data_parser: plugin.manager.migrate_plus.data_parser:
class: Drupal\migrate_plus\DataParserPluginManager class: Drupal\migrate_plus\DataParserPluginManager
parent: default_plugin_manager parent: default_plugin_manager
plugin.manager.config_entity_migration:
class: Drupal\migrate_plus\Plugin\MigrationConfigEntityPluginManager
parent: plugin.manager.migration
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
<?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;
}
}
<?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;
}
}
<?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;
}
}
...@@ -4,7 +4,6 @@ namespace Drupal\Tests\migrate_plus\Kernel; ...@@ -4,7 +4,6 @@ namespace Drupal\Tests\migrate_plus\Kernel;
use Drupal\KernelTests\KernelTestBase; use Drupal\KernelTests\KernelTestBase;
use Drupal\migrate_plus\Entity\Migration; use Drupal\migrate_plus\Entity\Migration;
use Drupal\migrate_plus\Plugin\MigrationConfigEntityPluginManager;
/** /**
* Test migration config entity discovery. * Test migration config entity discovery.
...@@ -16,13 +15,13 @@ class MigrationConfigEntityTest extends KernelTestBase { ...@@ -16,13 +15,13 @@ class MigrationConfigEntityTest extends KernelTestBase {
public static $modules = ['migrate', 'migrate_plus']; public static $modules = ['migrate', 'migrate_plus'];
/** /**
* @var MigrationConfigEntityPluginManager * @var \Drupal\migrate\Plugin\MigrationPluginManager
*/ */
protected $pluginMananger; protected $pluginManager;
protected function setUp() { protected function setUp() {
parent::setUp(); parent::setUp();
$this->pluginMananger = \Drupal::service('plugin.manager.config_entity_migration'); $this->pluginManager = \Drupal::service('plugin.manager.migration');
} }
public function testCacheInvalidation() { public function testCacheInvalidation() {
...@@ -36,19 +35,18 @@ class MigrationConfigEntityTest extends KernelTestBase { ...@@ -36,19 +35,18 @@ class MigrationConfigEntityTest extends KernelTestBase {
]); ]);
$config->save(); $config->save();
$this->assertTrue($this->pluginMananger->getDefinition('test')); $this->assertTrue($this->pluginManager->getDefinition('test'));
$this->assertSame('Label A', $this->pluginMananger->getDefinition('test')['label']); $this->assertSame('Label A', $this->pluginManager->getDefinition('test')['label']);
// Clear static cache in the plugin manager, the cache tag take care of the // Clear static cache in the plugin manager, the cache tag take care of the
// persistent cache. // persistent cache.
$this->pluginMananger->useCaches(FALSE); $this->pluginManager->useCaches(FALSE);
$this->pluginMananger->useCaches(TRUE); $this->pluginManager->useCaches(TRUE);
$config->set('label', 'Label B'); $config->set('label', 'Label B');
$config->save(); $config->save();
$this->assertSame('Label B', $this->pluginMananger->getDefinition('test')['label']); $this->assertSame('Label B', $this->pluginManager->getDefinition('test')['label']);
$this->assertSame('Label B', \Drupal::service('plugin.manager.migration')->getDefinition('test')['label']);
} }
} }
...@@ -76,7 +76,7 @@ class MigrationGroupTest extends KernelTestBase { ...@@ -76,7 +76,7 @@ class MigrationGroupTest extends KernelTestBase {
'destination' => ['plugin' => 'field_storage_config'], 'destination' => ['plugin' => 'field_storage_config'],
]; ];
/** @var \Drupal\migrate\Plugin\MigrationInterface $loaded_migration */ /** @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'); ->createInstance('specific_migration');
foreach ($expected_config as $key => $expected_value) { foreach ($expected_config as $key => $expected_value) {
$actual_value = $loaded_migration->get($key); $actual_value = $loaded_migration->get($key);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment