Problem/Motivation

Merging configuration into migration plugins at runtime is more difficult than it needs to be:

$migration = \Drupal::service('plugin.manager.migration')->createInstance('d6_file');
// Must pull out entire source configuration, modify it, and put it back.
$source = $migration->getSourceConfiguration();
$source['constants']['source_base_path'] = $source_base_path;
// set() only exists to work around this problem - see #2796755: [PP-1] Deprecate Migration::set()
$migration->set('source', $source);

when it could be

$configuration['source']['constants']['source_base_path'] = $source_base_path;
$migration = \Drupal::service('plugin.manager.migration')->createInstance('d6_file', $configuration);

Part of the problem is that createInstance() does not conform to the documented API (FactoryInterface). The $configuration passed to createInstance() is supposed to be simply the plugin's configuration, but as currently implemented the caller must wrap it in an array keyed by the plugin ID.

Proposed resolution

Properly implement createInstance(), and do a deepMerge() on the configuration.

Remaining tasks

None.

User interface changes

n/a

API changes

No change to documented APIs - MigrationPluginManager::createInstance() behavior changed to conform to API.

Data model changes

n/a

Original issue summary

Problem/Motivation

MigrateUpgradeRunBatch manually sets destination configuration onto the migration after loading it, this should not be needed.

Proposed resolution

Find a solution.

Remaining tasks

Write a patch

User interface changes

n/a

API changes

Likely we'll need a way for sources and destinations to accept their required configuration

Data model changes

n/a

Comments

benjy created an issue. See original summary.

mikeryan’s picture

Any work being done on this? It was suggested at https://www.drupal.org/node/2625696#comment-10955205 that this would address the issue of being able to discover only relevant migration plugins. I'm working on getting migrate_tools and migrate_plus working against 8.1.x #2667368: Make migrate_tools work with Drupal 8.1.x and it's not looking good so far...

mikeryan’s picture

Priority: Normal » Major

Another big problem here (besides the run-time destination injection in the issue summary) is the source connection information. The upgrade UI stores source connection key and database info in state keyed as (e.g.) migrate_drupal_6. Previously it set the 'database_state_key' configuration on each source plugin to that key - now it instead sets a global migrate.fallback_state_key. SqlBase::getDatabase() uses this global fallback key for all migrations if there is no explicit database_state_key on the source - even non-Drupal migration, and even if the source plugin contains explicit database configuration.

Previously configuration for migrations was simply part of the configuration entity, now we need a way to save any added/overridden configuration for migration plugins and load it with the plugins. How/where do we do that?

benjy’s picture

Yeah you're correct, the global key was added in the plugins patch.

How come you can't set a database_state_key in source anymore? I still see if (isset($this->configuration['database_state_key'])) { in SqlBase::getConnection() ?

mikeryan’s picture

database_state_key is still supported in the general Sql plugin, so general migration can (and should!) use it, but the migrations-as-plugins patch removed the upgrade UI's use of it in favor of that global fallback_state_key.

mikeryan’s picture

mikeryan’s picture

Issue tags: +Migrate critical
benjy’s picture

Status: Active » Needs review
StatusFileSize
new2.98 KB

I discussed this with chx and he suggested merging the configuration with the definition, it's a simple solution but it could just work. Initially I was thinking plugins would need a way to state required configuration and maybe even provide the relevant API's to collect that data from the runners but this approach solves the nasty and it's very inline with how plugins work.

benjy’s picture

