Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a custom Migrate destination plugin that allows testing of metadata migrations #1021

Open
mjordan opened this issue Feb 6, 2019 · 4 comments
Labels
Subject: Migration Concerning migration from Islandora 7 to Islandora 2.x.x
Milestone

Comments

@mjordan
Copy link
Contributor

mjordan commented Feb 6, 2019

Just bouncing an idea around here, but it would be great to be able to test a migration before committing to it, particularly one from an Islandora 7.x instance using https://github.com/Islandora-Devops/migrate_7x_claw. I notice that the Migrate Plus module provides a Table destination plugin (migrate_plus/src/Plugin/migrate/destination/Table.php). I wonder if we could use this to test a migration? Or use it as the basis for a custom plugin that writes the migrated data to a CSV file for manual inspection?

The workflow I am imagining is:

  1. Configure the Solr queries and XPaths in the https://github.com/Islandora-Devops/migrate_7x_claw YAML files as you would now.
  2. Configure the migrations to use the this custom destination plugin instead of plugin: 'entity:node', plugin: 'entity:taxonomy_term', etc.
  3. Run the test migration(s).
  4. Inspect the resulting Drupal field data written to the CSV file.
  5. Repeat as many times as you need until you're happy.
  6. Edit your YAML files to use the standard plugin: 'entity:node', plugin: 'entity:taxonomy_term', etc.
  7. Run your migration for reals.
@mjordan
Copy link
Contributor Author

mjordan commented Feb 6, 2019

Maybe even the Table destination plugin + Views would be a good start.

@dannylamb
Copy link
Contributor

dannylamb commented Feb 6, 2019

👍 to letting people sneak a peak before pulling the trigger on a potentially long migration.

@mjordan
Copy link
Contributor Author

mjordan commented Feb 6, 2019

Let me poke around a bit. Might be a good way to warn people about stuff like #1017 which they could then fix in the source, if applicable.

@mjordan
Copy link
Contributor Author

mjordan commented Feb 12, 2019

Some preliminary luck (only a little bit of it good) with using the table destination plugin. I am able to do a very pared down migration using migrate_plus.migration.islandora_objects.yml that results in the following values being added to my custom table:

mysql> select PID,title from islandora_migrate_7x_dry_run;
+-------------------------------------+------------------------------------------------------------------------+
| PID                                 | title                                                                  |
+-------------------------------------+------------------------------------------------------------------------+
| testing:9                           | Trading Post and Auto Court, Rocky Mountain Range, Spillimacheen, B.C. |
| testing:8                           | Manson's Landing-bortey? Id. B.C.                                      |
| testing:7                           | Winter Travel in the North, Atlin, B.C.                                |
| testing:6                           | Ruskin Power Plant, near Mission City, B.C.                            |
| testing:5                           | A Corner of the Fruit Fair, Nelson, B.C.                               |
| testing:4                           | Metropolitan Methodist Church Victoria B.C.                            |
| testing:3                           | Tillicum Seaside Cottages Yellow Point V.I., B.C.                      |
| testing:20                          | Royal Savary Hotel, Indian Point, Savary Island, B.C.                  |
| testing:2                           | Baker Street Cranbrook, B.C.                                           |
| testing:19                          | Kanaka Creek Port Haney, B.C.                                          |
| testing:18                          | Columbia Ave Rossland B.C.                                             |
| testing:17                          | Kelowna, B.C. Barnard Ave.                                             |
| testing:16                          | Ruskin Power Plant, near Mission City, B.C.                            |
| testing:15                          | Rainbow Lodge Alta Lake, B.C.                                          |
| testing:14                          | Barkerville BC                                                         |
| testing:13                          | Hallelujah Point, Vancouver, B.C.                                      |
| testing:12                          | Bill Bose Ox Team on way to Barkerville 1881                           |
| testing:11                          | Qualicum Beach, Vancouver Island, B.C.                                 |
| testing:10                          | Hastings Street, Vancouver, B.C.                                       |
| testing:1                           | Manson's Landing-bortey? Id. B.C.                                      |
| islandora:sp_basic_image_collection | Basic Image Collection                                                 |
| islandora:9                         | Testing multiple versions                                              |
| islandora:2                         | Mark's test PDF                                                        |
+-------------------------------------+------------------------------------------------------------------------+
23 rows in set (0.00 sec)

Which is something.

Steps I took:

  1. create a custom destination table using Drupal's Schema API in a module .install file (see below). Each field in this table corresponds to a source field in migrate_plus.migration.islandora_objects.yml.
  2. Run the migrate_plus.migration.islandora_objects.yml migration.

Here's my migrate_plus.migration.islandora_objects.yml.

langcode: en
status: true
dependencies:
  enforced:
    module:
      - migrate_7x_claw
      - migrate_plus
      - islandora
