Category Technology
Publication date
27 October 2009

Migrate module: file handling

UPDATE: In the latest version of the migrate module, the hook names have changed - the word 'destination' has been removed.

So you're migrating pages and users from another CMS to Drupal using the Migrate module, but how do you handle all those file attachments? This example will cover taking the input filename and adding it to an imagefield on a Drupal content type. However, this should work in exactly the same way for filefields too.

The first thing you need to do is to take all files to be migrated and place them in your site's files directory. If you plan on using the migrate module's "clear imported records" feature, so as to do multiple test runs, you should retain a backup of these files as when the nodes are cleared / deleted, so are the files.

Create the CCK content type and add an imagefield to it to store the migrated image. Then add a content set to map the source content fields to their Drupal equivalents. When configuring the content set, you will see three fields for your image: "fid", "list" and "data". We're going to ignore these and instead set the field value using the hook_migrate_destination_prepare_node().

<?php
function mymodule_migrate_destination_prepare_node(&$node, $tblinfo, $row) {
  $extensions = variable_get('upload_extensions_default', 'jpg jpeg gif png txt html doc xls pdf ppt pps odt ods odp');
  if ($node->type == 'news') {
    $filepath = 'sites/all/files/images/'. $row->cms_news_table_image;

    // Ensure the file exists.
    if (file_exists(file_create_path($filepath))) {
      // Check if the file exists in the 'files' table already.
      $file = db_fetch_object(db_query("SELECT * FROM {files} WHERE filepath = '%s'", $filepath));

      // Create the file entry in the 'files' table if necessary.
      if (!$file->fid) {
        $file = new stdClass;
        $file->filepath = $filepath;
        $file->filename = file_munge_filename(basename($file->filepath), $extensions);
        $file->filemime = file_get_mimetype($file->filename);
        $file->uid = 1;
        $file->status = 1;
        $file->timestamp = $node->created;
        $file->filesize = filesize($file->filepath);
        drupal_write_record('files', $file);
      }

      // Set up the image field.
      $node->field_news_image[0] = array(
        'fid' => $file->fid,
        'list' => 1,
        'data' => array('alt' => $node->title, 'title' => $node->title, 'description' => $node->title),
        'uid' => $node->uid,
        'filename' => $file->filename,
        'filepath' => $file->filepath,
        'filemime' => $file->filemime,
        'status' => 1,
        'timestamp' => $node->created,
      );

    }
    // Print an error message if the file doesn't exist.
    else {
      drupal_set_message(t('Failed to find file: %file', array('%file' => $filepath)), 'error');
    }
  }
}
?>

In our example, we used a content type called "news" with a field_news_image imagefield, while the column containing the image filename in the source CMS is cms_news_table_image.

The hook_migrate_destination_prepare_node() hook is invoked just before each node record is migrated, allowing the module to manipulate the node data, one row at a time, immediately before it is stored to Drupal's database.

For each row, we check that the file we wish to migrate exists in the "files" directory and create a record for it in Drupal's files table if one doesn't already exist. Finally we configure the field_news_image field with all the required information.

Profile picture for user Stella Power

Stella Power Managing Director

As well as being the founder and managing director of Annertech, Stella is one of the best known Drupal contributors in the world.