+++ b/core/modules/migrate_drupal_ui/src/MigrateUpgradeRunBatch.php
@@ -103,18 +103,18 @@ public static function run($initial_ids, $operation, $config, &$context) {
+    debug($definition);

ah, left a debug in there, will remove later.

mikeryan’s picture

Looks good! It does runtime plugin configuration injection just how plugins were designed, so... yeah.

I'll hold off on RTBC - it'd be good to get another pair of eyes in case we're missing something obvious. Also, note that whichever of this or #2695297: Refactor EntityFile and use process plugins instead gets in first, the other will need to be rerolled (since both touch where source_base_path is set on upgrades), and I'd like to see that one committed first...

mikeryan’s picture

Status: Needs review » Postponed
mikeryan’s picture

Status: Postponed » Needs work
Issue tags: +Needs reroll

EntityFile refactor is in. If I'd known how long it would take that one, I wouldn't have postponed this one, but we can reroll now...

mikeryan’s picture

Version: 8.1.x-dev » 8.2.x-dev
Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new3.01 KB

Reroll for 8.2.x with the EntityFile patch. If we still want to commit this to 8.1.x the patch in #8 is the one to go.

I've tested this manually - ran an upgrade through the UI with an HTTP source and the files were properly migrated, demonstrating that the configuration was properly set.

phenaproxima’s picture

Status: Needs review » Reviewed & tested by the community

It looks OK to me.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs tests
  1. +++ b/core/modules/migrate/src/Plugin/Migration.php
    @@ -292,7 +292,7 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition
    -    foreach ($plugin_definition as $key => $value) {
    +    foreach (NestedArray::mergeDeep($plugin_definition, $configuration) as $key => $value) {
    
    +++ b/core/modules/migrate/src/Plugin/MigrationPluginManager.php
    @@ -77,7 +77,7 @@ protected function getDiscovery() {
    -    $instances = $this->createInstances([$plugin_id], $configuration);
    +    $instances = $this->createInstances([$plugin_id], [$plugin_id => $configuration]);
    

    These fixes looks testable.

  2. +++ b/core/modules/migrate_drupal_ui/src/MigrateUpgradeRunBatch.php
    @@ -103,19 +103,17 @@ public static function run($initial_ids, $operation, $config, &$context) {
    +    if ($definition['destination']['plugin'] === 'entity:file') {
           // Make sure we have a single trailing slash.
    -      $source_base_path = rtrim($config['source_base_path'], '/') . '/';
    -      $source = $migration->getSourceConfiguration();
    -      $source['constants']['source_base_path'] = $source_base_path;
    -      $migration->set('source', $source);
    +      $configuration['source']['constants']['source_base_path'] = rtrim($config['source_base_path'], '/') . '/';
         }
    

    It is a shame we still have to do this special casing. There is an issue about this somewhere.

mikeryan’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
StatusFileSize
new5.11 KB
new2.79 KB

Test added, let me know if there are any scenarios you'd like added. The interdiff is kinda funky, MigrationPluginManager didn't actually change...

It is a shame we still have to do this special casing. There is an issue about this somewhere.

I don't see one. The idea is that only the migrations with entity:file destinations need the source_base_path - I'm not sure what else we can do here (other than just stuff source_base_path into all migrations). Anyway, I think that's out-of-scope here.

phenaproxima’s picture

+++ b/core/modules/migrate/tests/src/Kernel/Plugin/MigrationPluginConfigurationTest.php
@@ -0,0 +1,74 @@
+      // Add new configuration.

This comment, and the other one in the data provider, are vague. I don't understand what it's talking about. Can this be better documented? Other than that, I don't yet see a problem.

mikeryan’s picture

StatusFileSize
new5.32 KB
new1.22 KB
phenaproxima’s picture

Status: Needs review » Reviewed & tested by the community

Ah! Better -- now I see what this is trying to do. Assuming the tests pass, and that nobody wants additional test scenarios, I'm comfortable with this change. RTBC.

andypost’s picture

  1. +++ b/core/modules/migrate/src/Plugin/Migration.php
    @@ -292,7 +292,7 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition
    -    foreach ($plugin_definition as $key => $value) {
    +    foreach (NestedArray::mergeDeep($plugin_definition, $configuration) as $key => $value) {
    

    makes sense

  2. +++ b/core/modules/migrate/src/Plugin/MigrationPluginManager.php
    @@ -86,7 +86,7 @@ protected function getDiscovery() {
    -    $instances = $this->createInstances([$plugin_id], $configuration);
    +    $instances = $this->createInstances([$plugin_id], [$plugin_id => $configuration]);
    

    is not this a api change?
    configuration passed differently... now

mikeryan’s picture

Issue tags: +Needs change record

That's not an API change - it's fixing createInstance() to conform to the documented API (FactoryInterface). The $configuration passed to createInstance() is supposed to be simply the plugin's configuration, but without this change that would only worked if the caller had wrapped it in an array keyed by the plugin ID (which createInstance() now does for you, as it should be).

That being said, we should have a change record demonstrating how you can now merge configuration into migration plugins more cleanly...

mikeryan’s picture

Issue tags: -Needs change record

Draft change record added.

mikeryan’s picture

Note that this fix will obviate the need for Migration::set(): #2796755: [PP-1] Deprecate Migration::set()

xjm’s picture

Issue tags: +rc eligible

As an improvement to an experimental module, this is rc eligible per: https://www.drupal.org/core/d8-allowed-changes#rc

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

Whilst the changes on this issue are an improvement they are not really addressing the fundamental issue that the MigrateUpgradeRunBatch::run() method has to know that it needs to set this configuration. Before proceeding with this patch we need:

  • a new title
  • issue summary update
  • a new issue created to reflect the original purpose of this issue
  • an @todo added to that issue in the code
mikeryan’s picture

Title: Migrate sources and destinations need a way to get their requirements » Provide clean way to merge configuration into migration plugins
Issue summary: View changes
Status: Needs work » Needs review
StatusFileSize
new5.4 KB
new728 bytes

As requested.

phenaproxima’s picture

Status: Needs review » Reviewed & tested by the community
alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed and pushed 2a3217c to 8.3.x and a707147 to 8.2.x. Thanks!

diff --git a/core/modules/migrate/tests/src/Kernel/Plugin/MigrationPluginConfigurationTest.php b/core/modules/migrate/tests/src/Kernel/Plugin/MigrationPluginConfigurationTest.php
index 55cce71..827af91 100644
--- a/core/modules/migrate/tests/src/Kernel/Plugin/MigrationPluginConfigurationTest.php
+++ b/core/modules/migrate/tests/src/Kernel/Plugin/MigrationPluginConfigurationTest.php
@@ -2,9 +2,7 @@
 
 namespace Drupal\Tests\migrate\Kernel\Plugin;
 
-use Drupal\Core\Database\Database;
 use Drupal\KernelTests\KernelTestBase;
-use Drupal\migrate\Plugin\MigrationInterface;
 
 /**
  * Tests the migration plugin manager.

Removed unused uses on commit.

  • alexpott committed 2a3217c on 8.3.x
    Issue #2681869 by mikeryan, benjy: Provide clean way to merge...

  • alexpott committed a707147 on 8.2.x
    Issue #2681869 by mikeryan, benjy: Provide clean way to merge...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

quietone’s picture