From 828b769e4e3fa9326f9c0a3d786e8ce159d2d28b Mon Sep 17 00:00:00 2001
From: webchick <drupal@webchick.net>
Date: Mon, 2 Nov 2015 10:03:04 -0800
Subject: [PATCH] Issue #2324649 by phenaproxima, svendecabooter, benjy,
 Berdir: Migrate text fields correctly based on their text_processing setting

---
 .../field/migration_templates/d6_field.yml    | 11 +--
 .../migrate/process/d6/FieldIdGenerator.php   | 30 --------
 .../Plugin/migrate/process/d6/FieldType.php   | 76 +++++++++++++++++++
 .../Migrate/d6/MigrateFieldInstanceTest.php   |  5 +-
 .../src/Tests/Migrate/d6/MigrateFieldTest.php |  6 +-
 .../src/Plugin/migrate/cckfield/FileField.php | 12 ++-
 .../src/Plugin/migrate/cckfield/LinkField.php |  4 +-
 .../migrate_drupal.services.yml               |  7 +-
 .../src/Annotation/MigrateCckField.php        | 40 ++++++++++
 .../src/Plugin/MigrateCckFieldInterface.php   | 12 +++
 .../migrate/cckfield/CckFieldPluginBase.php   | 15 ++++
 .../cckfield/TaxonomyTermReference.php        |  4 +-
 .../src/Plugin/migrate/cckfield/TextField.php | 34 ++++++++-
 .../tests/src/Unit/Migrate/TextFieldTest.php  | 46 +++++++++++
 14 files changed, 255 insertions(+), 47 deletions(-)
 delete mode 100644 core/modules/field/src/Plugin/migrate/process/d6/FieldIdGenerator.php
 create mode 100644 core/modules/field/src/Plugin/migrate/process/d6/FieldType.php
 create mode 100644 core/modules/migrate_drupal/src/Annotation/MigrateCckField.php

diff --git a/core/modules/field/migration_templates/d6_field.yml b/core/modules/field/migration_templates/d6_field.yml
index dbe35055474c..ec29aadf0957 100644
--- a/core/modules/field/migration_templates/d6_field.yml
+++ b/core/modules/field/migration_templates/d6_field.yml
@@ -17,7 +17,7 @@ process:
   field_name: field_name
   type:
     -
-      plugin: static_map
+      plugin: field_type
       source:
         - type
         - widget_type
@@ -37,12 +37,6 @@ process:
           optionwidgets_select: list_float
           optionwidgets_buttons: list_float
           optionwidgets_onoff: boolean
-        text:
-          optionwidgets_select: list_string
-          optionwidgets_buttons: list_string
-          optionwidgets_onoff: boolean
-          text_textfield: text
-          text_textarea: text_long
         email:
           email_textfield: email
         filefield:
@@ -118,6 +112,9 @@ process:
           phone_textfield: telephone
         int_phone:
           phone_textfield: telephone
+    -
+      plugin: skip_on_empty
+      method: row
   cardinality:
     plugin: static_map
     bypass: true
