0

I need to import a set of authors as part of a content entity. It is an array in a JSON object of id/name. I have a field in Drupal on the content type to be a user reference that accepts unlimited cardinality.

First of all, I don't know these users ahead of time, no way to query it, so I cannot just create a migration dependency and do that first. This seems to be a popular answer, but doesn't fit any of my use cases.

Second, I think you should be able to take the source data and loop each one, and create a user stub if they do not exist already. How do you do that? If the user does not exist yet they should be created, if they do exist, just look up the uid and put it into the target id per row.

This won't be the only spot I run into this, I will have content related to content that I will need to stub too. I won't know the latter content until I run their migrations later.

Is this even possible in D8?

2 Answers 2

3

Yes. This use scenario is covered by migration_lookup plugin with its stub_id property and making sure it's referenced migration (in your case, a user migration sourced from the JSON array) has defined all the required fields via the default_value plugin such that migration_lookup can rely on it to stub out a user before the stub_id migration can be run on its own to fill in fields for each referenced entity.

3
  • Is there an example of this?
    – Kevin
    Mar 8, 2019 at 23:43
  • I got it! That took longer than it should have but migration_lookup stubbed the user since it does not exist, then my other migration filled in the user objects.
    – Kevin
    Mar 11, 2019 at 19:23
  • Yeah, I didn't have examples other than the linked docs. If you want to bolster your question with an example migration(s), I can bolster the answer using your question example code as an example.
    – Shawn Conn
    Mar 11, 2019 at 22:39
-1

Hey @Kevin here is complex example of looking/stubbing entities which involves creating custom source/process plugins:

  field_background_media:
    - plugin: sub_process
      source: field_background_media
      include_source: true # not required for this example
      source_key: root # not required for this example
      process:
        _migration:
          plugin: static_map
          source: bundle
          map:
            image: migrate_media__image
            video: migrate_media__video
        target_id:
          plugin: dynamic_migration_lookup
          migration: '@_migration'
          source: target_id
          source_ids: # not required for this example
            migrate_media__image:
              - target_id
              - root/langcode
            migrate_media__video:
              - target_id
              - root/langcode

The context.

I have an entity reference field that references two media types. The migration_lookup plugin can't get migration id from source/destination properties, it operates on static migration id.

The key idea to get somehow media type and map it with specific migration id.

You can find I'm using bundle source property to build up _migration property.

I'm populating bundle property in my custom source plugin:

  public function prepareRow(Row $row) {
    $result = parent::prepareRow($row);

    if (!$result) {
      return $result;
    }

    $media_references = $row->getSourceProperty('field_background_media');
    if (!empty($media_references)) {
      foreach ($media_references as &$value) {
        // Find media type by target_id
        $bundle = $this->getReferencedMediaType($value['target_id']);
        if (!$bundle) {
          continue;
        }
        $changed = TRUE;
        $value['bundle'] = $bundle;
      }
    }

    if ($changed) {
      $row->setSourceProperty('field_background_media', $media_references);
    }
    return $result;
  }

  protected function getReferencedMediaType(int $media_id): ?string {
    $query = $this
      ->select('media', 'm')
      ->condition('mid', $media_id);
    $query->addField('m', 'bundle');
    return $query->execute()->fetchField();
  }

Then after static_map plugin has filled up _migration property I can tell which migration exactly should be used for the lookup/stub process.

In order to use value from _migration property as lookup_migration_id in migration_lookup plugin I've created sub-class for it:

use Drupal\migrate\Plugin\migrate\process\MigrationLookup;

/** 
 * @MigrateProcessPlugin(
 *   id = "dynamic_migration_lookup"
 * )
 */
class DynamicMigrationLookup extends MigrationLookup {

  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
    $lookup_migration_id = $row->get($this->configuration['migration']);
    $this->configuration['migration'] = $lookup_migration_id;
    return parent::transform($value, $migrate_executable, $row, $destination_property);
  }

}

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.