Index: modules/node/node.install =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.install,v retrieving revision 1.46 diff -u -r1.46 node.install --- modules/node/node.install 28 Mar 2010 11:16:29 -0000 1.46 +++ modules/node/node.install 21 Apr 2010 01:18:11 -0000 @@ -413,6 +413,9 @@ $dependencies['system'][7050] = array( 'node' => 7006, ); + $dependencies['system'][7053] = array( + 'node' => 7006, + ); return $dependencies; } Index: modules/system/system.install =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.install,v retrieving revision 1.461 diff -u -r1.461 system.install --- modules/system/system.install 10 Apr 2010 17:30:15 -0000 1.461 +++ modules/system/system.install 21 Apr 2010 01:18:11 -0000 @@ -2188,27 +2188,7 @@ * Migrate upload module files to the new {file_managed} table. */ function system_update_7035() { - if (!db_table_exists('upload')) { - return; - } - - // The old {files} tables still exists. We migrate core data from upload - // module, but any contrib module using it will need to do its own update. - $result = db_query('SELECT f.fid, uid, filename, filepath AS uri, filemime, filesize, status, timestamp FROM {files} f INNER JOIN {upload} u ON u.fid = f.fid', array(), array('fetch' => PDO::FETCH_ASSOC)); - - // We will convert filepaths to uri using the default schmeme - // and stripping off the existing file directory path. - $basename = variable_get('file_directory_path', conf_path() . '/files'); - $scheme = variable_get('file_default_scheme', 'public') . '://'; - $fids = array(); - // TODO: does this function need to run in batch mode, or should we use a multi-insert? - foreach ($result as $file) { - $file['uri'] = $scheme . str_replace($basename, '', $file['uri']); - $file['uri'] = file_stream_wrapper_uri_normalize($file['uri']); - db_insert('file_managed')->fields($file)->execute(); - $fids[] = $file['fid']; - } - // TODO: delete the found fids from {files}? + // Update merged into system_update_7053(). } /** @@ -2397,6 +2377,210 @@ db_change_field('menu_router', 'file', 'include_file', array('type' => 'text', 'size' => 'medium')); } + +/** + * Migrate upload.module to file.module. + */ +function system_update_7053(&$sandbox) { + if (!db_table_exists('upload')) { + return; + } + + if (!isset($sandbox['progress'])) { + // Initialize batch update information. + $sandbox['progress'] = 0; + $sandbox['last_vid_processed'] = -1; + $sandbox['max'] = db_query("SELECT COUNT(DISTINCT u.vid) FROM {upload} u")->fetchField(); + + // Check which node types have upload.module attachments enabled. + $context['types'] = array(); + foreach (node_type_get_types() as $node_type => $node_info) { + if (variable_get('upload_' . $node_type, 1)) { + $context['types'][$node_type] = $node_type; + } + variable_del('upload_' . $node_type); + } + + // The {upload} table will be deleted when this update is complete so we + // want to be careful to migrate all the data, even for node types that + // may have had attachments disabled after files were uploaded. Look for + // any other node types referenced by the upload records and add those to + // the list. The admin can always remove the field later. + $query = db_select('node', 'n')->distinct(TRUE); + $query->innerJoin('upload', 'u', 'n.vid = u.vid'); + $results = $query->fields('n', array('type'))->execute(); + foreach ($results as $row) { + if (!isset($context['types'][$row->type])) { + drupal_set_message('The content type ' . $row->type . ' had uploads disabled but contained uploaded file data. Uploads have been re-enabled to migrate the existing data. You may delete the "File attachments" field in the ' . $row->type . ' type if this data is not necessary.'); + $context['types'][$row->type] = $row->type; + } + } + + // Create a single "field_upload" field on all the content types that have + // uploads enabled, then add an instance to each enabled type. + if (count($context['types']) > 0) { + module_enable(array('file')); + module_load_include('inc', 'field', 'field.crud'); + + $field = array( + 'field_name' => 'field_upload', + 'type' => 'file', + 'locked' => FALSE, + 'cardinality' => FIELD_CARDINALITY_UNLIMITED, + 'translatable' => FALSE, + 'settings' => array( + 'display_field' => 1, + 'display_default' => variable_get('upload_list_default', 1), + 'uri_scheme' => variable_get('file_default_scheme', 'public'), + 'default_file' => 0, + ), + ); + + $upload_size = variable_get('upload_uploadsize_default', 1); + $instance = array( + 'field_name' => 'field_upload', + 'entity_type' => 'node', + 'bundle' => NULL, + 'label' => 'File attachments', + 'widget_type' => 'file_generic', + 'required' => 0, + 'description' => '', + 'widget' => array( + 'weight' => '1', + 'settings' => array( + 'progress_indicator' => 'throbber', + ), + 'type' => 'file_generic', + ), + 'settings' => array( + 'max_filesize' => $upload_size ? ($upload_size . ' MB') : '', + 'file_extensions' => variable_get('upload_extensions_default', 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp'), + 'file_directory' => '', + 'description_field' => 1, + ), + 'display' => array( + 'full' => array( + 'label' => 'hidden', + 'type' => 'file_table', + 'settings' => array(), + 'weight' => 0, + 'module' => 'file', + ), + 'teaser' => array( + 'label' => 'hidden', + 'type' => 'hidden', + 'settings' => array(), + 'weight' => 0, + 'module' => NULL, + ), + 'rss' => array( + 'label' => 'hidden', + 'type' => 'file_table', + 'settings' => array(), + 'weight' => 0, + 'module' => 'file', + ), + ), + ); + + // Create the field. Save the field id for the data insertion later on. + $field = field_create_field($field); + $sandbox['field_id'] = $field['id']; + + // Create the instances. + foreach ($context['types'] as $bundle) { + $instance['bundle'] = $bundle; + field_create_instance($instance); + } + } + else { + // We're done: return without specifying a #progress. + return; + } + } + + // Migrate a batch of files from the upload table to the appropriate field. + $limit = 500; + $query = db_select('upload', 'u'); + $query->innerJoin('node_revision', 'nr', 'u.vid = nr.vid'); + $query->innerJoin('node', 'n', 'n.nid = nr.nid'); + $query + ->fields('u', array('fid', 'vid', 'list', 'description')) + ->fields('n', array('nid', 'type')) + ->distinct(TRUE) + ->condition('u.vid', $sandbox['last_vid_processed'], '>') + ->orderBy('u.vid') + ->orderBy('u.weight') + ->range(0, $limit); + $result = $query->execute(); + foreach ($result as $record) { + // Note that we still reference the old files table here, since upload will + // not know about the new FID in the new file table. + $file = db_select('files', 'f') + ->fields('f', array('fid', 'uid', 'filename', 'filepath', 'filemime', 'filesize', 'status', 'timestamp')) + ->condition('f.fid', $record->fid) + ->execute() + ->fetch(PDO::FETCH_ASSOC); + if (!$file) { + continue; + } + + $file['description'] = $record->description; + $file['display'] = $record->list; + + $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]['field_upload'][FIELD_LANGUAGE_NONE][] = $file; + } + + // To make sure we process an entire revision all at once, toss the last node + // revision (which might be partial) unless it's the last one. + if ((count($node_revisions) > 1) && ($result->rowCount() == $limit)) { + array_pop($node_revisions); + } + else { + $finished = TRUE; + } + + $basename = variable_get('file_directory_path', conf_path() . '/files'); + $scheme = variable_get('file_default_scheme', 'public') . '://'; + foreach ($node_revisions as $vid => $revision) { + // We will convert filepaths to uri using the default scheme + // and stripping off the existing file directory path. + $fids = array(); + foreach ($revision['field_upload'][FIELD_LANGUAGE_NONE] as $delta => $file) { + // Insert into the file table. + $file['uri'] = $scheme . str_replace($basename, '', $file['filepath']); + $file['uri'] = file_stream_wrapper_uri_normalize($file['uri']); + unset($file['filepath']); + drupal_write_record('file', $file); + + // Update the node field with the file URI. + $revision['field_upload'][FIELD_LANGUAGE_NONE][$delta] = $file; + } + + // Insert the revision's files into the field_upload table. + $node = (object) $revision; + field_sql_storage_field_storage_write('node', $node, FIELD_STORAGE_INSERT, array($sandbox['field_id'])); + + // Update our progress information for the batch update. + $sandbox['progress']++; + $sandbox['last_vid_processed'] = $vid; + } + + // If there's no max value then there's nothing to update and we're finished. + if (empty($sandbox['max']) || isset($finished)) { + db_delete('system', array('type' => 'module', 'name' => 'upload')); + db_drop_table('upload'); + 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']; + } +} + /** * @} End of "defgroup updates-6.x-to-7.x" * The next series of updates should start at 8000.