Try this one weird trick with the Migrate API

Image

One weird introduction

One of the key concepts of the Drupal Migrate API is the so-called process pipeline, in which we pass a value that is transformed by a series of process plugins. From time to time we find ourselves in the middle of a process pipeline wishing we could easily reference the current value in the process pipeline. I even created an issue on Drupal.org asking for this feature. As it turns out, the feature already exists! That is, as long as you know this one weird trick...

One weird trick

How do you reference the current value of the process pipeline? Use null as the source. Seriously!

One weird example

Consider the following process pipeline:

process:
  field_my_field:
    - plugin: callback
      callable: strtolower
      source: my_source_string
    - plugin: concat
      source:
        - null
        - null
      delimiter: +

If the value of my_source_string is Drupal, the value of field_my_field will be drupal+drupal.

You could try that out in Migrate Sandbox.

What's more, one can use a tilde (~) within YAML to indicate a null value. That means we can use ~ in place of null when specifying the source:

process:
  field_my_field:
    - plugin: callback
      callable: strtolower
      source: my_source_string
    - plugin: concat
      source:
        - ~
        - ~
      delimiter: + 

That gives us the same result. This syntax is particularly satisfying because ~ resembles water flowing through a pipeline!

One weird explanation

In case you're curious as to why that works, we need to look at a few lines of the Get process plugin.

public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
  $source = $this->configuration['source'];
  $properties = is_string($source) ? [$source] : $source;
  $return = [];
  foreach ($properties as $property) {
    if ($property || (string) $property === '0') {
      $return[] = $row->get($property);
    }
    else {
      $return[] = $value;
    }
  }
...
}

If the process plugin is configured with a source and the configured value is null, that else block runs. Whatever value was passed to the plugin is returned. Wait, we never used get though, did we? It turns out that any time the source is configured, an instance of the get plugin gets thrown into the pipeline automatically. So indeed the weird explanation is pretty weird, perhaps so weird that it's not worth the effort to understand.

Is this trick a good idea?

I reported this behavior to the current maintainers of the Migrate API and it was news to them. Indeed, the behavior is not documented in get and doesn't appear to be documented anywhere else. So is this a feature or a bug? I've heard it said that an undocumented feature is a bug. I'm personally leaning toward glitch, like Minus World in Super Mario Bros. Whatever you call it, this one weird trick may be just what you need in your next migration.