id: islandora_objects
class: null
field_plugin_method: null
cck_plugin_method: null
migration_tags: null
migration_group: islandora_7x
label: 'Islandora Objects'
source:
  plugin: islandora
  solr_base_url: 'http://192.168.0.120:8080/solr'
  q: 'RELS_EXT_isMemberOfCollection_uri_ms:"info:fedora/islandora:sp_basic_image_collection" OR PID:"islandora:sp_basic_image_collection"'
  row_type: solr
  fedora_base_url: 'http://192.168.0.120:8080/fedora'
  data_fetcher_plugin: http
  authentication:
    plugin: basic
    username: fedoraAdmin
    password: fedoraAdmin
  data_parser_plugin: json_list
  item_selector: '/response/docs'
  constants:
    creator_uid: 1
  fields:
    -
      name: PID
      label: PID
      selector: 'PID'
      name: created
      label: 'Created Date'
      selector: 'fgs_createdDate_dt'
    -
      name: lastmodified
      label: 'Last Modified Date'
      selector: 'fgs_lastModifiedDate_dt'
    -
      name: title
      label: 'Title'
      selector: 'fgs_label_s'
    -
      name: subtitle
      label: 'Subtitle'
      selector: 'mods_titleInfo_subTitle_s'
    -
      name: identifier
      label: 'Identifier'
      selector: 'mods_identifier_local_s'
    -
      name: description
      label: 'Description'
      selector: 'mods_abstract_s'
    -
      name: extent
      label: 'Physical Extent'
      selector: 'mods_physicalDescription_extent_s'
  ids:
    PID:
      type: string
process:
  title: title
  field_alternative_title: subtitle
  field_identifier: identifier
  field_pid: PID
  field_description: description
  field_extent: extent
  type:
    plugin: default_value
    default_value: islandora_object
  uid: constants/creator_uid
  created:
    plugin: format_date
    from_format: 'Y-m-d\TH:i:s.u\Z'
    to_format: U
    source: created
    settings:
      validate_format: false
 updated:
    plugin: format_date
    from_format: 'Y-m-d\TH:i:s.u\Z'
    to_format: U
    source: lastmodified
    settings:
      validate_format: false
destination:
  plugin: table
  # Table which already exists in Drupal database.
  table_name: islandora_migrate_7x_dry_run
  # Fields which will be used by the migration to map a unique table row.
  id_fields:
    localid:
      type: integer
  # Fields which will be inserted in the table columns.
  fields:
    PID: PID
    model: model
    created: created
    lastmodified: lastmodified
    title: title
    subtitle: subtitle
    resource_type: resource_type
    identifier: identifier
    description: description
    extent: extent
    member_of: member_of
    person_agents: person_agents
    person_roles: person_roles
    corporate_agents: corporate_agents
    corporate_roles: corporate_roles
    topic: topic
    temporal: temporal
    geographic: geographic
    continent: continent
    country: country
    province: province
    region: region
    county: county
    city: city
    city_section: city_section
migration_dependencies:
  required: { }
  optional: { }

Notice that it contains no source taxonomy terms. When you include them, they get created as terms, they do not get persisted to the table.

I'm getting errors like these. The nodes I am importing are linked to another table, migrate_map_islandora_objects, via a field that expects an integer:

[error]  SQLSTATE[HY000]: General error: 1366 Incorrect integer value: 'testing:4' for column 'destid1' at row 1: INSERT INTO {migrate_map_islandora_objects} (source_ids_hash, sourceid1, source_row_status, rollback_action, hash, destid1) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5); Array
(
    [:db_insert_placeholder_0] => 30c38925cc953d6176c91c2067d407fecb639cbeb0913c977b2d44fa0134be4a
    [:db_insert_placeholder_1] => testing:4
    [:db_insert_placeholder_2] => 0
    [:db_insert_placeholder_3] => 0
    [:db_insert_placeholder_4] => 
    [:db_insert_placeholder_5] => testing:4
)
 (/var/www/html/drupal/web/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php:650) 

Here's my .install file that creates the destination table:

<?php

/**
 * @file
 * Install/update hook implementations.
 */

/**
 * Implements hook_schema().
 */
function islandora_migrate_7x_dry_run_schema() {
  $schema = [];
  $schema['islandora_migrate_7x_dry_run'] = [
    'description' => 'Table used as a destination in dry run migrations from from Islandora 7.x.',
    'fields' => [
      'localid' => [
        'description' => 'The local ID in this database table.',
        'type' => 'serial',
        'not null' => TRUE,
        'unique' => TRUE,
      ],
      'PID' => [
        'description' => 'The 7.x PID',
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'unique' => TRUE,
      ],
      'model' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'created' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'lastmodified' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'title' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'subtitle' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'resource_type' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'description' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'extent' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'member_of' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'person_agents' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'person_roles' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'corporate_agents' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'corporate_roles' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'topic' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'temporal' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'geographic' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'continent' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'country' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'province' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'region' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'city' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
      'city_section' => [
        'description' => '',
        'type' => 'text',
        'size' => 'normal',
      ],
    ],
    'primary key' => ['localid'],
  ];
  return $schema;
}

I'm going to try hacking together a custom CSV destination plugin to get me past some of the Schema hassles. I'll report back.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Subject: Migration Concerning migration from Islandora 7 to Islandora 2.x.x
Projects
Development

No branches or pull requests

4 participants