From 6c8c545d75ee1946638323b97f13b93635eefc5e Mon Sep 17 00:00:00 2001
From: git <git@102134.no-reply.drupal.org>
Date: Mon, 22 Oct 2018 13:37:57 -0500
Subject: [PATCH] Issue #2961431 by ressa: Migrate from local JSON file?

---
 migrate_json_example/README.md                | 22 +++++
 migrate_json_example/artifacts/products.json  | 16 ++++
 ...tity_form_display.node.product.default.yml | 88 +++++++++++++++++++
 ...tity_view_display.node.product.default.yml | 49 +++++++++++
 ...d.field.node.product.field_description.yml | 18 ++++
 .../field.field.node.product.field_price.yml  | 22 +++++
 .../field.field.node.product.field_upc.yml    | 22 +++++
 .../field.storage.node.field_description.yml  | 20 +++++
 .../field.storage.node.field_price.yml        | 17 ++++
 .../optional/field.storage.node.field_upc.yml | 19 ++++
 .../migrate_plus.migration.product.yml        | 78 ++++++++++++++++
 .../config/optional/node.type.product.yml     | 17 ++++
 .../migrate_json_example.info.yml             |  9 ++
 .../migrate_json_example.install              | 20 +++++
 14 files changed, 417 insertions(+)
 create mode 100644 migrate_json_example/README.md
 create mode 100644 migrate_json_example/artifacts/products.json
 create mode 100644 migrate_json_example/config/optional/core.entity_form_display.node.product.default.yml
 create mode 100644 migrate_json_example/config/optional/core.entity_view_display.node.product.default.yml
 create mode 100644 migrate_json_example/config/optional/field.field.node.product.field_description.yml
 create mode 100644 migrate_json_example/config/optional/field.field.node.product.field_price.yml
 create mode 100644 migrate_json_example/config/optional/field.field.node.product.field_upc.yml
 create mode 100644 migrate_json_example/config/optional/field.storage.node.field_description.yml
 create mode 100644 migrate_json_example/config/optional/field.storage.node.field_price.yml
 create mode 100644 migrate_json_example/config/optional/field.storage.node.field_upc.yml
 create mode 100644 migrate_json_example/config/optional/migrate_plus.migration.product.yml
 create mode 100644 migrate_json_example/config/optional/node.type.product.yml
 create mode 100644 migrate_json_example/migrate_json_example.info.yml
 create mode 100644 migrate_json_example/migrate_json_example.install

