From 52d4ba85030c7a4a46269322ac7ff5211948c648 Mon Sep 17 00:00:00 2001
From: Mike Ryan <mikeryan@virtuoso-performance.com>
Date: Mon, 11 Apr 2016 09:35:48 -0500
Subject: [PATCH] Issue #2701277 by mikeryan: Use configuration entities as a
 registration mechanism for migrations

---
 .../schema/migrate_plus.data_types.schema.yml |  40 +++++
 .../migrate_plus.destination.schema.yml       |  18 +++
 config/schema/migrate_plus.process.schema.yml | 145 ++++++++++++++++++
 config/schema/migrate_plus.schema.yml         |  49 +++++-
 config/schema/migrate_plus.source.schema.yml  |  34 ++++
 .../migrate_plus.migration.beer_comment.yml}  |   0
 .../migrate_plus.migration.beer_node.yml}     |   0
 .../migrate_plus.migration.beer_term.yml}     |   3 +
 .../migrate_plus.migration.beer_user.yml}     |   4 +-
 migrate_plus.services.yml                     |   3 +
 src/Entity/Migration.php                      |  44 ++++++
 src/Entity/MigrationGroup.php                 |   1 -
 src/Entity/MigrationInterface.php             |  17 ++
 .../Discovery/ConfigEntityDiscovery.php       |  54 +++++++
 .../MigrationConfigEntityPluginManager.php    |  30 ++++
 15 files changed, 439 insertions(+), 3 deletions(-)
 create mode 100644 config/schema/migrate_plus.data_types.schema.yml
 create mode 100644 config/schema/migrate_plus.destination.schema.yml
 create mode 100644 config/schema/migrate_plus.process.schema.yml
 create mode 100644 config/schema/migrate_plus.source.schema.yml
 rename migrate_example/{migrations/migrate.migration.beer_comment.yml => config/install/migrate_plus.migration.beer_comment.yml} (100%)
 rename migrate_example/{migrations/migrate.migration.beer_node.yml => config/install/migrate_plus.migration.beer_node.yml} (100%)
 rename migrate_example/{migrations/migrate.migration.beer_term.yml => config/install/migrate_plus.migration.beer_term.yml} (97%)
 rename migrate_example/{migrations/migrate.migration.beer_user.yml => config/install/migrate_plus.migration.beer_user.yml} (97%)
 create mode 100644 src/Entity/Migration.php
 create mode 100644 src/Entity/MigrationInterface.php
 create mode 100644 src/Plugin/Discovery/ConfigEntityDiscovery.php
 create mode 100644 src/Plugin/MigrationConfigEntityPluginManager.php

