Khanh Hoang - Kenn
Kenn is a user experience designer and front end developer who enjoys creating beautiful and usable web and mobile experiences.
Migrate in Drupal 7 didn't explicitly have the concept of a process plugin but under the hood you were using the "Get" process plugin when you wrote code like $this->addFieldMapping('source', 'destination');
The Drupal 8 Migrate API has taken advantage of the new plugin system to provide a flexible way to process fields. In core, we already have a handful of process plugin examples including the Get plugin. I wouldn't look at the Get plugin for a simple example however.
The purpose of a process plugin is simply to take a value in and spit a new value out. The plugin can transform the data in anyway it sees fit but if you are following best practices you should ensure that a plugin does only one thing, definitely lean towards multiple process plugins as needed. From our experience so far, process plugins are usually quite simple and often less than 10 lines of code.
Let's take a look at the FileUri plugin. modules/migrate/lib/Drupal/migrate_drupal/Plugin/migrate_drupal/process/FileUri.php
<?php namespace Drupal\migrate_drupal\Plugin\migrate\process\d6; use Drupal\migrate\MigrateException; use Drupal\migrate\MigrateExecutable; use Drupal\migrate\ProcessPluginBase; use Drupal\migrate\Row; /** * Process the file url into a D8 compatible URL. * * @MigrateProcessPlugin( * id = "file_uri" * ) */ class FileUri extends ProcessPluginBase { /** * {@inheritdoc} */ public function transform($value, MigrateExecutable $migrate_executable, Row $row, $destination_property) { list($filepath, $file_directory_path, $is_public) = $value; // Strip the files path from the uri instead of using basename // so any additional folders in the path are preserved. $uri = preg_replace('/^' . preg_quote($file_directory_path, '/') . '/', '', $filepath); return $is_public ? "public://$uri" : "private://$uri"; } } ?>
Ignoring the namespace and the use statements which we've all seen before, the first thing of interest is the annotation. Identical to other plugins throughout core, we simply have to define the id key on top of our class and we have a valid migration process plugin.
ProcessPluginBase which we're extending in the above example implements the MigrateProcessInterface. This gives us the transform method which we must implement. The transform method is passed the fields specified in the YAML, transforms the value and return the new data. And that's all there is to it, easy right?
Now lets look at how we use the plugin in our YAML.
id: d6_file source: plugin: d6_file process: filename: filename uri: plugin: file_uri source: - filepath - file_directory_path - is_public filemime: filemime filesize: filesize status: status changed: timestamp destination: plugin: entity:file
This is an entire migration (cool right?) but we're only interested specifically in:
uri: plugin: file_uri source: - filepath - file_directory_path - is_public
The above piece of YAML says, set the destination key uri to the return value of the file_uri plugin which takes an array containing the filepath, file_directory_path and is_public values from the source. Process plugins will run for every row in the source and calculate the required new value for the field they're applied to.
One thing you should be aware of is that the migration process is a pipeline. That is, previously calculated values are passed onto the next process so we can chain plugins. Let's take a look.
process: id: - plugin: machine_name source: name - plugin: dedupe_entity entity_type: user_role field: id - plugin: user_update_8002
The above snippet was taken from the Drupal 6 to Drupal 8 user role migration and uses a combination of three process plugins to calculate the required value for the id key. You can read more about the pipeline in the drupal.org documentation.