Updated on June 20, 2022

Now that you've completed the migration of academic program nodes as mentioned in part 1 of this series and the migration of taxonomy terms as mentioned in part 2, this article focuses on the third requirement.

We have images for each academic program. The base name of the images is mentioned in the CSV data source for academic programs. To make things easy, we have only one image per program. 

This article assumes:

  • You have read the first part of this article series on migrating basic data.
  • You are able to write basic entity migrations.
  • You understand how to write multiple process plugins in migrations.

👩‍💻 Get up to speed on Drupal 9! Watch Evolving Web and Pantheon's webinar on Drupal 9 migrations.


The Drupal Migration Series


Though the problem might sound complex, the solution is as simple as following two steps.

Step 1: Import images as "file" entities

First we need to create file entities for each file. This is because Drupal treats files as file entities which have their own ID. Then Drupal treats node-file associations as entity references, referring to the file entities with their IDs.

We create the file entities in the migrate_plus.migration.program_image.yml file, but this time, using some other process plugins. We re-use the program.data.csv file to import the files, so the source definition again uses the CSV plugin. We specify the key parameter in source as the column containing file names, ie, Image file. This way, we would be refer to these files in other migrations using their names, eg, engineering.png.

keys:
  - Image file

Apart from that, we use some constants to refer to source and destination paths for the images.

constants:
  file_source_uri: public://import/program
  file_dest_uri: 'public://program/image'

file_source_uri is used to refer to the path from which files are to be read during the import, and file_dest_uri is used to refer to the destination path where files should be copied to. The newly created file entities would refer to files stored in this directory. The public:// URI refers to the files directory inside the site in question. This is where all public files related to the site are stored.

file_source:
  -
    plugin: concat
    delimiter: /
    source:
      - constants/file_source_uri
      - Image file
  -
    plugin: urlencode
file_dest:
  -
    plugin: concat
    delimiter: /
    source:
      - constants/file_dest_uri
      - Image file
  -
    plugin: urlencode

Where do we use these constants? In the process element, we prepare two paths - the file source path (file_source) and the file destination path (file_dest).

  • file_source is obtained by concatenating the file_source_uri with the Image file column which stores the file's basename. Using delimiter: / we tell the migrate module to join the two strings with a / (slash) in between to ensure we have a valid file name. In short, we do file_source_uri . '/' . basename using the concat plugin.
  • file_dest, in a similar way, is file_dest_uri . '/' . basename. This is where we utilize the constants we defined in the source element.

Now, we use the file_source and file_dest paths generated above with plugin: file_copy. The file_copy plugin simply copies the files from the file_source path to the file_dest path. All the steps we did above were just for being able to refer to complete file source and destination paths during the process of copying files. The file gets copied and the uri property gets populated with the destination file path.

uri:
  plugin: file_copy
  source:
    - '@file_source'
    - '@file_dest'

We also use the existing file names as names of the newly created files. We do this using a direct assignment of the Image file column to the filename property as follows:

filename: Image file

Finally, since the destination of the migration is entity:file, the migrate module would use the filename and uri properties to generate a file entity, thereby generating a unique file ID.

Step 2: Associate files to academic programs

Once the heavy-lifting is done and we have our file entities, we need to put the files to use by associating them to academic programs. To do this, we add processing instructions for file_image in migrate_plus.migration.program_data.yml. Just like we did for taxonomy terms, we tell the migrate module that the Image file column contains a unique file name, which refers to a file entity created during the program_image migration. We assign these file references to the field_image/target_id property since file associations are also treated as entity references in Drupal.

'field_image/target_id':
  plugin: migration_lookup
  migration: program_image
  source: Image file

However, in the data-source for academic program data, we see a column named Image alt as well. Can we migrate these as well? We can! With an additional line of YAML.

'field_image/alt': Image alt

And we are done! If you update the configuration introduced by the c11n_migrate module and run the migration with the command drush config-import --partial --source=sites/sandbox.com/modules/c11n_migrate/config/install -y && drush migrate-import --group=c11n --update -y, you should see the following output::

$ drush mi --group=c11n --update -y
Processed 8 items (0 created, 8 updated, 0 failed, 0 ignored) - done with 'program_tags'
Processed 4 items (4 created, 0 updated, 0 failed, 0 ignored) - done with 'program_image'
Processed 4 items (0 created, 4 updated, 0 failed, 0 ignored) - done with 'program_data'

To make sure that tag data is imported and available during the academic program migration, we specify the program_image migration in the migration_dependencies for the program_data migration. Now, when you run these migrations, the image files get associated to the academic program nodes.

Migrated image visible in UI
Migrated image visible in UI.

Next steps

This is part three in a series of three articles on migrating data in Drupal. If you missed it, go back and read part one: Migration basics or part two: Migrating taxonomy terms and term references.