diff --git a/core/modules/field/src/Plugin/migrate/process/d6/FieldIdGenerator.php b/core/modules/field/src/Plugin/migrate/process/d6/FieldIdGenerator.php
deleted file mode 100644
index 93eca113d860..000000000000
--- a/core/modules/field/src/Plugin/migrate/process/d6/FieldIdGenerator.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\field\Plugin\migrate\process\d6\FieldIdGenerator.
- */
-
-namespace Drupal\field\Plugin\migrate\process\d6;
-
-use Drupal\migrate\MigrateExecutableInterface;
-use Drupal\migrate\ProcessPluginBase;
-use Drupal\migrate\Row;
-
-/**
- * Generate the file name for field config entities.
- *
- * @MigrateProcessPlugin(
- *   id = "field_id_generator"
- * )
- */
-class FieldIdGenerator extends ProcessPluginBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
-    return $value[0] . "." . $value[1];
-  }
-
-}
diff --git a/core/modules/field/src/Plugin/migrate/process/d6/FieldType.php b/core/modules/field/src/Plugin/migrate/process/d6/FieldType.php
new file mode 100644
index 000000000000..2c36275baaf1
--- /dev/null
+++ b/core/modules/field/src/Plugin/migrate/process/d6/FieldType.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\field\Plugin\migrate\process\d6\FieldType.
+ */
+
+namespace Drupal\field\Plugin\migrate\process\d6;
+
+use Drupal\Component\Plugin\Exception\PluginNotFoundException;
+use Drupal\Component\Plugin\PluginManagerInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\migrate\MigrateExecutableInterface;
+use Drupal\migrate\Plugin\migrate\process\StaticMap;
+use Drupal\migrate\Row;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * @MigrateProcessPlugin(
+ *   id = "field_type"
+ * )
+ */
+class FieldType extends StaticMap implements ContainerFactoryPluginInterface {
+
+  /**
+   * The cckfield plugin manager.
+   *
+   * @var \Drupal\Component\Plugin\PluginManagerInterface
+   */
+  protected $cckPluginManager;
+
+  /**
+   * Constructs a FieldType plugin.
+   *
+   * @param array $configuration
+   *   The plugin configuration.
+   * @param string $plugin_id
+   *   The plugin ID.
+   * @param mixed $plugin_definition
+   *   The plugin definition.
+   * @param \Drupal\Component\Plugin\PluginManagerInterface $cck_plugin_manager
+   *   The cckfield plugin manager.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, PluginManagerInterface $cck_plugin_manager) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->cckPluginManager = $cck_plugin_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('plugin.manager.migrate.cckfield')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
+    list ($field_type, $widget_type) = $value;
+
+    try {
+      return $this->cckPluginManager->createInstance($field_type)
+        ->getFieldType($row);
+    }
+    catch (PluginNotFoundException $e) {
+      return parent::transform($value, $migrate_executable, $row, $destination_property);
+    }
+  }
+
+}
diff --git a/core/modules/field/src/Tests/Migrate/d6/MigrateFieldInstanceTest.php b/core/modules/field/src/Tests/Migrate/d6/MigrateFieldInstanceTest.php
index c3c0cb62c248..8f0e96bacc1e 100644
--- a/core/modules/field/src/Tests/Migrate/d6/MigrateFieldInstanceTest.php
+++ b/core/modules/field/src/Tests/Migrate/d6/MigrateFieldInstanceTest.php
@@ -27,10 +27,11 @@ public function testFieldInstanceMigration() {
 
     $entity = Node::create(['type' => 'story']);
     // Test a text field.
+    /** @var \Drupal\field\FieldConfigInterface $field */
     $field = FieldConfig::load('node.story.field_test');
     $this->assertIdentical('Text Field', $field->label());
-    $expected = array('max_length' => 255);
-    $this->assertIdentical($expected, $field->getSettings());
+    // field_test is a text_long field, which have no settings.
+    $this->assertIdentical([], $field->getSettings());
     $this->assertIdentical('text for default value', $entity->field_test->value);
 
     // Test a number field.
diff --git a/core/modules/field/src/Tests/Migrate/d6/MigrateFieldTest.php b/core/modules/field/src/Tests/Migrate/d6/MigrateFieldTest.php
index 4eb9426c5de1..1eb5ad6599c2 100644
--- a/core/modules/field/src/Tests/Migrate/d6/MigrateFieldTest.php
+++ b/core/modules/field/src/Tests/Migrate/d6/MigrateFieldTest.php
@@ -33,9 +33,9 @@ public function testFields() {
     // Text field.
     /** @var \Drupal\field\Entity\FieldStorageConfig $field_storage */
     $field_storage = FieldStorageConfig::load('node.field_test');
-    $expected = array('max_length' => 255);
-    $this->assertIdentical("text", $field_storage->getType(),  t('Field type is @fieldtype. It should be text.', array('@fieldtype' => $field_storage->getType())));
-    $this->assertIdentical($expected, $field_storage->getSettings(), "Field type text settings are correct");
+    $this->assertIdentical('text_long', $field_storage->getType());
+    // text_long fields do not have settings.
+    $this->assertIdentical([], $field_storage->getSettings());
 
     // Integer field.
     $field_storage = FieldStorageConfig::load('node.field_test_two');
diff --git a/core/modules/file/src/Plugin/migrate/cckfield/FileField.php b/core/modules/file/src/Plugin/migrate/cckfield/FileField.php
index d275dcff5cd1..022f01e98ba3 100644
--- a/core/modules/file/src/Plugin/migrate/cckfield/FileField.php
+++ b/core/modules/file/src/Plugin/migrate/cckfield/FileField.php
@@ -8,10 +8,13 @@
 namespace Drupal\file\Plugin\migrate\cckfield;
 
 use Drupal\migrate\Entity\MigrationInterface;
+use Drupal\migrate\Row;
 use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
 
 /**
- * @PluginID("filefield")
+ * @MigrateCckField(
+ *   id = "filefield"
+ * )
  */
 class FileField extends CckFieldPluginBase {
 
@@ -49,4 +52,11 @@ public function processCckFieldValues(MigrationInterface $migration, $field_name
     $migration->mergeProcessOfProperty($field_name, $process);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getFieldType(Row $row) {
+    return $row->getSourceProperty('widget_type') == 'imagefield_widget' ? 'image' : 'file';
+  }
+
 }
diff --git a/core/modules/link/src/Plugin/migrate/cckfield/LinkField.php b/core/modules/link/src/Plugin/migrate/cckfield/LinkField.php
index 394dc43111d8..327cbdaadb00 100644
--- a/core/modules/link/src/Plugin/migrate/cckfield/LinkField.php
+++ b/core/modules/link/src/Plugin/migrate/cckfield/LinkField.php
@@ -11,7 +11,9 @@
 use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
 
 /**
- * @PluginID("link")
+ * @MigrateCckField(
+ *   id = "link"
+ * )
  */
 class LinkField extends CckFieldPluginBase {
 
diff --git a/core/modules/migrate_drupal/migrate_drupal.services.yml b/core/modules/migrate_drupal/migrate_drupal.services.yml
index 00730b4ce1ec..2807b5f4b74c 100644
--- a/core/modules/migrate_drupal/migrate_drupal.services.yml
+++ b/core/modules/migrate_drupal/migrate_drupal.services.yml
@@ -1,4 +1,9 @@
 services:
   plugin.manager.migrate.cckfield:
     class: Drupal\migrate\Plugin\MigratePluginManager
-    arguments: [cckfield, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments:
+      - cckfield
+      - '@container.namespaces'
+      - '@cache.discovery'
+      - '@module_handler'
+      - '\Drupal\migrate_drupal\Annotation\MigrateCckField'
diff --git a/core/modules/migrate_drupal/src/Annotation/MigrateCckField.php b/core/modules/migrate_drupal/src/Annotation/MigrateCckField.php
new file mode 100644
index 000000000000..b7edf0ef33bb
--- /dev/null
+++ b/core/modules/migrate_drupal/src/Annotation/MigrateCckField.php
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal\Annotation\MigrateCckField.
+ */
+
+namespace Drupal\migrate_drupal\Annotation;
+
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Defines a cckfield plugin annotation object.
+ *
+ * cckfield plugins are variously responsible for handling the migration of
+ * CCK fields from Drupal 6 to Drupal 8. They are allowed to alter CCK-related
+ * migrations when migrations are being generated, and can compute destination
+ * field types for individual fields during the actual migration process.
+ *
+ * Plugin Namespace: Plugin\migrate\cckfield
+ *
+ * @Annotation
+ */
+class MigrateCckField extends Plugin {
+
+  /**
+   * The plugin ID.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * Map of D6 and D7 field types to D8 field type plugin IDs.
+   *
+   * @var string[]
+   */
+  public $type_map = [];
+
+}
diff --git a/core/modules/migrate_drupal/src/Plugin/MigrateCckFieldInterface.php b/core/modules/migrate_drupal/src/Plugin/MigrateCckFieldInterface.php
index 7f8bb5aec3d1..dbe499d9064a 100644
--- a/core/modules/migrate_drupal/src/Plugin/MigrateCckFieldInterface.php
+++ b/core/modules/migrate_drupal/src/Plugin/MigrateCckFieldInterface.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Plugin\PluginInspectionInterface;
 use Drupal\migrate\Entity\MigrationInterface;
+use Drupal\migrate\Row;
 
 /**
  * Provides an interface for all CCK field type plugins.
@@ -77,4 +78,15 @@ public function getFieldWidgetMap();
    */
   public function processCckFieldValues(MigrationInterface $migration, $field_name, $data);
 
+  /**
+   * Computes the destination type of a migrated field.
+   *
+   * @param \Drupal\migrate\Row $row
+   *   The field being migrated.
+   *
+   * @return string
+   *   The destination field type.
+   */
+  public function getFieldType(Row $row);
+
 }
diff --git a/core/modules/migrate_drupal/src/Plugin/migrate/cckfield/CckFieldPluginBase.php b/core/modules/migrate_drupal/src/Plugin/migrate/cckfield/CckFieldPluginBase.php
index 783a36fb8bdf..38b96df20765 100644
--- a/core/modules/migrate_drupal/src/Plugin/migrate/cckfield/CckFieldPluginBase.php
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/cckfield/CckFieldPluginBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Plugin\PluginBase;
 use Drupal\migrate\Entity\MigrationInterface;
+use Drupal\migrate\Row;
 use Drupal\migrate_drupal\Plugin\MigrateCckFieldInterface;
 
 /**
@@ -70,4 +71,18 @@ public function processFieldFormatter(MigrationInterface $migration) {
     $migration->mergeProcessOfProperty('options/type', $process);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getFieldType(Row $row) {
+    $field_type = $row->getSourceProperty('type');
+
+    if (isset($this->pluginDefinition['type_map'][$field_type])) {
+      return $this->pluginDefinition['type_map'][$field_type];
+    }
+    else {
+      return $field_type;
+    }
+  }
+
 }
diff --git a/core/modules/taxonomy/src/Plugin/migrate/cckfield/TaxonomyTermReference.php b/core/modules/taxonomy/src/Plugin/migrate/cckfield/TaxonomyTermReference.php
index 2ce428e05c6e..d6de1eca0123 100644
--- a/core/modules/taxonomy/src/Plugin/migrate/cckfield/TaxonomyTermReference.php
+++ b/core/modules/taxonomy/src/Plugin/migrate/cckfield/TaxonomyTermReference.php
@@ -11,7 +11,9 @@
 use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
 
 /**
- * @PluginID("taxonomy_term_reference")
+ * @MigrateCckField(
+ *   id = "taxonomy_term_reference"
+ * )
  */
 class TaxonomyTermReference extends CckFieldPluginBase {
 
diff --git a/core/modules/text/src/Plugin/migrate/cckfield/TextField.php b/core/modules/text/src/Plugin/migrate/cckfield/TextField.php
index 71e811224d9c..a386b5ffe566 100644
--- a/core/modules/text/src/Plugin/migrate/cckfield/TextField.php
+++ b/core/modules/text/src/Plugin/migrate/cckfield/TextField.php
@@ -8,10 +8,13 @@
 namespace Drupal\text\Plugin\migrate\cckfield;
 
 use Drupal\migrate\Entity\MigrationInterface;
+use Drupal\migrate\Row;
 use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
 
 /**
- * @PluginID("text")
+ * @MigrateCckField(
+ *   id = "text"
+ * )
  */
 class TextField extends CckFieldPluginBase {
 
@@ -91,4 +94,33 @@ public function processCckFieldValues(MigrationInterface $migration, $field_name
     $migration->setProcessOfProperty($field_name, $process);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getFieldType(Row $row) {
+    $widget_type = $row->getSourceProperty('widget_type');
+
+    if ($widget_type == 'text_textfield') {
+      $settings = $row->getSourceProperty('global_settings');
+      $field_type = $settings['text_processing'] ? 'text' : 'string';
+      if (empty($settings['max_length']) || $settings['max_length'] > 255) {
+        $field_type .= '_long';
+      }
+      return $field_type;
+    }
+    else {
+      switch ($widget_type) {
+        case 'optionwidgets_buttons':
+        case 'optionwidgets_select':
+          return 'list_string';
+        case 'optionwidgets_onoff':
+          return 'boolean';
+        case 'text_textarea':
+          return 'text_long';
+        default:
+          break;
+      }
+    }
+  }
+
 }
diff --git a/core/modules/text/tests/src/Unit/Migrate/TextFieldTest.php b/core/modules/text/tests/src/Unit/Migrate/TextFieldTest.php
index 89b8c2619da7..117919dada84 100644
--- a/core/modules/text/tests/src/Unit/Migrate/TextFieldTest.php
+++ b/core/modules/text/tests/src/Unit/Migrate/TextFieldTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\Tests\text\Unit\Migrate;
 
 use Drupal\migrate\Entity\MigrationInterface;
+use Drupal\migrate\Row;
 use Drupal\Tests\UnitTestCase;
 use Drupal\text\Plugin\migrate\cckfield\TextField;
 use Prophecy\Argument;
@@ -121,4 +122,49 @@ public function testProcessBooleanTextExplicitValues() {
     $this->assertSame($expected, $this->migration->getProcess()['process']);
   }
 
+  /**
+   * Data provider for testGetFieldType().
+   */
+  public function getFieldTypeProvider() {
+    return array(
+      array('string_long', 'text_textfield', array(
+        'text_processing' => FALSE,
+      )),
+      array('string', 'text_textfield', array(
+        'text_processing' => FALSE,
+        'max_length' => 128,
+      )),
+      array('string_long', 'text_textfield', array(
+        'text_processing' => FALSE,
+        'max_length' => 4096,
+      )),
+      array('text_long', 'text_textfield', array(
+        'text_processing' => TRUE,
+      )),
+      array('text', 'text_textfield', array(
+        'text_processing' => TRUE,
+        'max_length' => 128,
+      )),
+      array('text_long', 'text_textfield', array(
+        'text_processing' => TRUE,
+        'max_length' => 4096,
+      )),
+      array('list_string', 'optionwidgets_buttons'),
+      array('list_string', 'optionwidgets_select'),
+      array('boolean', 'optionwidgets_onoff'),
+      array('text_long', 'text_textarea'),
+      array(NULL, 'undefined'),
+    );
+  }
+
+  /**
+   * @covers ::getFieldType
+   * @dataProvider getFieldTypeProvider
+   */
+  public function testGetFieldType($expected_type, $widget_type, array $settings = array()) {
+    $row = new Row(array('widget_type' => $widget_type), array('widget_type' => array()));
+    $row->setSourceProperty('global_settings', $settings);
+    $this->assertSame($expected_type, $this->plugin->getFieldType($row));
+  }
+
 }
-- 
GitLab