diff --git a/config/schema/migrate_plus.data_types.schema.yml b/config/schema/migrate_plus.data_types.schema.yml
new file mode 100644
index 00000000..27c8006f
--- /dev/null
+++ b/config/schema/migrate_plus.data_types.schema.yml
@@ -0,0 +1,40 @@
+# Basic data types for Migrate.
+
+migrate_plugin:
+  type: mapping
+  mapping:
+    plugin:
+      type: string
+      label: 'Plugin'
+
+migrate_destination:
+  type: migrate_plugin
+  label: 'Destination'
+  mapping:
+    overwrite_properties:
+      type: sequence
+      label: 'Properties to overwrite'
+      sequence:
+        type: string
+        label: 'Property'
+
+migrate_source:
+  type: migrate_plugin
+  label: 'Source'
+  mapping:
+    constants:
+      type: ignore
+      label: 'Constants'
+
+migrate_process:
+  type: migrate_plugin
+  label: 'Process'
+
+# Base schema for migrate source plugins that extend
+# \Drupal\migrate\Plugin\migrate\source\SqlBase.
+migrate_source_sql:
+  type: migrate_source
+  mapping:
+    target:
+      type: string
+      label: 'The migration database target'
diff --git a/config/schema/migrate_plus.destination.schema.yml b/config/schema/migrate_plus.destination.schema.yml
new file mode 100644
index 00000000..58ad74e5
--- /dev/null
+++ b/config/schema/migrate_plus.destination.schema.yml
@@ -0,0 +1,18 @@
+# Schema for the migrate destination plugins.
+
+migrate_plus.destination.*:
+  type: migrate_destination
+  label: 'Default destination'
+  mapping:
+    no_stub:
+      type: boolean
+      label: 'Whether stubbing is allowed.'
+      default: false
+
+migrate_plus.destination.config:
+  type: migrate_destination
+  label: 'Config'
+  mapping:
+    config_name:
+      type: string
+      label: 'Configuration name'
diff --git a/config/schema/migrate_plus.process.schema.yml b/config/schema/migrate_plus.process.schema.yml
new file mode 100644
index 00000000..b1f123bc
--- /dev/null
+++ b/config/schema/migrate_plus.process.schema.yml
@@ -0,0 +1,145 @@
+# Schema for the migrate process plugins.
+
+migrate_plus.process.*:
+  type: migrate_process
+  label: 'Default process'
+
+migrate_plus.process.callback:
+  type: migrate_process
+  label: 'Callback process'
+  mapping:
+    callback:
+      type: string
+      label: 'Callback'
+
+migrate_plus.process.concat:
+  type: migrate_process
+  label: 'Concat process'
+  mapping:
+    delimiter:
+      type: string
+      label: 'Delimiter'
+
+migrate_plus.process.dedupe_entity:
+  type: migrate_process
+  label: 'Dedupe Entity process'
+  mapping:
+    entity_type:
+      type: string
+      label: 'Entity type'
+    field:
+      type: string
+      label: 'Field name'
+    postfix:
+      type: string
+      label: 'Postfix'
+    start:
+      type: integer
+      label: 'Start'
+    length:
+      type: integer
+      label: 'Length'
+
+migrate_plus.process.explode:
+  type: migrate_process
+  label: 'Explode process'
+  mapping:
+    delimiter:
+      type: string
+      label: 'Delimiter'
+    limit:
+      type: integer
+      label: 'Limit'
+
+migrate_plus.process.extract:
+  type: migrate_process
+  label: 'Extract process'
+  mapping:
+    default:
+      type: string
+      label: 'Default value'
+
+migrate_plus.process.flatten:
+  type: migrate_process
+  label: 'Flatten process'
+
+migrate_plus.process.get:
+  type: migrate_process
+  label: 'Get process'
+  mapping:
+    source:
+      type: string
+      label: 'Source key'
+
+migrate_plus.process.iterator:
+  type: migrate_process
+  label: 'Iterator process'
+  mapping:
+    process:
+      type: ignore
+      label: 'Process'
+    key:
+      type: string
+      label: 'Key'
+
+migrate_plus.process.machine_name:
+  type: migrate_process
+  label: 'Machine name process'
+
+migrate_plus.process.migration:
+  type: migrate_process
+  label: 'Migration process'
+  mapping:
+    migration:
+      type: sequence
+      label: 'Migration'
+    source:
+      type: sequence
+      label: 'Source keys'
+    source_ids:
+      type: string
+      label: 'Source IDs'
+    stub_id:
+      type: string
+      label: 'Stub ID'
+
+migrate_plus.process.route:
+  type: migrate_process
+  label: 'Route process'
+
+migrate_plus.process.skip_on_empty:
+  type: migrate_process
+  label: 'Skip on Empty'
+
+migrate_plus.process.skip_row_if_not_set:
+  type: migrate_process
+  label: 'Skip Row process if not set'
+  mapping:
+    index:
+      type: integer
+      label: 'Index'
+
+migrate_plus.process.static_map:
+  type: migrate_process
+  label: 'Static Map'
+  mapping:
+    map:
+      type: sequence
+      label: 'Map'
+    default_value:
+      type: string
+      label: 'Default value'
+    bypass:
+      type: boolean
+      label: 'Bypass lookup'
+
+migrate_plus.process.default_value:
+  type: migrate_process
+  label: 'Default value'
+  mapping:
+    strict:
+      type: boolean
+      label: 'Strict type check'
+    default_value:
+      type: string
+      label: 'Default value'
diff --git a/config/schema/migrate_plus.schema.yml b/config/schema/migrate_plus.schema.yml
index 63712fbb..a2c682d4 100644
--- a/config/schema/migrate_plus.schema.yml
+++ b/config/schema/migrate_plus.schema.yml
@@ -1,3 +1,50 @@
+# Schema for the configuration files of the Migrate Plus module.
+
+migrate_plus.migration.*:
+  type: config_entity
+  label: 'Migration'
+  mapping:
+    id:
+      type: string
+      label: 'ID'
+    migration_tags:
+      type: sequence
+      label: 'Migration Tags'
+      sequence:
+        type: string
+        label: 'Tag'
+    label:
+      type: label
+      label: 'Label'
+    source:
+      type: migrate_plus.source.[plugin]
+      label: 'Source'
+    process:
+      type: ignore
+      label: 'Process'
+    destination:
+      type: migrate_plus.destination.[plugin]
+      label: 'Destination'
+    template:
+      type: string
+      label: 'Template'
+    migration_dependencies:
+      type: mapping
+      label: 'Dependencies'
+      mapping:
+        required:
+          type: sequence
+          label: 'Required dependencies'
+          sequence:
+            type: string
+            label: 'Dependency'
+        optional:
+          type: sequence
+          label: 'Optional dependencies'
+          sequence:
+            type: string
+            label: 'Dependency'
+
 migrate_plus.migration_group.*:
   type: config_entity
   label: 'Migration Group'
