From 4b73e57d4bdac31fa97b6fbd0aaff86eb19706ff Mon Sep 17 00:00:00 2001
From: Mike Ryan <mike.ryan@acquia.com>
Date: Mon, 24 Aug 2015 09:03:18 -0500
Subject: [PATCH] Issue #2556541 by mikeryan: Basic migration support (terms,
 users, nodes)

---
 migration_templates/d5_filter_format.yml      |  45 ++++++++
 migration_templates/d5_node.yml               |  57 ++++++++++
 migration_templates/d5_node_revision.yml      |  41 +++++++
 .../d5_node_setting_promote.yml               |  19 ++++
 .../d5_node_setting_status.yml                |  19 ++++
 .../d5_node_setting_sticky.yml                |  19 ++++
 migration_templates/d5_node_settings.yml      |  13 +++
 migration_templates/d5_node_type.yml          |  24 ++++
 migration_templates/d5_taxonomy_term.yml      |  30 +++++
 .../d5_taxonomy_vocabulary.yml                |  24 ++++
 migration_templates/d5_term_node.yml          |  22 ++++
 migration_templates/d5_user.yml               |  38 +++++++
 .../d5_user_contact_settings.yml              |  23 ++++
 migration_templates/d5_user_mail.yml          |  39 +++++++
 migration_templates/d5_user_role.yml          |  46 ++++++++
 migration_templates/d5_user_settings.yml      |  28 +++++
 migration_templates/d5_vocabulary_field.yml   |  26 +++++
 .../d5_vocabulary_field_instance.yml          |  27 +++++
 src/Plugin/migrate/builder/d5/Node.php        |  75 ++++++++++++
 src/Plugin/migrate/source/d5/Field.php        |  93 +++++++++++++++
 .../migrate/source/d5/FieldInstance.php       |  86 ++++++++++++++
 .../source/d5/FieldInstancePerFormDisplay.php | 101 +++++++++++++++++
 .../source/d5/FieldInstancePerViewMode.php    | 107 ++++++++++++++++++
 src/Plugin/migrate/source/d5/Node.php         |  70 ++++++++++++
 src/Plugin/migrate/source/d5/NodeRevision.php |  45 ++++++++
 src/Plugin/migrate/source/d5/TermNode.php     |  76 +++++++++++++
 src/Plugin/migrate/source/d5/User.php         |  31 +++++
 27 files changed, 1224 insertions(+)
 create mode 100644 migration_templates/d5_filter_format.yml
 create mode 100644 migration_templates/d5_node.yml
 create mode 100644 migration_templates/d5_node_revision.yml
 create mode 100644 migration_templates/d5_node_setting_promote.yml
 create mode 100644 migration_templates/d5_node_setting_status.yml
 create mode 100644 migration_templates/d5_node_setting_sticky.yml
 create mode 100644 migration_templates/d5_node_settings.yml
 create mode 100644 migration_templates/d5_node_type.yml
 create mode 100644 migration_templates/d5_taxonomy_term.yml
 create mode 100644 migration_templates/d5_taxonomy_vocabulary.yml
 create mode 100644 migration_templates/d5_term_node.yml
 create mode 100644 migration_templates/d5_user.yml
 create mode 100644 migration_templates/d5_user_contact_settings.yml
 create mode 100644 migration_templates/d5_user_mail.yml
 create mode 100644 migration_templates/d5_user_role.yml
 create mode 100644 migration_templates/d5_user_settings.yml
 create mode 100644 migration_templates/d5_vocabulary_field.yml
 create mode 100644 migration_templates/d5_vocabulary_field_instance.yml
 create mode 100644 src/Plugin/migrate/builder/d5/Node.php
 create mode 100644 src/Plugin/migrate/source/d5/Field.php
 create mode 100644 src/Plugin/migrate/source/d5/FieldInstance.php
 create mode 100644 src/Plugin/migrate/source/d5/FieldInstancePerFormDisplay.php
 create mode 100644 src/Plugin/migrate/source/d5/FieldInstancePerViewMode.php
 create mode 100644 src/Plugin/migrate/source/d5/Node.php
 create mode 100644 src/Plugin/migrate/source/d5/NodeRevision.php
 create mode 100644 src/Plugin/migrate/source/d5/TermNode.php
 create mode 100644 src/Plugin/migrate/source/d5/User.php

