Drupal Migrate API skip_on_multiple Process Plugin
Here’s a Migrate API process plugin I wrote in Drupal 9 that skips a property or row when more than one value exists. My use case:
- My source data has locations; each location has multiple associated organizations
- My new Drupal site has locations; each location has a parent organization
- I want to only populate the field_parent_org field (an entity reference) if there is a single organization value in the source data for the location
- I’m using a custom module called “pdms_migrate”
I’ve stripped out all of the noise from the examples below… hopefully it’s enough to help you understand the example:
modules/custom/pdms_migrate/data/sitecore_locations.xml
In this example, only “My Second Location” will reference a parent organization in Drupal.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<?xml version="1.0" encoding="utf-8"?> <Locations> <Location> <SCID>{F12BD0F2-DB8B-4BD0-9D29-AB21D055636F}</SCID> <LocationName>My First Location</LocationName> <Organizations> <Organization> <SCID>{5B3752FC-18B4-40F1-9A3F-9E10502AC86D}</SCID> <Name>Drupal Incorporated</Name> </Organization> <Organization> <SCID>{36DD9ECA-4697-4898-B6AD-BE95710A6565}</SCID> <Name>Agileadam LLC</Name> </Organization> </Organizations> </Location> <Location> <SCID>{5EEA5426-174D-4CE8-A190-ADD13B8C3F94}</SCID> <LocationName>My Second Location</LocationName> <Organizations> <Organization> <SCID>{36DD9ECA-4697-4898-B6AD-BE95710A6565}</SCID> <Name>Agileadam LLC</Name> </Organization> </Organizations> </Location> </Locations> |
modules/custom/pdms_migrate/config/install/migrate_plus.migration.organization.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
status: true id: organization label: Organizations migration_group: pdms source: plugin: url data_fetcher_plugin: http urls: 'modules/custom/pdms_migrate/data/sitecore_locations.xml' data_parser_plugin: xml item_selector: /Locations/Location/Organizations/Organization fields: - name: scid label: Sitecore GUID selector: SCID - name: f_organization_name label: Organization name selector: Name ids: scid: type: string process: uid: plugin: default_value default_value: 1 status: plugin: default_value default_value: 1 title: f_organization_name field_mho_sitecore_guid: scid destination: plugin: entity:node default_bundle: org migration_dependencies: { } dependencies: enforced: module: - pdms_migrate |
modules/custom/pdms_migrate/config/install/migrate_plus.migration.location.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
status: true id: location label: Locations migration_group: pdms source: plugin: url data_fetcher_plugin: http urls: 'modules/custom/pdms_migrate/data/sitecore_locations.xml' data_parser_plugin: xml item_selector: /Locations/Location fields: - name: scid label: Sitecore GUID selector: SCID - name: f_location_name label: Location name selector: LocationName - name: f_organizations label: Organizations selector: Organizations/Organization/SCID ids: scid: type: string process: uid: plugin: default_value default_value: 1 status: plugin: default_value default_value: 1 title: f_location_name field_parent_org: - plugin: pdms_migrate_skip_on_multiple source: f_organizations method: process - plugin: skip_on_empty method: process - plugin: migration_lookup migration: organization destination: plugin: entity:node default_bundle: location migration_dependencies: required: - pdms_migrate:organization dependencies: enforced: module: - pdms_migrate |
modules/custom/pdms_migrate/src/Plugin/migrate/process/SkipOnMultiple.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
<?php namespace Drupal\pdms_migrate\Plugin\migrate\process; use Drupal\migrate\MigrateSkipProcessException; use Drupal\migrate\ProcessPluginBase; use Drupal\migrate\MigrateExecutableInterface; use Drupal\migrate\Row; use Drupal\migrate\MigrateSkipRowException; /** * Skips processing current row when input value is array with count > 1. * * The pdms_migrate_skip_on_multiple process plugin checks to if the current input value * is an array with more than one value. If so, the migration will skip the * property or the entire row (depending on the chosen method). * * Available configuration keys: * - method: (optional) What to do if the input value is empty. Possible values: * - row: Skips the entire row when an array with count > 1 is encountered. * - process: Prevents further processing of the input property when the value * is an array with count > 1. * - message: (optional) A message to be logged in the {migrate_message_*} table * for this row. Messages are only logged for the 'row' method. If not set, * nothing is logged in the message table. * * Examples: * * @code * process: * field_organization: * - plugin: pdms_migrate_skip_on_multiple * method: process * source: field_organizations * - plugin: migration_lookup * migration: organizations * @endcode * * @code * process: * field_organization: * plugin: pdms_migrate_skip_on_multiple * method: row * source: field_organizations * message: 'Field field_organizations has more than one value. Skipping row.' * @endcode * * @see \Drupal\migrate\Plugin\MigrateProcessInterface * * @MigrateProcessPlugin( * id = "pdms_migrate_skip_on_multiple", * handle_multiples = TRUE * ) */ class SkipOnMultiple extends ProcessPluginBase { /** * Skips the current row when value is array with count > 1. * * @param mixed $value * The input value. * @param \Drupal\migrate\MigrateExecutableInterface $migrate_executable * The migration in which this process is being executed. * @param \Drupal\migrate\Row $row * The row from the source to process. * @param string $destination_property * The destination property currently worked on. This is only used together * with the $row above. * * @return mixed * The input value, $value, if it is not empty. * * @throws \Drupal\migrate\MigrateSkipRowException * Thrown if the source property is not set and the row should be skipped, * records with STATUS_IGNORED status in the map. */ public function row( $value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property ) { if (is_array($value) && count($value) > 1) { $message = !empty($this->configuration['message']) ? $this->configuration['message'] : ''; throw new MigrateSkipRowException($message); } return $value; } /** * Stops processing the current property when value is array with count > 1. * * @param mixed $value * The input value. * @param \Drupal\migrate\MigrateExecutableInterface $migrate_executable * The migration in which this process is being executed. * @param \Drupal\migrate\Row $row * The row from the source to process. * @param string $destination_property * The destination property currently worked on. This is only used together * with the $row above. * * @return mixed * The input value, $value, if it is not empty. * * @throws \Drupal\migrate\MigrateSkipProcessException * Thrown if the source property is not set and rest of the process should * be skipped. */ public function process( $value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property ) { if (is_array($value) && count($value) > 1) { throw new MigrateSkipProcessException(); } return $value; } } |