You are here

public function MigrateFileFieldHandler::prepare in Migrate 6.2

Prepare file data for saving as a Field API file field. The job of this handler is to make sure the file itself ends up in the right place, the files table row is set up, and the files array returned for each file.

Return value

array Field API array suitable for inserting in the destination object.

File

plugins/destinations/fields.inc, line 269
Support for processing CCK fields

Class

MigrateFileFieldHandler

Code

public function prepare($entity, array $instance, array $values) {
  $migration = Migration::currentMigration();
  $return = array();
  $arguments = $values['arguments'];
  unset($values['arguments']);

  // One can override a file_function via CLI or drushrc.php
  if ($migration
    ->getOption('file_function')) {
    $file_function = $migration
      ->getOption('file_function');
  }
  else {
    $file_function = $arguments['file_function'];
  }
  foreach ($values as $delta => $file_path) {
    if (!$file_path) {
      continue;
    }

    // Handle JSON input
    if ($file_path[0] == '{') {
      $properties = json_decode($file_path, TRUE);
      $file_path = $properties['path'];

      // Properties passed in with the image override any set via arguments
      if (!empty($properties['alt'])) {
        $arguments['alt'] = $properties['alt'];
      }
      if (!empty($properties['title'])) {
        $arguments['title'] = $properties['title'];
      }
      if (!empty($properties['description'])) {
        $arguments['description'] = $properties['description'];
      }
      if (!empty($properties['list'])) {
        $arguments['list'] = $properties['list'];
      }
    }
    $message_saved = FALSE;
    if ($arguments['source_path']) {
      $full_path = rtrim($arguments['source_path'], "/\\") . '/' . ltrim($file_path, "/\\");
    }
    else {
      $full_path = $file_path;
    }

    // Set destination_dir, considering user tokens which filefield natively supports.
    // Also load $account or build a stub (faster)
    $account = user_load(array(
      'uid' => $entity->uid,
    ));
    if (!module_exists('filefield_paths') && isset($entity->uid) && strpos($instance['widget']['file_path'], '[')) {
      $destination_dir = filefield_widget_file_path($instance, $account);
    }
    else {

      // Set a default destination_dir.
      $destination_dir = file_directory_path() . '/' . $instance['widget']['file_path'];
    }

    // file_check_directory does not do $recursive so we create dir ourselves.
    @mkdir($destination_dir, 0777, TRUE);
    $destination_file = rtrim($destination_dir, "/\\") . '/' . basename($full_path);
    migrate_instrument_start('MigrateFileFieldHandler file_function');
    switch ($file_function) {

      // These physically transfer the file to the destination, applying
      // the file_replace setting if the file already exists
      case 'file_copy':
      case 'file_move':
        $remote = FALSE;

        // Check that source exists. If not, mark the entity as 'needs_update' and bail.
        // Sometimes the source file arrives later, when rsync is slower than DB.
        if (!is_file($full_path)) {

          // is_file() won't handle URLs, check to see if we have a remote file
          // (only relevant in the file_copy case)
          if ($file_function == 'file_copy') {
            $headers = @get_headers($full_path);
            if (is_array($headers) && preg_match('%^HTTP/[0-9]\\.[0-9] 200 OK$%', $headers[0])) {
              $remote = TRUE;
            }
          }
          if (!$remote) {
            $message = t('Source file does not exist: !path', array(
              '!path' => $full_path,
            ));
            if ($arguments['throw_error']) {
              throw new MigrateException($message, MigrationBase::MESSAGE_ERROR);
            }
            else {
              $migration
                ->saveMessage($message, MigrationBase::MESSAGE_INFORMATIONAL);
            }
            $message_saved = TRUE;
            $migration->needsUpdate = MigrateMap::STATUS_NEEDS_UPDATE;
            continue;
          }
        }

        // TODO: FILE_EXISTS_REPLACE is hardcoded
        // TODO: Should retrieve and pass validators in 2nd arg
        if ($remote) {
          $temporary_file = file_directory_temp() . "/" . basename($full_path);
          $result = @copy($full_path, $temporary_file);
          if ($result) {
            $file = field_file_save_file($temporary_file, array(), $destination_dir, $account);
            file_delete($temporary_file);
          }
          else {
            $migration
              ->saveMessage(t('Unable to copy file from !source', array(
              '!source' => $source->uri,
            )));
          }
        }
        else {
          $file = field_file_save_file($full_path, array(), $destination_dir, $account);
          if ($file_function == 'file_move') {

            // TODO: Optimize by using rename()
            unlink($full_path);
          }
        }
        break;
      case 'file_fast':
        static $fid;

        // Keep re-using an existing file.
        if (!isset($fid)) {
          $full_path = 'misc/druplicon.png';
          $file = field_file_save_file($full_path, array(), $destination_dir, $account);

          //          $file = file_copy($source, $destination_dir, FILE_EXISTS_RENAME);
          $fid = $file['fid'];
        }
        else {
          $file = array(
            'fid' => $fid,
          );
        }
        break;
      case 'file_link':

        // The file is copied by some outside process (e.g., rsync), and we
        // just need to make sure it's present and has a files table row.
        // Not present - skip
        migrate_instrument_start('file_link: file_exists');
        if (!file_exists($full_path)) {
          migrate_instrument_stop('file_link: file_exists');
          $message = t('File does not exist in Drupal files directory: !path', array(
            '!path' => $full_path,
          ));
          if ($arguments['throw_error']) {
            throw new MigrateException($message, MigrationBase::MESSAGE_ERROR);
          }
          else {
            $migration
              ->saveMessage($message, MigrationBase::MESSAGE_INFORMATIONAL);
          }
          $message_saved = TRUE;

          // TODO     $migration->needsUpdate = MigrateMap::STATUS_NEEDS_UPDATE;
          continue;
        }
        migrate_instrument_stop('file_link: file_exists');

        // Files table entry exists? Use that...
        migrate_instrument_start('file_link: select existing');

        // Note that indexing files.filepath can be very helpful.
        $file = db_select('files', 'f')
          ->fields('f')
          ->condition('filepath', $full_path)
          ->execute()
          ->fetchAssoc();
        migrate_instrument_stop('file_link: select existing');
        if (!$file) {
          migrate_instrument_start('file_link: create file record');
          $file = new stdClass();
          $file->uri = $full_path;
          $file->uid = isset($entity->uid) ? $entity->uid : 0;
          $file->filename = basename($full_path);
          $file->filepath = $full_path;
          $file->filemime = file_get_mimetype($full_path);
          $file->timestamp = $_SERVER['REQUEST_TIME'];
          $file->filesize = filesize($full_path);
          $file->status = FILE_STATUS_PERMANENT;
          drupal_write_record('files', $file);
          $file = (array) $file;
          migrate_instrument_stop('file_link: create file record');
        }
        break;
      default:
        $migration
          ->saveMessage(t('Unrecognized file_function: !func', array(
          '!func' => $file_function,
        )));
        $message_saved = TRUE;
        break;
    }
    migrate_instrument_stop('MigrateFileFieldHandler file_function');
    if (isset($file) && is_array($file)) {

      // Build up a return object.
      $file['list'] = isset($arguments['list']) ? $arguments['list'] : NULL;
      $file['data'] = array(
        'alt' => isset($arguments['alt']) ? $arguments['alt'] : NULL,
        'title' => isset($arguments['title']) ? $arguments['title'] : NULL,
        'description' => isset($arguments['description']) ? $arguments['description'] : NULL,
        'process' => TRUE,
      );
      $return[] = $file;
    }
    elseif (!$message_saved) {
      throw new MigrateException(t('Unable to create file record for !path', array(
        '!path' => $full_path,
      )), Migration::MESSAGE_ERROR);
    }
  }
  return $return;
}