@@ -20,7 +67,7 @@ migrate_plus.migration_group.*:
     shared_configuration:
       type: ignore
       label: 'Shared migration configuration'
-migrate.migration.*.third_party.migrate_plus:
+migrate_plus.migration.*.third_party.migrate_plus:
   type: mapping
   label: 'Group'
   mapping:
diff --git a/config/schema/migrate_plus.source.schema.yml b/config/schema/migrate_plus.source.schema.yml
new file mode 100644
index 00000000..4117ea41
--- /dev/null
+++ b/config/schema/migrate_plus.source.schema.yml
@@ -0,0 +1,34 @@
+# Schema for the migrate source plugins.
+
+migrate_plus.source.*:
+  type: migrate_source
+  label: 'Default source'
+
+migrate_plus.source.empty:
+  type: migrate_source_sql
+  label: 'Empty source'
+  mapping:
+    provider:
+      type: string
+      label: 'Provider'
+
+migrate_plus.source.embedded_data:
+  type: migrate_source
+  label: 'Embedded data source'
+  mapping:
+    data_rows:
+      type: sequence
+      label: 'Data rows'
+      sequence:
+        type: ignore
+        label: 'Data row'
+    ids:
+      type: sequence
+      label: 'Unique key'
+      sequence:
+        type: mapping
+        label: 'Key column'
+        mapping:
+          type:
+            type: string
+            label: 'Column type'
diff --git a/migrate_example/migrations/migrate.migration.beer_comment.yml b/migrate_example/config/install/migrate_plus.migration.beer_comment.yml
similarity index 100%
rename from migrate_example/migrations/migrate.migration.beer_comment.yml
rename to migrate_example/config/install/migrate_plus.migration.beer_comment.yml
diff --git a/migrate_example/migrations/migrate.migration.beer_node.yml b/migrate_example/config/install/migrate_plus.migration.beer_node.yml
similarity index 100%
rename from migrate_example/migrations/migrate.migration.beer_node.yml
rename to migrate_example/config/install/migrate_plus.migration.beer_node.yml
diff --git a/migrate_example/migrations/migrate.migration.beer_term.yml b/migrate_example/config/install/migrate_plus.migration.beer_term.yml
similarity index 97%
rename from migrate_example/migrations/migrate.migration.beer_term.yml
rename to migrate_example/config/install/migrate_plus.migration.beer_term.yml
index d92a8b38..b0ee91ac 100644
--- a/migrate_example/migrations/migrate.migration.beer_term.yml
+++ b/migrate_example/config/install/migrate_plus.migration.beer_term.yml
@@ -82,3 +82,6 @@ process:
     # with the Drupal term ID of the referenced style (or NULL if style_parent
     # was empty).
     source: style_parent