diff --git a/migrate_json_example/README.md b/migrate_json_example/README.md
new file mode 100644
index 00000000..4736b985
--- /dev/null
+++ b/migrate_json_example/README.md
@@ -0,0 +1,22 @@
+A demonstration of a simple import of a JSON file.
+
+REQUIREMENTS
+============
+You need the contrib modules Migrate Plus and Migrate Tools.
+To make the products.json file available for import, the file will be copied
+from the artifacts folder to your sites/default/files folder.
+
+USAGE
+=====
+Enable the module, check status, import all products and rollback with Drush
+drush en migrate_json_example
+drush migrate-status
+drush migrate-import product
+drush migrate-rollback product
+
+See config/optional/migrate_plus.migration.product.yml for details about the
+migration.
+
+Thanks to Jeff Geerling and Christophe for the original code:
+- https://www.jeffgeerling.com/blog/2016/migrate-custom-json-feed-drupal-8-migrate-source-json
+- https://colorfield.be/blog/drupal-8-json-custom-migration
diff --git a/migrate_json_example/artifacts/products.json b/migrate_json_example/artifacts/products.json
new file mode 100644
index 00000000..def2ddf2
--- /dev/null
+++ b/migrate_json_example/artifacts/products.json
@@ -0,0 +1,16 @@
+{
+  "product": [
+    {
+      "upc": "11111",
+      "name": "Widget",
+      "description": "Helpful for many things.",
+      "price": "14.99"
+    },
+    {
+      "upc": "22222",
+      "name": "Sprocket",
+      "description": "Helpful for things needing sprockets.",
+      "price": "8.99"
+    }
+  ]
+}
diff --git a/migrate_json_example/config/optional/core.entity_form_display.node.product.default.yml b/migrate_json_example/config/optional/core.entity_form_display.node.product.default.yml
new file mode 100644
index 00000000..7faa1a2b
--- /dev/null
+++ b/migrate_json_example/config/optional/core.entity_form_display.node.product.default.yml
@@ -0,0 +1,88 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.node.product.field_description
+    - field.field.node.product.field_price
+    - field.field.node.product.field_upc
+    - node.type.product
+  module:
+    - path
+id: node.product.default
+targetEntityType: node
+bundle: product
+mode: default
+content:
+  created:
+    type: datetime_timestamp
+    weight: 10
+    region: content
+    settings: {  }
+    third_party_settings: {  }
+  field_description:
+    weight: 123
+    settings:
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+    type: string_textfield
+    region: content
+  field_price:
+    weight: 124
+    settings:
+      placeholder: ''
+    third_party_settings: {  }
+    type: number
+    region: content
+  field_upc:
+    weight: 122
+    settings:
+      placeholder: ''
+    third_party_settings: {  }
+    type: number
+    region: content
+  path:
+    type: path
+    weight: 30
+    region: content
+    settings: {  }
+    third_party_settings: {  }
+  promote:
+    type: boolean_checkbox
+    settings:
+      display_label: true
+    weight: 15
+    region: content
+    third_party_settings: {  }
+  status:
+    type: boolean_checkbox
+    settings:
+      display_label: true
+    weight: 120
+    region: content
+    third_party_settings: {  }
+  sticky:
+    type: boolean_checkbox
+    settings:
+      display_label: true
+    weight: 16
+    region: content
+    third_party_settings: {  }
+  title:
+    type: string_textfield
+    weight: -5
+    region: content
+    settings:
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+  uid:
+    type: entity_reference_autocomplete
+    weight: 5
+    settings:
+      match_operator: CONTAINS
+      size: 60
+      placeholder: ''
+    region: content
+    third_party_settings: {  }
+hidden: {  }
diff --git a/migrate_json_example/config/optional/core.entity_view_display.node.product.default.yml b/migrate_json_example/config/optional/core.entity_view_display.node.product.default.yml
new file mode 100644
index 00000000..9e7a9f23
--- /dev/null
+++ b/migrate_json_example/config/optional/core.entity_view_display.node.product.default.yml
@@ -0,0 +1,49 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.node.product.field_description
+    - field.field.node.product.field_price
+    - field.field.node.product.field_upc
+    - node.type.product
+  module:
+    - user
+id: node.product.default
+targetEntityType: node
+bundle: product
+mode: default
+content:
+  field_description:
+    weight: 103
+    label: above
+    settings:
+      link_to_entity: false
+    third_party_settings: {  }
+    type: string
+    region: content
+  field_price:
+    weight: 104
+    label: above
+    settings:
+      thousand_separator: ''
+      decimal_separator: .
+      scale: 2
+      prefix_suffix: true
+    third_party_settings: {  }
+    type: number_decimal
+    region: content
+  field_upc:
+    weight: 102
+    label: above
+    settings:
+      thousand_separator: ''
+      prefix_suffix: true
+    third_party_settings: {  }
+    type: number_integer
+    region: content
+  links:
+    weight: 100
+    settings: {  }
+    third_party_settings: {  }
+    region: content
+hidden: {  }
diff --git a/migrate_json_example/config/optional/field.field.node.product.field_description.yml b/migrate_json_example/config/optional/field.field.node.product.field_description.yml
new file mode 100644
index 00000000..7bbbd841
--- /dev/null
+++ b/migrate_json_example/config/optional/field.field.node.product.field_description.yml
@@ -0,0 +1,18 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.node.field_description
+    - node.type.product
+id: node.product.field_description
+field_name: field_description
+entity_type: node
+bundle: product
+label: Description
+description: ''
+required: false
+translatable: false
+default_value: {  }
+default_value_callback: ''
+settings: {  }
+field_type: string
diff --git a/migrate_json_example/config/optional/field.field.node.product.field_price.yml b/migrate_json_example/config/optional/field.field.node.product.field_price.yml
new file mode 100644
index 00000000..df23a84a
--- /dev/null
+++ b/migrate_json_example/config/optional/field.field.node.product.field_price.yml
@@ -0,0 +1,22 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.node.field_price
+    - node.type.product
+id: node.product.field_price
+field_name: field_price
+entity_type: node
+bundle: product
+label: Price
+description: ''
+required: false
+translatable: false
+default_value: {  }
+default_value_callback: ''
+settings:
+  min: null
+  max: null
+  prefix: ''
+  suffix: ''
+field_type: float
diff --git a/migrate_json_example/config/optional/field.field.node.product.field_upc.yml b/migrate_json_example/config/optional/field.field.node.product.field_upc.yml
new file mode 100644
index 00000000..ef0a28ec
--- /dev/null
+++ b/migrate_json_example/config/optional/field.field.node.product.field_upc.yml
@@ -0,0 +1,22 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.node.field_upc
+    - node.type.product
+id: node.product.field_upc
+field_name: field_upc
+entity_type: node
+bundle: product
+label: UPC
+description: ''
+required: false
+translatable: false
+default_value: {  }
+default_value_callback: ''
+settings:
+  min: null
+  max: null
+  prefix: ''
+  suffix: ''
+field_type: integer
diff --git a/migrate_json_example/config/optional/field.storage.node.field_description.yml b/migrate_json_example/config/optional/field.storage.node.field_description.yml
new file mode 100644
index 00000000..a5c39580
--- /dev/null
+++ b/migrate_json_example/config/optional/field.storage.node.field_description.yml
@@ -0,0 +1,20 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - node
+id: node.field_description
+field_name: field_description
+entity_type: node
+type: string
+settings:
+  max_length: 255
+  is_ascii: false
+  case_sensitive: false
+module: core
+locked: false
+cardinality: 1
+translatable: true
+indexes: {  }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/migrate_json_example/config/optional/field.storage.node.field_price.yml b/migrate_json_example/config/optional/field.storage.node.field_price.yml
new file mode 100644
index 00000000..090acad3
--- /dev/null
+++ b/migrate_json_example/config/optional/field.storage.node.field_price.yml
@@ -0,0 +1,17 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - node
+id: node.field_price
+field_name: field_price
+entity_type: node
+type: float
+settings: {  }
+module: core
+locked: false
+cardinality: 1
+translatable: true
+indexes: {  }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/migrate_json_example/config/optional/field.storage.node.field_upc.yml b/migrate_json_example/config/optional/field.storage.node.field_upc.yml
new file mode 100644
index 00000000..149b11da
--- /dev/null
+++ b/migrate_json_example/config/optional/field.storage.node.field_upc.yml
@@ -0,0 +1,19 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - node
+id: node.field_upc
+field_name: field_upc
+entity_type: node
+type: integer
+settings:
+  unsigned: false
+  size: normal
+module: core
+locked: false
+cardinality: 1
+translatable: true
+indexes: {  }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/migrate_json_example/config/optional/migrate_plus.migration.product.yml b/migrate_json_example/config/optional/migrate_plus.migration.product.yml
new file mode 100644
index 00000000..755cfbec
--- /dev/null
+++ b/migrate_json_example/config/optional/migrate_plus.migration.product.yml
@@ -0,0 +1,78 @@
+# This migration demonstrates a simple import from a JSON file.
+id: product
+label: JSON feed of Products
+migration_group: Product
+source:
+  # We use the JSON source plugin.
+  plugin: url
+  # In this example we get data from a local file, to get data from a URL
+  # define http as data_fetcher_plugin.
+  # data_fetcher_plugin: http
+  data_fetcher_plugin: file
+  data_parser_plugin: json
+  # The data_parser normally limits the fields passed on to the source plugin
+  # to fields configured to be used as part of the migration. To support more
+  # dynamic migrations, the JSON data parser supports including the original
+  # data for the current row. Simply include the 'include_raw_data' flag set
+  # to `true` to enable this. This option is disabled by default to minimize
+  # memory footprint for migrations that do not need this capability.
+  # include_raw_data: true
+  # Flags whether to track changes to incoming data. If TRUE, we will maintain
+  # hashed source rows to determine whether incoming data has changed.
+  # track_changes: true
+  # Copy the example JSON file in artifacts folder to sites/default/files folder.
+  urls: 'public://migrate_json_example/products.json'
+  # An xpath-like selector corresponding to the items to be imported.
+  item_selector: product
+  # Under 'fields', we list the data items to be imported. The first level keys
+  # are the source field names we want to populate (the names to be used as
+  # sources in the process configuration below). For each field we're importing,
+  # we provide a label (optional - this is for display in migration tools) and
+  # an xpath for retrieving that value. It's important to note that this xpath
+  # is relative to the elements retrieved by item_selector.
+  fields:
+    -
+      name: upc
+      label: 'Unique product identifier'
+      selector: upc
+    -
+      name: name
+      label: 'Product name'
+      selector: name
+    -
+      name: description
+      label: 'Product description'
+      selector: description
+    -
+      name: price
+      label: 'Product price'
+      selector: price
+  # Under 'ids', we identify source fields populated above which will uniquely
+  # identify each imported item. The 'type' makes sure the migration map table
+  # uses the proper schema type for stored the IDs.
+  ids:
+    upc:
+      type: integer
+process:
+  # Note that the source field names here (name, description and price) were
+  # defined by the 'fields' configuration for the source plugin above.
+  type:
+    plugin: default_value
+    default_value: product
+  title: name
+  field_upc: upc
+  field_description: description
+  field_price: price
+  sticky:
+    plugin: default_value
+    default_value: 0
+  uid:
+    plugin: default_value
+    default_value: 0
+destination:
+  plugin: 'entity:node'
+migration_dependencies: {  }
+dependencies:
+  enforced:
+    module:
+      - migrate_json_example
diff --git a/migrate_json_example/config/optional/node.type.product.yml b/migrate_json_example/config/optional/node.type.product.yml
new file mode 100644
index 00000000..18d8499d
--- /dev/null
+++ b/migrate_json_example/config/optional/node.type.product.yml
@@ -0,0 +1,17 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - menu_ui
+third_party_settings:
+  menu_ui:
+    available_menus:
+      - main
+    parent: 'main:'
+name: Product
+type: product
+description: ''
+help: ''
+new_revision: true
+preview_mode: 1
+display_submitted: true
diff --git a/migrate_json_example/migrate_json_example.info.yml b/migrate_json_example/migrate_json_example.info.yml
new file mode 100644
index 00000000..ed4b8ef4
--- /dev/null
+++ b/migrate_json_example/migrate_json_example.info.yml
@@ -0,0 +1,9 @@
+type: module
+name: Migrate JSON Example
+description: 'Simple JSON Migration example'
+package: Examples
+core: 8.x
+dependencies:
+  - drupal:migrate
+  - migrate_plus:migrate_plus
+  - migrate_plus:migrate_tools
diff --git a/migrate_json_example/migrate_json_example.install b/migrate_json_example/migrate_json_example.install
new file mode 100644
index 00000000..961a0a9e
--- /dev/null
+++ b/migrate_json_example/migrate_json_example.install
@@ -0,0 +1,20 @@
+<?php
+
+/**
+ * @file
+ * Install, update, and uninstall functions for migrate_json_example.
+ */
+
+/**
+ * Copies the example file to the sites/default/files folder.
+ */
+function migrate_json_example_install() {
+  // Create the example file directory and ensure it's writable.
+  $directory = file_default_scheme() . '://migrate_json_example';
+  file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+
+  // Copy the example file to example directory
+  $module_path = drupal_get_path('module', 'migrate_json_example');
+  $file_source = $module_path . '/artifacts/products.json';
+  file_unmanaged_copy($file_source, $directory . '/products.json', FILE_EXISTS_REPLACE);
+}
-- 
GitLab