diff --git a/migration_templates/d5_filter_format.yml b/migration_templates/d5_filter_format.yml
new file mode 100644
index 0000000..101598c
--- /dev/null
+++ b/migration_templates/d5_filter_format.yml
@@ -0,0 +1,45 @@
+id: d5_filter_format
+label: Drupal 5 filter format configuration
+migration_tags:
+  - Drupal 5
+source:
+  plugin: d6_filter_format
+process:
+  format:
+    -
+      plugin: machine_name
+      source: name
+    -
+      plugin: dedupe_entity
+      entity_type: filter_format
+      field: format
+      length: 32
+  name: name
+  cache: cache
+  filters:
+    plugin: iterator
+    source: filters
+    key: @id
+    process:
+      id:
+        plugin: static_map
+        default_value: filter_null
+        source:
+          - module
+          - delta
+        map:
+          filter:
+            - filter_html
+            - filter_autop
+            - filter_url
+            - filter_htmlcorrector
+            - filter_html_escape
+          php:
+            - php_code
+      settings: settings
+      status:
+        plugin: default_value
+        default_value: true
+destination:
+  plugin: entity:filter_format
+  no_stub: true
diff --git a/migration_templates/d5_node.yml b/migration_templates/d5_node.yml
new file mode 100644
index 0000000..4163931
--- /dev/null
+++ b/migration_templates/d5_node.yml
@@ -0,0 +1,57 @@
+id: d5_node
+label: Drupal 5 nodes
+migration_tags:
+  - Drupal 5
+builder:
+  plugin: d5_node
+source:
+  plugin: d5_node
+process:
+  nid: nid
+  vid: vid
+  type: type
+  langcode:
+    plugin: default_value
+    source: language
+    default_value: "und"
+  title: title
+  uid: node_uid
+# Core migrations are designed for replacing the upgrade path and therefore
+# all node and user ids are preserved. For that reason we do not need to look-up
+# the user id for the node. If you're writing a custom migration, user ids will
+# vary from the source site and a lookup as shown below will be required.
+#    plugin: migration
+#    migration: d5_user
+#    source: node_uid
+  status: status
+  created: created
+  changed: changed
+  promote: promote
+  sticky: sticky
+  'body/format':
+    plugin: migration
+    migration: d5_filter_format
+    source: format
+  'body/value': body
+  'body/summary': teaser
+  revision_uid: revision_uid
+  revision_log: log
+  revision_timestamp: timestamp
+
+#  unmapped d6 fields.
+#  tnid
+#  translate
+#  moderate
+#  comment
+
+destination:
+  plugin: entity:node
+migration_dependencies:
+  required:
+    - d5_user
+    - d5_node_type
+    - d5_node_settings
+    - d5_filter_format
+#  optional:
+#    - d5_field_instance_widget_settings
+#    - d5_field_formatter_settings
diff --git a/migration_templates/d5_node_revision.yml b/migration_templates/d5_node_revision.yml
new file mode 100644
index 0000000..b7c96a4
--- /dev/null
+++ b/migration_templates/d5_node_revision.yml
@@ -0,0 +1,41 @@
+id: d5_node_revision
+label: Drupal 5 node revisions
+migration_tags:
+  - Drupal 5
+builder:
+  plugin: d5_node
+source:
+  plugin: d6_node_revision
+process:
+  nid: nid
+  vid: vid
+  type: type
+  langcode:
+    plugin: default_value
+    default_value: "und"
+  title: title
+  uid: node_uid
+  status: status
+  created: created
+  changed: changed
+  promote: promote
+  sticky: sticky
+  'body/format':
+    plugin: migration
+    migration: d5_filter_format
+    source: format
+  'body/value': body
+  'body/summary': teaser
+  revision_uid: revision_uid
+  revision_log: log
+  revision_timestamp: timestamp
+
+#  unmapped d5 fields.
+#  moderate
+#  comment
+
+destination:
+  plugin: entity_revision:node
+migration_dependencies:
+  required:
+    - d5_node:*
diff --git a/migration_templates/d5_node_setting_promote.yml b/migration_templates/d5_node_setting_promote.yml
new file mode 100644
index 0000000..02e4bcd
--- /dev/null
+++ b/migration_templates/d5_node_setting_promote.yml
@@ -0,0 +1,19 @@
+id: d5_node_setting_promote
+label: Drupal 5 node type 'promote' setting
+migration_tags:
+  - Drupal 5
+source:
+  plugin: d6_node_type
+  constants:
+    entity_type: node
+    field_name: promote
+process:
+  entity_type: 'constants/entity_type'
+  bundle: type
+  field_name: 'constants/field_name'
+  'default_value/0/value': 'options/promote'
+destination:
+  plugin: entity:base_field_override
+migration_dependencies:
+  required:
+    - d5_node_type
diff --git a/migration_templates/d5_node_setting_status.yml b/migration_templates/d5_node_setting_status.yml
new file mode 100644
index 0000000..611307d
--- /dev/null
+++ b/migration_templates/d5_node_setting_status.yml
@@ -0,0 +1,19 @@
+id: d5_node_setting_status
+label: Drupal 5 node type 'status' setting
+migration_tags:
+  - Drupal 5
+source:
+  plugin: d6_node_type
+  constants:
+    entity_type: node
+    field_name: status
+process:
+  entity_type: 'constants/entity_type'
+  bundle: type
+  field_name: 'constants/field_name'
+  'default_value/0/value': 'options/status'
+destination:
+  plugin: entity:base_field_override
+migration_dependencies:
+  required:
+    - d5_node_type
diff --git a/migration_templates/d5_node_setting_sticky.yml b/migration_templates/d5_node_setting_sticky.yml
new file mode 100644
index 0000000..48e4fa9
--- /dev/null
+++ b/migration_templates/d5_node_setting_sticky.yml
@@ -0,0 +1,19 @@
+id: d5_node_setting_sticky
+label: Drupal 5 node type 'sticky' setting
+migration_tags:
+  - Drupal 5
+source:
+  plugin: d6_node_type
+  constants:
+    entity_type: node
+    field_name: sticky
+process:
+  entity_type: 'constants/entity_type'
+  bundle: type
+  field_name: 'constants/field_name'
+  'default_value/0/value': 'options/sticky'
+destination:
+  plugin: entity:base_field_override
+migration_dependencies:
+  required:
+    - d5_node_type
diff --git a/migration_templates/d5_node_settings.yml b/migration_templates/d5_node_settings.yml
new file mode 100644
index 0000000..937ebfd
--- /dev/null
+++ b/migration_templates/d5_node_settings.yml
@@ -0,0 +1,13 @@
+id: d5_node_settings
+label: Drupal 5 node configuration
+migration_tags:
+  - Drupal 5
+source:
+  plugin: variable
+  variables:
+    - node_admin_theme
+process:
+  use_admin_theme: node_admin_theme
+destination:
+  plugin: config
+  config_name: node.settings
diff --git a/migration_templates/d5_node_type.yml b/migration_templates/d5_node_type.yml
new file mode 100644
index 0000000..55d84d5
--- /dev/null
+++ b/migration_templates/d5_node_type.yml
@@ -0,0 +1,24 @@
+id: d5_node_type
+label: Drupal 5 node type configuration
+migration_tags:
+  - Drupal 5
+source:
+  plugin: d6_node_type
+  constants:
+    preview: 1 # DRUPAL_OPTIONAL
+    create_body: false
+process:
+  type: type
+  name: name
+  module: module
+  description: description
+  help: help
+  title_label: title_label
+  'preview_mode': 'constants/preview'
+  'display_submitted': display_submitted
+  'new_revision': 'options/revision'
+  'settings/node/options': options
+  create_body: has_body
+  create_body_label: body_label
+destination:
+  plugin: entity:node_type
diff --git a/migration_templates/d5_taxonomy_term.yml b/migration_templates/d5_taxonomy_term.yml
new file mode 100644
index 0000000..d8205b8
--- /dev/null
+++ b/migration_templates/d5_taxonomy_term.yml
@@ -0,0 +1,30 @@
+id: d5_taxonomy_term
+label: Drupal 5 taxonomy terms
+migration_tags:
+  - Drupal 5
+source:
+  # The D5 and D6 vocabulary schemas were identical.
+  plugin: d6_taxonomy_term
+process:
+  tid: tid
+  vid:
+    plugin: migration
+    migration: d5_taxonomy_vocabulary
+    source: vid
+  name: name
+  description: description
+  weight: weight
+  parent:
+    -
+      plugin: skip_on_empty
+      method: process
+      source: parent
+    -
+      plugin: migration
+      migration: d5_taxonomy_term
+  changed: timestamp
+destination:
+  plugin: entity:taxonomy_term
+migration_dependencies:
+  required:
+    - d5_taxonomy_vocabulary
diff --git a/migration_templates/d5_taxonomy_vocabulary.yml b/migration_templates/d5_taxonomy_vocabulary.yml
new file mode 100644
index 0000000..b83ceac
--- /dev/null
+++ b/migration_templates/d5_taxonomy_vocabulary.yml
@@ -0,0 +1,24 @@
+id: d5_taxonomy_vocabulary
+label: Drupal 5 taxonomy vocabularies
+migration_tags:
+  - Drupal 5
+source:
+  # The D5 and D6 vocabulary schemas were identical.
+  plugin: d6_taxonomy_vocabulary
+process:
+  vid:
+    -
+      plugin: machine_name
+      source: name
+    -
+      plugin: dedupe_entity
+      entity_type: taxonomy_vocabulary
+      field: vid
+      length: 32
+  label: name
+  name: name
+  description: description
+  hierarchy: hierarchy
+  weight: weight
+destination:
+  plugin: entity:taxonomy_vocabulary
diff --git a/migration_templates/d5_term_node.yml b/migration_templates/d5_term_node.yml
new file mode 100644
index 0000000..8b9279c
--- /dev/null
+++ b/migration_templates/d5_term_node.yml
@@ -0,0 +1,22 @@
+id: d5_term_node
+label: Drupal 5 term/node relationships
+#migration_tags:
+#  - Drupal 5
+builder:
+  plugin: d6_term_node
+load:
+  plugin: d6_term_node
+
+source:
+  plugin: d5_term_node
+
+process:
+  nid: nid
+  type: type
+  # The actual field name is dynamic and will be added by the load plugin.
+
+destination:
+  plugin: entity:node
+migration_dependencies:
+  required:
+    - d5_node:*
diff --git a/migration_templates/d5_user.yml b/migration_templates/d5_user.yml
new file mode 100644
index 0000000..c535721
--- /dev/null
+++ b/migration_templates/d5_user.yml
@@ -0,0 +1,38 @@
+id: d5_user
+label: Drupal 5 user accounts
+migration_tags:
+  - Drupal 5
+source:
+  plugin: d5_user
+process:
+  uid: uid
+  name: name
+  pass: pass
+  mail: mail
+  created: created
+  access: access
+  login: login
+  status: status
+  timezone:
+    plugin: user_update_7002
+    source: timezone
+  preferred_langcode: language
+  init: init
+  roles:
+    plugin: migration
+    migration: d5_user_role
+    source: roles
+  user_picture:
+    # Same for D5 and D6.
+    plugin: d6_user_picture
+    source: uid
+destination:
+  plugin: entity:user
+  md5_passwords: true
+migration_dependencies:
+  required:
+    - d5_user_role
+#  optional:
+#    - d5_user_picture_file
+#    - d5_user_picture_entity_display
+#    - d5_user_picture_entity_form_display
diff --git a/migration_templates/d5_user_contact_settings.yml b/migration_templates/d5_user_contact_settings.yml
new file mode 100644
index 0000000..180de6a
--- /dev/null
+++ b/migration_templates/d5_user_contact_settings.yml
@@ -0,0 +1,23 @@
+id: d5_user_contact_settings
+label: Drupal 5 user contact settings
+migration_tags:
+  - Drupal 5
+source:
+  plugin: d5_user
+  constants:
+    key: contact
+    module: contact
+process:
+  uid: uid
+  key: 'constants/key'
+  module: 'constants/module'
+  settings:
+    plugin: skip_row_if_not_set
+    index: contact
+    source: data
+
+destination:
+  plugin: user_data
+migration_dependencies:
+  required:
+    - d5_user
diff --git a/migration_templates/d5_user_mail.yml b/migration_templates/d5_user_mail.yml
new file mode 100644
index 0000000..49c4bb5
--- /dev/null
+++ b/migration_templates/d5_user_mail.yml
@@ -0,0 +1,39 @@
+id: d5_user_mail
+label: Drupal 5 user mail configuration
+migration_tags:
+  - Drupal 5
+source:
+  plugin: variable
+  variables:
+    - user_mail_status_activated_subject
+    - user_mail_status_activated_body
+    - user_mail_password_reset_subject
+    - user_mail_password_reset_body
+    - user_mail_status_deleted_subject
+    - user_mail_status_deleted_body
+    - user_mail_register_admin_created_subject
+    - user_mail_register_admin_created_body
+    - user_mail_register_no_approval_required_subject
+    - user_mail_register_no_approval_required_body
+    - user_mail_user_mail_register_pending_approval_subject
+    - user_mail_user_mail_register_pending_approval_body
+    - user_mail_status_blocked_subject
+    - user_mail_status_blocked_body
+process:
+  'status_activated/subject': user_mail_status_activated_subject
+  'status_activated/body': user_mail_status_activated_body
+  'password_reset/subject': user_mail_password_reset_subject
+  'password_reset/body': user_mail_password_reset_body
+  'cancel_confirm/subject': user_mail_status_deleted_subject
+  'cancel_confirm/body': user_mail_status_deleted_body
+  'register_admin_created/subject': user_mail_register_admin_created_subject
+  'register_admin_created/body': user_mail_register_admin_created_body
+  'register_no_approval_required/subject': user_mail_register_no_approval_required_subject
+  'register_no_approval_required/body': user_mail_register_no_approval_required_body
+  'register_pending_approval/subject': user_mail_user_mail_register_pending_approval_subject
+  'register_pending_approval/body': user_mail_user_mail_register_pending_approval_body
+  'status_blocked/subject': user_mail_status_blocked_subject
+  'status_blocked/body': user_mail_status_blocked_body
+destination:
+  plugin: config
+  config_name: user.mail
diff --git a/migration_templates/d5_user_role.yml b/migration_templates/d5_user_role.yml
new file mode 100644
index 0000000..b916ff7
--- /dev/null
+++ b/migration_templates/d5_user_role.yml
@@ -0,0 +1,46 @@
+id: d5_user_role
+label: Drupal 5 user roles
+migration_tags:
+  - Drupal 5
+source:
+  plugin: d6_user_role
+process:
+  id:
+    -
+      plugin: machine_name
+      source: name
+    -
+      plugin: dedupe_entity
+      entity_type: user_role
+      field: id
+      length: 32
+    -
+      plugin: user_update_8002
+  label: name
+  permissions:
+    -
+      plugin: static_map
+      source: permissions
+      bypass: true
+      map:
+        'use PHP for block visibility': 'use PHP for settings'
+        'administer site-wide contact form': 'administer contact forms'
+        'post comments without approval': 'skip comment approval'
+        'edit own blog entries' : 'edit own blog content'
+        'edit any blog entry' : 'edit any blog content'
+        'delete own blog entries' : 'delete own blog content'
+        'delete any blog entry' : 'delete any blog content'
+        'create forum topics' : 'create forum content'
+        'delete any forum topic' : 'delete any forum content'
+        'delete own forum topics' : 'delete own forum content'
+        'edit any forum topic' : 'edit any forum content'
+        'edit own forum topics' : 'edit own forum content'
+    - plugin: system_update_7000
+    - plugin: node_update_7008
+    - plugin: flatten
+    - plugin: filter_format_permission
+destination:
+  plugin: entity:user_role
+migration_dependencies:
+  required:
+    - d5_filter_format
diff --git a/migration_templates/d5_user_settings.yml b/migration_templates/d5_user_settings.yml
new file mode 100644
index 0000000..49b7f27
--- /dev/null
+++ b/migration_templates/d5_user_settings.yml
@@ -0,0 +1,28 @@
+id: d5_user_settings
+label: Drupal 5 user configuration
+migration_tags:
+  - Drupal 5
+source:
+  plugin: variable
+  variables:
+    - user_mail_status_blocked_notify
+    - user_mail_status_activated_notify
+    - user_email_verification
+    - user_register
+    - anonymous
+process:
+  'notify/status_blocked': user_mail_status_blocked_notify
+  'notify/status_activated': user_mail_status_activated_notify
+  verify_mail: user_email_verification
+  register:
+    plugin: static_map
+    source: user_register
+    default_value: visitors_admin_approval
+    map:
+      2: visitors_admin_approval
+      1: user_register
+      0: admin_only
+  anonymous: anonymous
+destination:
+  plugin: config
+  config_name: user.settings
diff --git a/migration_templates/d5_vocabulary_field.yml b/migration_templates/d5_vocabulary_field.yml
new file mode 100644
index 0000000..bb0f707
--- /dev/null
+++ b/migration_templates/d5_vocabulary_field.yml
@@ -0,0 +1,26 @@
+id: d5_vocabulary_field
+label: Drupal 5 vocabulary field configuration
+migration_tags:
+  - Drupal 5
+source:
+  # The D5 and D6 vocabulary schemas were identical.
+  plugin: d6_taxonomy_vocabulary
+  constants:
+    entity_type: node
+    type: entity_reference
+    target_entity_type: taxonomy_term
+    cardinality: -1
+process:
+  entity_type: 'constants/entity_type'
+  type: 'constants/type'
+  field_name:
+    plugin: migration
+    migration: d5_taxonomy_vocabulary
+    source: vid
+  'settings/target_type': 'constants/target_entity_type'
+  cardinality: 'constants/cardinality'
+destination:
+  plugin: md_entity:field_storage_config
+migration_dependencies:
+  required:
+    - d5_taxonomy_vocabulary
diff --git a/migration_templates/d5_vocabulary_field_instance.yml b/migration_templates/d5_vocabulary_field_instance.yml
new file mode 100644
index 0000000..5572d9a
--- /dev/null
+++ b/migration_templates/d5_vocabulary_field_instance.yml
@@ -0,0 +1,27 @@
+id: d5_vocabulary_field_instance
+label: Drupal 5 vocabulary field instance configuration
+migration_tags:
+  - Drupal 5
+source:
+  # The D5 and D6 vocabulary schemas were identical.
+  plugin: d6_taxonomy_vocabulary_per_type
+  constants:
+    entity_type: node
+    auto_create: true
+    selection_handler: 'default:taxonomy_term'
+process:
+  entity_type: 'constants/entity_type'
+  bundle: type
+  field_name:
+    plugin: migration
+    migration: d5_taxonomy_vocabulary
+    source: vid
+  'settings/handler': 'constants/selection_handler'
+  'settings/handler_settings/target_bundles/0': @field_name
+  'settings/handler_settings/auto_create': 'constants/auto_create'
+destination:
+  plugin: entity:field_config
+migration_dependencies:
+  required:
+    - d5_node_type
+    - d5_vocabulary_field
diff --git a/src/Plugin/migrate/builder/d5/Node.php b/src/Plugin/migrate/builder/d5/Node.php
new file mode 100644
index 0000000..0fafb9c
--- /dev/null
+++ b/src/Plugin/migrate/builder/d5/Node.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal_d5\Plugin\migrate\builder\d5\Node.
+ */
+
+namespace Drupal\migrate_drupal_d5\Plugin\migrate\builder\d5;
+
+use Drupal\migrate\Entity\Migration;
+use Drupal\migrate\Entity\MigrationInterface;
+use Drupal\migrate_drupal\Plugin\migrate\builder\d6\CckBuilder;
+
+/**
+ * @PluginID("d5_node")
+ */
+class Node extends CckBuilder {
+
+  /**
+   * Already-instantiated cckfield plugins, keyed by ID.
+   *
+   * @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldInterface[]
+   */
+  protected $cckPluginCache = [];
+
+  /**
+   * Gets a cckfield plugin instance.
+   *
+   * @param string $field_type
+   *   The field type (plugin ID).
+   * @param \Drupal\migrate\Entity\MigrationInterface|NULL $migration
+   *   The migration, if any.
+   *
+   * @return \Drupal\migrate_drupal\Plugin\MigrateCckFieldInterface
+   *   The cckfield plugin instance.
+   */
+  protected function getCckPlugin($field_type, MigrationInterface $migration = NULL) {
+    if (empty($this->cckPluginCache[$field_type])) {
+      $this->cckPluginCache[$field_type] = $this->cckPluginManager->createInstance($field_type, [], $migration);
+    }
+    return $this->cckPluginCache[$field_type];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildMigrations(array $template) {
+    $migrations = [];
+
+    foreach ($this->getSourcePlugin('d6_node_type', $template['source']) as $row) {
+      $node_type = $row->getSourceProperty('type');
+      $values = $template;
+      $values['id'] = $template['id'] . '__' . $node_type;
+      $migration = Migration::create($values);
+
+      $fields = $this->getSourcePlugin('d5_field_instance', ['node_type' => $node_type] + $template['source']);
+      foreach ($fields as $field) {
+        $data = $field->getSource();
+
+        if ($this->cckPluginManager->hasDefinition($data['type'])) {
+          $this->getCckPlugin($data['type'])
+            ->processCckFieldValues($migration, $data['field_name'], $data);
+        }
+        else {
+          $migration->setProcessOfProperty($data['field_name'], $data['field_name']);
+        }
+      }
+
+      $migrations[] = $migration;
+    }
+
+    return $migrations;
+  }
+
+}
diff --git a/src/Plugin/migrate/source/d5/Field.php b/src/Plugin/migrate/source/d5/Field.php
new file mode 100644
index 0000000..335e6fd
--- /dev/null
+++ b/src/Plugin/migrate/source/d5/Field.php
@@ -0,0 +1,93 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal_d5\Plugin\migrate\source\d5\Field.
+ */
+
+namespace Drupal\migrate_drupal_d5\Plugin\migrate\source\d5;
+
+use Drupal\migrate\Row;
+use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
+
+/**
+ * Drupal 5 field source from database.
+ *
+ * @MigrateSource(
+ *   id = "d5_field",
+ *   source_provider = "content"
+ * )
+ */
+class Field extends DrupalSqlBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    $query = $this->select('node_field', 'cnf')
+      ->fields('cnf', array(
+        'field_name',
+        'type',
+        'global_settings',
+        'required',
+        'multiple',
+        'db_storage',
+        'module',
+        'db_columns',
+        'active',
+        'locked',
+      ))
+      ->fields('cnfi', array(
+        'widget_type',
+        'widget_settings',
+      ));
+    $query->join('node_field_instance', 'cnfi', 'cnfi.field_name = cnf.field_name');
+    $query->orderBy('field_name');
+
+    return $query;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    return array(
+      'field_name' => $this->t('Field name'),
+      'type' => $this->t('Type (text, integer, ....)'),
+      'global_settings' => $this->t('Global settings. Shared with every field instance.'),
+      'required' => $this->t('Required'),
+      'multiple' => $this->t('Multiple'),
+      'db_storage' => $this->t('DB storage'),
+      'module' => $this->t('Module'),
+      'db_columns' => $this->t('DB Columns'),
+      'active' => $this->t('Active'),
+      'locked' => $this->t('Locked'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function prepareRow(Row $row) {
+    parent::prepareRow($row);
+    // Unserialize data.
+    $global_settings = unserialize($row->getSourceProperty('global_settings'));
+    $widget_settings = unserialize($row->getSourceProperty('widget_settings'));
+    $db_columns = unserialize($row->getSourceProperty('db_columns'));
+    $row->setSourceProperty('global_settings', $global_settings);
+    $row->setSourceProperty('widget_settings', $widget_settings);
+    $row->setSourceProperty('db_columns', $db_columns);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids['field_name'] = array(
+      'type' => 'string',
+      'alias' => 'cnf',
+    );
+    return $ids;
+  }
+
+}
diff --git a/src/Plugin/migrate/source/d5/FieldInstance.php b/src/Plugin/migrate/source/d5/FieldInstance.php
new file mode 100644
index 0000000..3b17db9
--- /dev/null
+++ b/src/Plugin/migrate/source/d5/FieldInstance.php
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal_d5\Plugin\migrate\source\d5\FieldInstance.
+ */
+
+namespace Drupal\migrate_drupal_d5\Plugin\migrate\source\d5;
+
+use Drupal\migrate\Row;
+use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
+
+/**
+ * Drupal 5 field instances source from database.
+ *
+ * @MigrateSource(
+ *   id = "d5_field_instance",
+ *   source_provider = "content"
+ * )
+ */
+class FieldInstance extends DrupalSqlBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    $query = $this->select('node_field_instance', 'cnfi')->fields('cnfi');
+    if (isset($this->configuration['node_type'])) {
+      $query->condition('cnfi.type_name', $this->configuration['node_type']);
+    }
+    $query->join('node_field', 'cnf', 'cnf.field_name = cnfi.field_name');
+    $query->fields('cnf');
+
+    return $query;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    return array(
+      'field_name' => $this->t('The machine name of field.'),
+      'type_name' => $this->t('Content type where is used this field.'),
+      'weight' => $this->t('Weight.'),
+      'label' => $this->t('A name to show.'),
+      'widget_type' => $this->t('Widget type.'),
+      'widget_settings' => $this->t('Serialize data with widget settings.'),
+      'display_settings' => $this->t('Serialize data with display settings.'),
+      'description' => $this->t('A description of field.'),
+      'widget_module' => $this->t('Module that implements widget.'),
+      'widget_active' => $this->t('Status of widget'),
+      'module' => $this->t('The module that provides the field.'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function prepareRow(Row $row) {
+    parent::prepareRow($row);
+    // Unserialize data.
+    $widget_settings = unserialize($row->getSourceProperty('widget_settings'));
+    $display_settings = unserialize($row->getSourceProperty('display_settings'));
+    $global_settings = unserialize($row->getSourceProperty('global_settings'));
+    $row->setSourceProperty('widget_settings', $widget_settings);
+    $row->setSourceProperty('display_settings', $display_settings);
+    $row->setSourceProperty('global_settings', $global_settings);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids = array(
+      'field_name' => array(
+        'type' => 'string',
+        'alias' => 'cnfi',
+      ),
+      'type_name' => array(
+        'type' => 'string',
+      ),
+    );
+    return $ids;
+  }
+
+}
diff --git a/src/Plugin/migrate/source/d5/FieldInstancePerFormDisplay.php b/src/Plugin/migrate/source/d5/FieldInstancePerFormDisplay.php
new file mode 100644
index 0000000..00cc486
--- /dev/null
+++ b/src/Plugin/migrate/source/d5/FieldInstancePerFormDisplay.php
@@ -0,0 +1,101 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal_d5\Plugin\migrate\source\d5\FieldInstancePerFormDisplay.
+ */
+
+namespace Drupal\migrate_drupal_d5\Plugin\migrate\source\d5;
+
+use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
+
+/**
+ * The field instance per form display source class.
+ *
+ * @MigrateSource(
+ *   id = "d5_field_instance_per_form_display"
+ * )
+ */
+class FieldInstancePerFormDisplay extends DrupalSqlBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function initializeIterator() {
+    $rows = array();
+    $result = $this->prepareQuery()->execute();
+    while ($field_row = $result->fetchAssoc()) {
+      $field_row['display_settings'] = unserialize($field_row['display_settings']);
+      $field_row['widget_settings'] = unserialize($field_row['widget_settings']);
+      $bundle = $field_row['type_name'];
+      $field_name = $field_row['field_name'];
+
+      $index = "$bundle.$field_name";
+      $rows[$index]['type_name'] = $bundle;
+      $rows[$index]['widget_active'] = (bool) $field_row['widget_active'];
+      $rows[$index]['field_name'] = $field_name;
+      $rows[$index]['type'] = $field_row['type'];
+      $rows[$index]['module'] = $field_row['module'];
+      $rows[$index]['weight'] = $field_row['weight'];
+      $rows[$index]['widget_type'] = $field_row['widget_type'];
+      $rows[$index]['widget_settings'] = $field_row['widget_settings'];
+    }
+
+    return new \ArrayIterator($rows);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    $query = $this->select('node_field_instance', 'cnfi')
+      ->fields('cnfi', array(
+        'field_name',
+        'type_name',
+        'weight',
+        'label',
+        'widget_type',
+        'widget_settings',
+        'display_settings',
+        'description',
+        'widget_module',
+        'widget_active',
+      ))
+      ->fields('cnf', array(
+        'type',
+        'module',
+      ));
+    $query->join('node_field', 'cnf', 'cnfi.field_name = cnf.field_name');
+    $query->orderBy('weight');
+
+    return $query;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    return array(
+      'field_name' => $this->t('The machine name of field.'),
+      'type_name' => $this->t('Content type where this field is used.'),
+      'weight' => $this->t('Weight.'),
+      'label' => $this->t('A name to show.'),
+      'widget_type' => $this->t('Widget type.'),
+      'widget_settings' => $this->t('Serialize data with widget settings.'),
+      'display_settings' => $this->t('Serialize data with display settings.'),
+      'description' => $this->t('A description of field.'),
+      'widget_module' => $this->t('Module that implements widget.'),
+      'widget_active' => $this->t('Status of widget'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids['type_name']['type'] = 'string';
+    $ids['field_name']['type'] = 'string';
+    return $ids;
+  }
+
+}
diff --git a/src/Plugin/migrate/source/d5/FieldInstancePerViewMode.php b/src/Plugin/migrate/source/d5/FieldInstancePerViewMode.php
new file mode 100644
index 0000000..a6241cc
--- /dev/null
+++ b/src/Plugin/migrate/source/d5/FieldInstancePerViewMode.php
@@ -0,0 +1,107 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal_d5\Plugin\migrate\source\d5\FieldInstancePerViewMode.
+ */
+
+namespace Drupal\migrate_drupal_d5\Plugin\migrate\source\d5;
+
+use Drupal\node\Plugin\migrate\source\d6\ViewModeBase;
+
+/**
+ * The field instance per view mode source class.
+ *
+ * @MigrateSource(
+ *   id = "d5_field_instance_per_view_mode",
+ *   source_provider = "content"
+ * )
+ */
+class FieldInstancePerViewMode extends ViewModeBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function initializeIterator() {
+    $rows = array();
+    $result = $this->prepareQuery()->execute();
+    while ($field_row = $result->fetchAssoc()) {
+      // These are added to every view mode row.
+      $field_row['display_settings'] = unserialize($field_row['display_settings']);
+      $field_row['widget_settings'] = unserialize($field_row['widget_settings']);
+      $bundle = $field_row['type_name'];
+      $field_name = $field_row['field_name'];
+
+      foreach ($this->getViewModes() as $view_mode) {
+        if (isset($field_row['display_settings'][$view_mode]) && empty($field_row['display_settings'][$view_mode]['exclude'])) {
+          $index = $view_mode . "." . $bundle . "." . $field_name;
+          $rows[$index]['entity_type'] = 'node';
+          $rows[$index]['view_mode'] = $view_mode;
+          $rows[$index]['type_name'] = $bundle;
+          $rows[$index]['field_name'] = $field_name;
+          $rows[$index]['type'] = $field_row['type'];
+          $rows[$index]['module'] = $field_row['module'];
+          $rows[$index]['weight'] = $field_row['weight'];
+          $rows[$index]['label'] = $field_row['display_settings']['label']['format'];
+          $rows[$index]['display_settings'] = $field_row['display_settings'][$view_mode];
+          $rows[$index]['widget_settings'] = $field_row['widget_settings'];
+        }
+      }
+    }
+
+    return new \ArrayIterator($rows);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    $query = $this->select('node_field_instance', 'cnfi')
+      ->fields('cnfi', array(
+        'field_name',
+        'type_name',
+        'weight',
+        'label',
+        'display_settings',
+        'widget_settings',
+    ))
+    ->fields('cnf', array(
+        'type',
+        'module',
+    ));
+    $query->join('node_field', 'cnf', 'cnfi.field_name = cnf.field_name');
+    $query->orderBy('weight');
+
+    return $query;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    return array(
+      'field_name' => $this->t('The machine name of field.'),
+      'type_name' => $this->t('Content type where this field is used.'),
+      'weight' => $this->t('Weight.'),
+      'label' => $this->t('A name to show.'),
+      'widget_type' => $this->t('Widget type.'),
+      'widget_settings' => $this->t('Serialize data with widget settings.'),
+      'display_settings' => $this->t('Serialize data with display settings.'),
+      'description' => $this->t('A description of field.'),
+      'widget_module' => $this->t('Module that implements widget.'),
+      'widget_active' => $this->t('Status of widget'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids['type_name']['type'] = 'string';
+    $ids['view_mode']['type'] = 'string';
+    $ids['entity_type']['type'] = 'string';
+    $ids['field_name']['type'] = 'string';
+    return $ids;
+  }
+
+}
diff --git a/src/Plugin/migrate/source/d5/Node.php b/src/Plugin/migrate/source/d5/Node.php
new file mode 100644
index 0000000..5076cb9
--- /dev/null
+++ b/src/Plugin/migrate/source/d5/Node.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal_d5\Plugin\migrate\source\d5\Node.
+ */
+
+namespace Drupal\migrate_drupal_d5\Plugin\migrate\source\d5;
+
+use Drupal\node\Plugin\migrate\source\d6\Node as NodeBase;
+
+/**
+ * Drupal 5 node source from database. All that differs from Drupal 6 is that
+ * we don't have the language, tnid, and translate columns.
+ *
+ * @MigrateSource(
+ *   id = "d5_node"
+ * )
+ */
+class Node extends NodeBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    // Select node in its last revision.
+    $query = $this->select('node_revisions', 'nr')
+      ->fields('n', array(
+        'nid',
+        'type',
+        'status',
+        'created',
+        'changed',
+        'comment',
+        'promote',
+        'moderate',
+        'sticky',
+      ))
+      ->fields('nr', array(
+        'vid',
+        'title',
+        'body',
+        'teaser',
+        'log',
+        'timestamp',
+        'format',
+      ));
+    $query->addField('n', 'uid', 'node_uid');
+    $query->addField('nr', 'uid', 'revision_uid');
+    $query->innerJoin('node', 'n', static::JOIN);
+
+    if (isset($this->configuration['node_type'])) {
+      $query->condition('type', $this->configuration['node_type']);
+    }
+
+    return $query;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    $fields = parent::fields();
+    unset($fields['language']);
+    unset($fields['tnid']);
+    unset($fields['translate']);
+    return $fields;
+  }
+
+}
diff --git a/src/Plugin/migrate/source/d5/NodeRevision.php b/src/Plugin/migrate/source/d5/NodeRevision.php
new file mode 100644
index 0000000..d27bc2d
--- /dev/null
+++ b/src/Plugin/migrate/source/d5/NodeRevision.php
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal_d5\Plugin\migrate\source\d5\NodeRevision.
+ */
+
+namespace Drupal\migrate_drupal_d5\Plugin\migrate\source\d5;
+
+/**
+ * Drupal 5 node revision source from database.
+ *
+ * @MigrateSource(
+ *   id = "d5_node_revision"
+ * )
+ */
+class NodeRevision extends Node {
+
+  /**
+   * The join options between the node and the node_revisions_table.
+   */
+  const JOIN = 'n.nid = nr.nid AND n.vid <> nr.vid';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    // Use all the node fields plus the vid that identifies the version.
+    return parent::fields() + array(
+      'vid' => t('The primary identifier for this version.'),
+      'log' => $this->t('Revision Log message'),
+      'timestamp' => $this->t('Revision timestamp'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids['vid']['type'] = 'integer';
+    $ids['vid']['alias'] = 'nr';
+    return $ids;
+  }
+
+}
diff --git a/src/Plugin/migrate/source/d5/TermNode.php b/src/Plugin/migrate/source/d5/TermNode.php
new file mode 100644
index 0000000..59783e1
--- /dev/null
+++ b/src/Plugin/migrate/source/d5/TermNode.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal_d5\Plugin\migrate\source\d5\TermNode.
+ */
+
+namespace Drupal\migrate_drupal_d5\Plugin\migrate\source\d5;
+
+use Drupal\migrate\Plugin\SourceEntityInterface;
+use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
+
+/**
+ * Source returning tids from the term_node table for the current revision.
+ *
+ * @MigrateSource(
+ *   id = "d5_term_node",
+ *   source_provider = "taxonomy"
+ * )
+ */
+class TermNode extends DrupalSqlBase implements SourceEntityInterface {
+
+    /**
+   * The join options between the node and the term node table.
+   */
+  const JOIN = 'tn.nid = n.nid';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    $query = $this->select('term_node', 'tn')
+      // @todo: working, but not is there support for distinct() in FakeSelect?
+      ->distinct()
+      ->fields('tn', array('nid'))
+      ->fields('n', array('type'))
+      ->fields('td', array('tid'));
+    $query->innerJoin('term_data', 'td', 'td.tid = tn.tid AND td.vid = :vid', array(':vid' => $this->configuration['vid']));
+    $query->innerJoin('node', 'n', static::JOIN);
+    return $query;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    return array(
+      'nid' => $this->t('The node ID.'),
+      'tid' => $this->t('The term ID.'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids['nid']['type'] = 'integer';
+    $ids['nid']['alias'] = 'tn';
+    return $ids;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function bundleMigrationRequired() {
+    return TRUE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function entityTypeId() {
+    return 'taxonomy_term';
+  }
+
+}
diff --git a/src/Plugin/migrate/source/d5/User.php b/src/Plugin/migrate/source/d5/User.php
new file mode 100644
index 0000000..39eb625
--- /dev/null
+++ b/src/Plugin/migrate/source/d5/User.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal_d5\Plugin\migrate\source\d5\User.
+ */
+
+namespace Drupal\migrate_drupal_d5\Plugin\migrate\source\d5;
+
+use Drupal\user\Plugin\migrate\source\d6\User as UserBase;
+
+/**
+ * Drupal 5 user source from database.
+ *
+ * @MigrateSource(
+ *   id = "d5_user"
+ * )
+ */
+class User extends UserBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function baseFields() {
+    $fields = parent::baseFields();
+    // The only difference between D5 and D6 is only D6 has signature_format.
+    unset($fields['signature_format']);
+    return $fields;
+  }
+
+}
-- 
GitLab