Commit 61df34e0 authored by Gábor Hojtsy's avatar Gábor Hojtsy

Issue #2859304 by quietone, heddn, Jo Fitzgerald, maxocub, rivimey,...

Issue #2859304 by quietone, heddn, Jo Fitzgerald, maxocub, rivimey, phenaproxima, jhodgdon: Show field type migrations correctly in Migrate Drupal UI
parent 8d2a2ec2
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
* core = {6,7}, * core = {6,7},
* type_map = { * type_map = {
* "email" = "email" * "email" = "email"
* } * },
* source_module = "email",
* destination_module = "core"
* ) * )
*/ */
class Email extends FieldPluginBase { class Email extends FieldPluginBase {
......
...@@ -10,7 +10,9 @@ ...@@ -10,7 +10,9 @@
* type_map = { * type_map = {
* "entityreference" = "entity_reference", * "entityreference" = "entity_reference",
* }, * },
* core = {7} * core = {7},
* source_module = "entityreference",
* destination_module = "core"
* ) * )
*/ */
class EntityReference extends FieldPluginBase {} class EntityReference extends FieldPluginBase {}
...@@ -12,7 +12,9 @@ ...@@ -12,7 +12,9 @@
* "number_decimal" = "decimal", * "number_decimal" = "decimal",
* "number_float" = "float", * "number_float" = "float",
* }, * },
* core = {7} * core = {7},
* source_module = "number",
* destination_module = "core"
* ) * )
*/ */
class NumberField extends FieldPluginBase {} class NumberField extends FieldPluginBase {}
...@@ -14,7 +14,9 @@ ...@@ -14,7 +14,9 @@
* "datestamp" = "timestamp", * "datestamp" = "timestamp",
* "datetime" = "datetime", * "datetime" = "datetime",
* }, * },
* core = {6,7} * core = {6,7},
* source_module = "date",
* destination_module = "datetime"
* ) * )
*/ */
class DateField extends FieldPluginBase { class DateField extends FieldPluginBase {
......
...@@ -16,7 +16,9 @@ ...@@ -16,7 +16,9 @@
* "datestamp" = "timestamp", * "datestamp" = "timestamp",
* "datetime" = "datetime", * "datetime" = "datetime",
* }, * },
* core = {6} * core = {6},
* source_module = "date",
* destination_module = "datetime"
* ) * )
* *
* @deprecated in Drupal 8.4.x, to be removed before Drupal 9.0.x. Use * @deprecated in Drupal 8.4.x, to be removed before Drupal 9.0.x. Use
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* @MigrateSource( * @MigrateSource(
* id = "d7_field", * id = "d7_field",
* source_module = "field" * source_module = "field_sql_storage"
* ) * )
*/ */
class Field extends DrupalSqlBase { class Field extends DrupalSqlBase {
......
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
/** /**
* @MigrateCckField( * @MigrateCckField(
* id = "filefield", * id = "filefield",
* core = {6} * core = {6},
* source_module = "filefield",
* destination_module = "file"
* ) * )
* *
* @deprecated in Drupal 8.3.x, to be removed before Drupal 9.0.x. Use * @deprecated in Drupal 8.3.x, to be removed before Drupal 9.0.x. Use
......
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
/** /**
* @MigrateCckField( * @MigrateCckField(
* id = "file", * id = "file",
* core = {7} * core = {7},
* source_module = "file",
* destination_module = "file"
* ) * )
* *
* @deprecated in Drupal 8.3.x, to be removed before Drupal 9.0.x. Use * @deprecated in Drupal 8.3.x, to be removed before Drupal 9.0.x. Use
......
...@@ -10,7 +10,9 @@ ...@@ -10,7 +10,9 @@
/** /**
* @MigrateCckField( * @MigrateCckField(
* id = "image", * id = "image",
* core = {7} * core = {7},
* source_module = "image",
* destination_module = "file"
* ) * )
* *
* @deprecated in Drupal 8.3.x, to be removed before Drupal 9.0.x. Use * @deprecated in Drupal 8.3.x, to be removed before Drupal 9.0.x. Use
......
...@@ -9,7 +9,9 @@ ...@@ -9,7 +9,9 @@
/** /**
* @MigrateField( * @MigrateField(
* id = "filefield", * id = "filefield",
* core = {6} * core = {6},
* source_module = "filefield",
* destination_module = "file"
* ) * )
*/ */
class FileField extends FieldPluginBase { class FileField extends FieldPluginBase {
......
<?php
namespace Drupal\file\Plugin\migrate\field\d6;
/**
* @MigrateField(
* id = "imagefield",
* core = {6},
* source_module = "imagefield",
* destination_module = "file"
* )
*/
class ImageField extends FileField {}
...@@ -8,7 +8,9 @@ ...@@ -8,7 +8,9 @@
/** /**
* @MigrateField( * @MigrateField(
* id = "file", * id = "file",
* core = {7} * core = {7},
* source_module = "file",
* destination_module = "file"
* ) * )
*/ */
class FileField extends D6FileField { class FileField extends D6FileField {
......
...@@ -8,7 +8,9 @@ ...@@ -8,7 +8,9 @@
/** /**
* @MigrateField( * @MigrateField(
* id = "image", * id = "image",
* core = {7} * core = {7},
* source_module = "image",
* destination_module = "file"
* ) * )
*/ */
class ImageField extends FieldPluginBase { class ImageField extends FieldPluginBase {
......
...@@ -13,7 +13,9 @@ ...@@ -13,7 +13,9 @@
* core = {6}, * core = {6},
* type_map = { * type_map = {
* "link_field" = "link" * "link_field" = "link"
* } * },
* source_module = "link",
* destination_module = "link"
* ) * )
* *
* @deprecated in Drupal 8.3.x and will be removed in Drupal 9.0.x. Use * @deprecated in Drupal 8.3.x and will be removed in Drupal 9.0.x. Use
......
...@@ -13,7 +13,9 @@ ...@@ -13,7 +13,9 @@
* core = {7}, * core = {7},
* type_map = { * type_map = {
* "link_field" = "link" * "link_field" = "link"
* } * },
* source_module = "link",
* destination_module = "link"
* ) * )
* *
* This plugin provides the exact same functionality as the Drupal 6 "link" * This plugin provides the exact same functionality as the Drupal 6 "link"
......
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
* core = {6}, * core = {6},
* type_map = { * type_map = {
* "link_field" = "link" * "link_field" = "link"
* } * },
* source_module = "link",
* destination_module = "link"
* ) * )
*/ */
class LinkField extends FieldPluginBase { class LinkField extends FieldPluginBase {
......
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
* core = {7}, * core = {7},
* type_map = { * type_map = {
* "link_field" = "link" * "link_field" = "link"
* } * },
* source_module = "link",
* destination_module = "link"
* ) * )
* *
* This plugin provides the exact same functionality as the Drupal 6 "link" * This plugin provides the exact same functionality as the Drupal 6 "link"
......
<?php
namespace Drupal\migrate\Plugin\Exception;
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
/**
* Defines a class for bad plugin definition exceptions.
*/
class BadPluginDefinitionException extends InvalidPluginDefinitionException {
/**
* Constructs a BadPluginDefinitionException.
*
* For the remaining parameters see \Exception.
*
* @param string $plugin_id
* The plugin ID of the mapper.
* @param string $property
* The name of the property that is missing from the plugin.
*
* @see \Exception
*/
public function __construct($plugin_id, $property, $code = 0, \Exception $previous = NULL) {
$message = sprintf('The %s plugin should define the %s property.', $plugin_id, $property);
parent::__construct($plugin_id, $message, $code, $previous);
}
}
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
use Drupal\Component\Render\FormattableMarkup; use Drupal\Component\Render\FormattableMarkup;
use Drupal\KernelTests\FileSystemModuleDiscoveryDataProviderTrait; use Drupal\KernelTests\FileSystemModuleDiscoveryDataProviderTrait;
use Drupal\migrate\Plugin\Exception\BadPluginDefinitionException;
use Drupal\migrate_drupal\Plugin\MigrateFieldPluginManager;
use Drupal\Tests\migrate_drupal\Kernel\MigrateDrupalTestBase; use Drupal\Tests\migrate_drupal\Kernel\MigrateDrupalTestBase;
/** /**
...@@ -33,7 +35,7 @@ public function testProvidersExist() { ...@@ -33,7 +35,7 @@ public function testProvidersExist() {
/** @var \Drupal\migrate\Plugin\MigrationPluginManager $plugin_manager */ /** @var \Drupal\migrate\Plugin\MigrationPluginManager $plugin_manager */
$plugin_manager = $this->container->get('plugin.manager.migration'); $plugin_manager = $this->container->get('plugin.manager.migration');
// Get all the migrations // Get all the migrations.
$migrations = $plugin_manager->createInstances(array_keys($plugin_manager->getDefinitions())); $migrations = $plugin_manager->createInstances(array_keys($plugin_manager->getDefinitions()));
// Ensure the test module was enabled. // Ensure the test module was enabled.
$this->assertTrue(array_key_exists('migration_provider_test', $migrations)); $this->assertTrue(array_key_exists('migration_provider_test', $migrations));
...@@ -55,10 +57,190 @@ public function testProvidersExist() { ...@@ -55,10 +57,190 @@ public function testProvidersExist() {
$this->assertTrue($source_module, new FormattableMarkup('Source module found for @migration_id.', ['@migration_id' => $migration_id])); $this->assertTrue($source_module, new FormattableMarkup('Source module found for @migration_id.', ['@migration_id' => $migration_id]));
$this->assertTrue($destination_module, new FormattableMarkup('Destination module found for @migration_id.', ['@migration_id' => $migration_id])); $this->assertTrue($destination_module, new FormattableMarkup('Destination module found for @migration_id.', ['@migration_id' => $migration_id]));
} }
// Destination module can't be migrate or migrate_drupal or migrate_drupal_ui // Destination module can't be migrate or migrate_drupal or
// migrate_drupal_ui.
$invalid_destinations = ['migrate', 'migrate_drupal', 'migrate_drupal_ui']; $invalid_destinations = ['migrate', 'migrate_drupal', 'migrate_drupal_ui'];
$this->assertNotContains($destination_module, $invalid_destinations, new FormattableMarkup('Invalid destination for @migration_id.', ['@migration_id' => $migration_id])); $this->assertNotContains($destination_module, $invalid_destinations, new FormattableMarkup('Invalid destination for @migration_id.', ['@migration_id' => $migration_id]));
} }
} }
/**
* Tests that modules exist for all field plugins.
*/
public function testFieldProvidersExist() {
$expected_mappings = [
'userreference' => [
'source_module' => 'user_reference',
'destination_module' => 'core',
],
'nodereference' => [
'source_module' => 'node_reference',
'destination_module' => 'core',
],
'optionwidgets' => [
'source_module' => 'optionwidgets',
'destination_module' => 'options',
],
'list' => [
'source_module' => 'list',
'destination_module' => 'options',
],
'options' => [
'source_module' => 'options',
'destination_module' => 'options',
],
'filefield' => [
'source_module' => 'filefield',
'destination_module' => 'file',
],
'imagefield' => [
'source_module' => 'imagefield',
'destination_module' => 'file',
],
'file' => [
'source_module' => 'file',
'destination_module' => 'file',
],
'image' => [
'source_module' => 'image',
'destination_module' => 'file',
],
'phone' => [
'source_module' => 'phone',
'destination_module' => 'telephone',
],
'link' => [
'source_module' => 'link',
'destination_module' => 'link',
],
'link_field' => [
'source_module' => 'link',
'destination_module' => 'link',
],
'd6_text' => [
'source_module' => 'text',
'destination_module' => 'text',
],
'd7_text' => [
'source_module' => 'text',
'destination_module' => 'text',
],
'taxonomy_term_reference' => [
'source_module' => 'taxonomy',
'destination_module' => 'core',
],
'date' => [
'source_module' => 'date',
'destination_module' => 'datetime',
],
'datetime' => [
'source_module' => 'date',
'destination_module' => 'datetime',
],
'email' => [
'source_module' => 'email',
'destination_module' => 'core',
],
'number_default' => [
'source_module' => 'number',
'destination_module' => 'core',
],
'entityreference' => [
'source_module' => 'entityreference',
'destination_module' => 'core',
],
];
// Install all available modules.
$module_handler = $this->container->get('module_handler');
$modules = $this->coreModuleListDataProvider();
$modules_enabled = $module_handler->getModuleList();
$modules_to_enable = array_keys(array_diff_key($modules, $modules_enabled));
$this->enableModules($modules_to_enable);
/** @var \Drupal\migrate_drupal\Plugin\MigrateFieldPluginManager $plugin_manager */
$plugin_manager = $this->container->get('plugin.manager.migrate.field');
$definitions = $plugin_manager->getDefinitions();
foreach ($definitions as $key => $definition) {
$this->assertArrayHasKey($key, $expected_mappings);
$this->assertEquals($expected_mappings[$key]['source_module'], $definition['source_module']);
$this->assertEquals($expected_mappings[$key]['destination_module'], $definition['destination_module']);
}
}
/**
* Test a missing required definition.
*
* @param array $definitions
* A field plugin definition.
* @param string $missing_property
* The name of the property missing from the definition.
*
* @dataProvider fieldPluginDefinitionsProvider
*/
public function testFieldProviderMissingRequiredProperty(array $definitions, $missing_property) {
$discovery = $this->getMockBuilder(MigrateFieldPluginManager::class)
->disableOriginalConstructor()
->setMethods(['getDefinitions'])
->getMock();
$discovery->method('getDefinitions')
->willReturn($definitions);
$plugin_manager = $this->getMockBuilder(MigrateFieldPluginManager::class)
->disableOriginalConstructor()
->setMethods(['getDiscovery'])
->getMock();
$plugin_manager->method('getDiscovery')
->willReturn($discovery);
$this->setExpectedException(BadPluginDefinitionException::class, "The missing_{$missing_property} plugin should define the $missing_property property.");
$plugin_manager->getDefinitions();
}
/**
* Data provider for field plugin definitions.
*
* @return array
* Array of plugin definitions.
*/
public function fieldPluginDefinitionsProvider() {
return [
'missing_core_scenario' => [
'definitions' => [
'missing_core' => [
'source_module' => 'migrate',
'destination_module' => 'migrate',
'id' => 'missing_core',
'class' => 'foo',
'provider' => 'foo',
],
],
'missing_property' => 'core',
],
'missing_source_scenario' => [
'definitions' => [
'missing_source_module' => [
'core' => [6, 7],
'destination_module' => 'migrate',
'id' => 'missing_source_module',
'class' => 'foo',
'provider' => 'foo',
],
],
'missing_property' => 'source_module',
],
'missing_destination_scenario' => [
'definitions' => [
'missing_destination_module' => [
'core' => [6, 7],
'source_module' => 'migrate',
'id' => 'missing_destination_module',
'class' => 'foo',
'provider' => 'foo',
],
],
'missing_property' => 'destination_module',
],
];
}
} }
...@@ -49,6 +49,26 @@ public function __construct($values) { ...@@ -49,6 +49,26 @@ public function __construct($values) {
* *
* @var int[] * @var int[]
*/ */
public $core = []; public $core;
/**
* Identifies the system providing the data the field plugin will read.
*
* The source_module is expected to be the name of a Drupal module that must
* must be installed in the source database.
*
* @var string
*/
public $source_module;
/**
* Identifies the system handling the data the destination plugin will write.
*
* The destination_module is expected to be the name of a Drupal module on the
* destination site that must be installed.
*
* @var string
*/
public $destination_module;
} }
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
namespace Drupal\migrate_drupal\Plugin; namespace Drupal\migrate_drupal\Plugin;
use Drupal\Component\Plugin\Exception\PluginNotFoundException; use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\migrate\Plugin\Exception\BadPluginDefinitionException;
use Drupal\migrate\Plugin\MigratePluginManager; use Drupal\migrate\Plugin\MigratePluginManager;
use Drupal\migrate\Plugin\MigrationInterface; use Drupal\migrate\Plugin\MigrationInterface;
...@@ -53,4 +54,17 @@ public function getPluginIdFromFieldType($field_type, array $configuration = [], ...@@ -53,4 +54,17 @@ public function getPluginIdFromFieldType($field_type, array $configuration = [],
throw new PluginNotFoundException($field_type); throw new PluginNotFoundException($field_type);
} }
/**
* {@inheritdoc}
*/
public function processDefinition(&$definition, $plugin_id) {
parent::processDefinition($definition, $plugin_id);
foreach (['core', 'source_module', 'destination_module'] as $required_property) {
if (empty($definition[$required_property])) {
throw new BadPluginDefinitionException($plugin_id, $required_property);
}
}
}
} }
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
* type_map = { * type_map = {
* "nodereference" = "entity_reference", * "nodereference" = "entity_reference",
* }, * },
* source_module = "node_reference",
* destination_module = "core",
* ) * )
*/ */
class NodeReference extends FieldPluginBase { class NodeReference extends FieldPluginBase {
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
* type_map = { * type_map = {
* "userreference" = "entity_reference", * "userreference" = "entity_reference",
* }, * },
* source_module = "user_reference",
* destination_module = "core",
* ) * )
*/ */
class UserReference extends FieldPluginBase { class UserReference extends FieldPluginBase {
......
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
* core = {6}, * core = {6},
* type_map = { * type_map = {
* "file" = "file" * "file" = "file"
* } * },
* source_module = "foo",
* destination_module = "bar"
* ) * )
*/ */
class D6FileField extends CckFieldPluginBase { class D6FileField extends CckFieldPluginBase {
......
...@@ -7,7 +7,9 @@ ...@@ -7,7 +7,9 @@
/** /**
* @MigrateCckField( * @MigrateCckField(
* id = "d6_no_core_version_specified" * id = "d6_no_core_version_specified",
* source_module = "foo",
* destination_module = "bar",
* ) * )
*/ */
class D6NoCoreVersionSpecified extends CckFieldPluginBase { class D6NoCoreVersionSpecified extends CckFieldPluginBase {
......
...@@ -10,7 +10,9 @@ ...@@ -10,7 +10,9 @@
* core = {6}, * core = {6},
* type_map = { * type_map = {
* "file" = "file" * "file" = "file"
* } * },
* source_module = "foo",
* destination_module = "bar"
* ) * )
*/ */
class D6FileField extends FieldPluginBase {} class D6FileField extends FieldPluginBase {}
...@@ -6,10 +6,9 @@ ...@@ -6,10 +6,9 @@
/** /**
* @MigrateField( * @MigrateField(
* id = "d6_no_core_version_specified" * id = "d6_no_core_version_specified",
* source_module = "foo",
* destination_module = "bar",
* ) * )
*/ */
class D6NoCoreVersionSpecified extends FieldPluginBase { class D6NoCoreVersionSpecified extends FieldPluginBase {}
}
...@@ -3,12 +3,14 @@ ...@@ -3,12 +3,14 @@
namespace Drupal\migrate_drupal_ui\Form; namespace Drupal\migrate_drupal_ui\Form;