You are here

function system_update_7061 in Drupal 7

Migrate upload.module data to the newly created file field.

Related topics

File

modules/system/system.install, line 2872
Install, update and uninstall functions for the system module.

Code

function system_update_7061(&$sandbox) {
  if (!db_table_exists('upload')) {
    return;
  }
  if (!isset($sandbox['progress'])) {

    // Delete stale rows from {upload} where the fid is not in the {files} table.
    db_delete('upload')
      ->notExists(db_select('files', 'f')
      ->fields('f', array(
      'fid',
    ))
      ->where('f.fid = {upload}.fid'))
      ->execute();

    // Delete stale rows from {upload} where the vid is not in the
    // {node_revision} table. The table has already been renamed in
    // node_update_7001().
    db_delete('upload')
      ->notExists(db_select('node_revision', 'nr')
      ->fields('nr', array(
      'vid',
    ))
      ->where('nr.vid = {upload}.vid'))
      ->execute();

    // Retrieve a list of node revisions that have uploaded files attached.
    // DISTINCT queries are expensive, especially when paged, so we store the
    // data in its own table for the duration of the update.
    if (!db_table_exists('system_update_7061')) {
      $table = array(
        'description' => t('Stores temporary data for system_update_7061.'),
        'fields' => array(
          'vid' => array(
            'type' => 'int',
            'not null' => TRUE,
          ),
        ),
        'primary key' => array(
          'vid',
        ),
      );
      db_create_table('system_update_7061', $table);
    }
    $query = db_select('upload', 'u');
    $query
      ->distinct();
    $query
      ->addField('u', 'vid');
    db_insert('system_update_7061')
      ->from($query)
      ->execute();

    // Retrieve a list of duplicate files with the same filepath. Only the
    // most-recently uploaded of these will be moved to the new {file_managed}
    // table (and all references will be updated to point to it), since
    // duplicate file URIs are not allowed in Drupal 7.
    // Since the Drupal 6 to 7 upgrade path leaves the {files} table behind
    // after it's done, custom or contributed modules which need to migrate
    // file references of their own can use a similar query to determine the
    // file IDs that duplicate filepaths were mapped to.
    $sandbox['duplicate_filepath_fids_to_use'] = db_query("SELECT filepath, MAX(fid) FROM {files} GROUP BY filepath HAVING COUNT(*) > 1")
      ->fetchAllKeyed();

    // Initialize batch update information.
    $sandbox['progress'] = 0;
    $sandbox['last_vid_processed'] = -1;
    $sandbox['max'] = db_query("SELECT COUNT(*) FROM {system_update_7061}")
      ->fetchField();
  }

  // Determine vids for this batch.
  // Process all files attached to a given revision during the same batch.
  $limit = variable_get('upload_update_batch_size', 100);
  $vids = db_query_range('SELECT vid FROM {system_update_7061} WHERE vid > :lastvid ORDER BY vid', 0, $limit, array(
    ':lastvid' => $sandbox['last_vid_processed'],
  ))
    ->fetchCol();

  // Retrieve information on all the files attached to these revisions.
  if (!empty($vids)) {
    $node_revisions = array();
    $result = db_query('SELECT u.fid, u.vid, u.list, u.description, n.nid, n.type, u.weight FROM {upload} u INNER JOIN {node_revision} nr ON u.vid = nr.vid INNER JOIN {node} n ON n.nid = nr.nid WHERE u.vid IN (:vids) ORDER BY u.vid, u.weight, u.fid', array(
      ':vids' => $vids,
    ));
    foreach ($result as $record) {

      // For each uploaded file, retrieve the corresponding data from the old
      // files table (since upload doesn't know about the new entry in the
      // file_managed table).
      $file = db_select('files', 'f')
        ->fields('f', array(
        'fid',
        'uid',
        'filename',
        'filepath',
        'filemime',
        'filesize',
        'status',
        'timestamp',
      ))
        ->condition('f.fid', $record->fid)
        ->execute()
        ->fetchAssoc();
      if (!$file) {
        continue;
      }

      // If this file has a duplicate filepath, replace it with the
      // most-recently uploaded file that has the same filepath.
      if (isset($sandbox['duplicate_filepath_fids_to_use'][$file['filepath']]) && $record->fid != $sandbox['duplicate_filepath_fids_to_use'][$file['filepath']]) {
        $file = db_select('files', 'f')
          ->fields('f', array(
          'fid',
          'uid',
          'filename',
          'filepath',
          'filemime',
          'filesize',
          'status',
          'timestamp',
        ))
          ->condition('f.fid', $sandbox['duplicate_filepath_fids_to_use'][$file['filepath']])
          ->execute()
          ->fetchAssoc();
      }

      // Add in the file information from the upload table.
      $file['description'] = $record->description;
      $file['display'] = $record->list;

      // Create one record for each revision that contains all the uploaded
      // files.
      $node_revisions[$record->vid]['nid'] = $record->nid;
      $node_revisions[$record->vid]['vid'] = $record->vid;
      $node_revisions[$record->vid]['type'] = $record->type;
      $node_revisions[$record->vid]['file'][LANGUAGE_NONE][] = $file;
    }

    // Now that we know which files belong to which revisions, update the
    // files'// database entries, and save a reference to each file in the
    // upload field on their node revisions.
    $basename = variable_get('file_directory_path', conf_path() . '/files');
    $scheme = file_default_scheme() . '://';
    foreach ($node_revisions as $vid => $revision) {
      foreach ($revision['file'][LANGUAGE_NONE] as $delta => $file) {

        // We will convert filepaths to URI using the default scheme
        // and stripping off the existing file directory path.
        $file['uri'] = $scheme . preg_replace('!^' . preg_quote($basename) . '!', '', $file['filepath']);

        // Normalize the URI but don't call file_stream_wrapper_uri_normalize()
        // directly, since that is a higher-level API function which invokes
        // hooks while validating the scheme, and those will not work during
        // the upgrade. Instead, use a simpler version that just assumes the
        // scheme from above is already valid.
        if (($file_uri_scheme = file_uri_scheme($file['uri'])) && ($file_uri_target = file_uri_target($file['uri']))) {
          $file['uri'] = $file_uri_scheme . '://' . $file_uri_target;
        }
        unset($file['filepath']);

        // Insert into the file_managed table.
        // Each fid should only be stored once in file_managed.
        db_merge('file_managed')
          ->key(array(
          'fid' => $file['fid'],
        ))
          ->fields(array(
          'uid' => $file['uid'],
          'filename' => $file['filename'],
          'uri' => $file['uri'],
          'filemime' => $file['filemime'],
          'filesize' => $file['filesize'],
          'status' => $file['status'],
          'timestamp' => $file['timestamp'],
        ))
          ->execute();

        // Add the usage entry for the file.
        $file = (object) $file;
        file_usage_add($file, 'file', 'node', $revision['nid']);

        // Update the node revision's upload file field with the file data.
        $revision['file'][LANGUAGE_NONE][$delta] = array(
          'fid' => $file->fid,
          'display' => $file->display,
          'description' => $file->description,
        );
      }

      // Write the revision's upload field data into the field_upload tables.
      $node = (object) $revision;
      _update_7000_field_sql_storage_write('node', $node->type, $node->nid, $node->vid, 'upload', $node->file);

      // Update our progress information for the batch update.
      $sandbox['progress']++;
      $sandbox['last_vid_processed'] = $vid;
    }
  }

  // If less than limit node revisions were processed, the update process is
  // finished.
  if (count($vids) < $limit) {
    $finished = TRUE;
  }

  // If there's no max value then there's nothing to update and we're finished.
  if (empty($sandbox['max']) || isset($finished)) {
    db_drop_table('upload');
    db_drop_table('system_update_7061');
    return t('Upload module has been migrated to File module.');
  }
  else {

    // Indicate our current progress to the batch update system.
    $sandbox['#finished'] = $sandbox['progress'] / $sandbox['max'];
  }
}