1

I know I can use sub_process to iterate over an associative array like

field_categories:
  plugin: sub_process
  source: remote_categories
  process:
    target_id:
      plugin: migration_lookup
      migration: my_existing_taxonomy_migration
      source: name_of_key

But I don't know how to iterate over a numeric / non-associative array. Assume the JSON data structure

{
  remote_categories: [ 'alpha', 'beta', 'gamma' ]
}

how can I pass the values as keys to migration_lookup? I.e. what would be name_of_key in the example above?

2

2 Answers 2

10

I've written a process plugin that transforms a sequential list into an array of associative sub-arrays, so sub_process and migration_lookup can use them.

namespace Drupal\my_module\Plugin\migrate\process;

use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\MigrateException;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Row;

/**
 * Transforms an array of values into an array of associative arrays.
 *
 * The inner array will be filled with one key. E.g. ['alpha', 'beta'] becomes
 * [[value => 'alpha'], [value => 'beta']]
 *
 * Use this plugin to preprocess a numeric/non-associative array for other
 * plugins that requires an associative array as input, such as the sub_process
 * plugin.
 *
 * Available configuration keys:
 * - source: Source property.
 * - keyname: name of the key to be used for the associative sub-arrays,
 *   defaults to 'value'.
 *
 * Example:
 *
 * @code
 * source:
 *   my_flat_array:
 *     - category1
 *     - category2
 * process:
 *   my_associative_array:
 *     plugin: deepen
 *     source: my_flat_array
 *   field_taxonomy_term:
 *     plugin: sub_process
 *     source: '@my_associative_array'
 *     process:
 *       target_id:
 *         plugin: migration_lookup
 *         migration: my_taxonomy_migration
 *         source: value
 * @endcode
 *
 * @see \Drupal\migrate\Plugin\MigrateProcessInterface
 *
 * @MigrateProcessPlugin(
 *   id = "deepen",
 *   handle_multiples = TRUE
 * )
 */
class Deepen extends ProcessPluginBase {

  /**
   * {@inheritdoc}
   */
  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
    $keyname = (is_string($this->configuration['keyname']) && $this->configuration['keyname'] != '') ? $this->configuration['keyname'] : 'value';

    if (is_array($value) || $value instanceof \Traversable) {
      $result = [];
      foreach ($value as $sub_value) {
        $result[] = [$keyname => $sub_value];
      }
      return $result;
    }
    else {
      throw new MigrateException(sprintf('%s is not traversable', var_export($value, TRUE)));
    }
  }

}
1
  • 1
    Wow, very illuminating. I just ran into this myself dealing with an API that does not consistently return array data in the way sub process would want it.
    – Kevin
    Commented Mar 12, 2019 at 20:56
0

I have had success in two different ways. I found your question because I wanted "sub_process" to "key" my string value into an array, so it goes into a specific property on the field, not the default property.

  field_categories:
    -
      plugin: multiple_values
      source: remote_categories
    -
      plugin: migration_lookup
      migration: my_existing_taxonomy_migration
    -
      plugin: skip_on_empty
      method: process
      message: 'Migrate lookup failed, or no value passed!'
    -
      plugin: explode
      delimiter: 'StringThatShoudNotExistIntheValue'
    -
      plugin: sub_process
      process:
        target_id: '0'

Alternative method without sub_process (but will runs a process for each value).

  field_categories:
    -
      plugin: multiple_values
      source: remote_categories
    -
      plugin: migration_lookup
      migration: my_existing_taxonomy_migration
    -
      plugin: skip_on_empty
      method: process
      message: 'Migrate lookup failed, or no value passed!'

The explode() just casts the string of each array element into a array [0 => $value], then we use sub_process with target_id: 0 to key by the first/0-th element (which is $value).

The skip_on_empty is there for sanity check but is optional.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.