+
+# We'll learn more about dependencies in beer_node - here, we leave them empty.
+migration_dependencies: {}
diff --git a/migrate_example/migrations/migrate.migration.beer_user.yml b/migrate_example/config/install/migrate_plus.migration.beer_user.yml
similarity index 97%
rename from migrate_example/migrations/migrate.migration.beer_user.yml
rename to migrate_example/config/install/migrate_plus.migration.beer_user.yml
index 7f4a4ab7..fcbb4702 100644
--- a/migrate_example/migrations/migrate.migration.beer_user.yml
+++ b/migrate_example/config/install/migrate_plus.migration.beer_user.yml
@@ -1,5 +1,5 @@
 # Migration configuration for user accounts. We've described most of what goes
-# into migration configuration in migrate.migration.beer_term.yml, so won't
+# into migration configuration in migrate_plus.migration.beer_term.yml, so won't
 # repeat that here.
 id: beer_user
 label: Beer Drinkers of the world
@@ -95,3 +95,5 @@ process:
 #    plugin: migration
 #    source: beers
 #    migration: beer_node
+
+migration_dependencies: {}
diff --git a/migrate_plus.services.yml b/migrate_plus.services.yml
index 3efe3607..da0bc916 100644
--- a/migrate_plus.services.yml
+++ b/migrate_plus.services.yml
@@ -5,3 +5,6 @@ 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
+    arguments: ['@module_handler', '@cache.discovery', '@language_manager']
diff --git a/src/Entity/Migration.php b/src/Entity/Migration.php
new file mode 100644
index 00000000..b1b72f65
--- /dev/null
+++ b/src/Entity/Migration.php
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\migrate_plus\Entity\Migration.
+ */
+
+namespace Drupal\migrate_plus\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+
+/**
+ * Defines the Migration entity.
+ *
+ * The migration entity stores the information about a single migration, like
+ * the source, process and destination plugins.
+ *
+ * @ConfigEntityType(
+ *   id = "migration",
+ *   label = @Translation("Migration"),
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "label" = "label",
+ *     "weight" = "weight"
+ *   }
+ * )
+ */
+class Migration extends ConfigEntityBase implements MigrationInterface {
+
+  /**
+   * The migration ID (machine name).
+   *
+   * @var string
+   */
+  protected $id;
+
+  /**
+   * The human-readable label for the migration.
+   *
+   * @var string
+   */
+  protected $label;
+
+}
diff --git a/src/Entity/MigrationGroup.php b/src/Entity/MigrationGroup.php
index 589f1d7d..35e1ecaf 100644
--- a/src/Entity/MigrationGroup.php
+++ b/src/Entity/MigrationGroup.php
@@ -8,7 +8,6 @@
 namespace Drupal\migrate_plus\Entity;
 
 use Drupal\Core\Config\Entity\ConfigEntityBase;
-use Drupal\migrate\Plugin\MigrationInterface;
 
 /**
  * Defines the Migration Group entity.
diff --git a/src/Entity/MigrationInterface.php b/src/Entity/MigrationInterface.php
new file mode 100644
index 00000000..728c287e
--- /dev/null
+++ b/src/Entity/MigrationInterface.php
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_plus\Entity\MigrationInterface.
+ */
+
+namespace Drupal\migrate_plus\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
+
+/**
+ * Interface for migrations.
+ */
+interface MigrationInterface extends ConfigEntityInterface {
+
+}
diff --git a/src/Plugin/Discovery/ConfigEntityDiscovery.php b/src/Plugin/Discovery/ConfigEntityDiscovery.php
new file mode 100644
index 00000000..3367e168
--- /dev/null
+++ b/src/Plugin/Discovery/ConfigEntityDiscovery.php
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_plus\Plugin\Discovery\ConfigEntityDiscovery.
+ */
+
+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/MigrationConfigEntityPluginManager.php b/src/Plugin/MigrationConfigEntityPluginManager.php
new file mode 100644
index 00000000..61c0cb5c
--- /dev/null
+++ b/src/Plugin/MigrationConfigEntityPluginManager.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_plus\Plugin\MigrationConfigEntityPluginManager.
+ */
+
+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;
+  }
+
+}
-- 
GitLab