#1015580_media_type_on_install

From: Damien Tournoud <damien@commerceguys.com>


---
 includes/media.variables.inc |    4 +++
 media.admin.inc              |   53 +++++++++++++++++++++++++++++++++++++++
 media.install                |   16 +++++++++++-
 media.module                 |   18 +++++++++++++
 media.types.inc              |   57 +++++++++++++++++++++++++++++++++++++++++-
 5 files changed, 145 insertions(+), 3 deletions(-)

diff --git a/includes/media.variables.inc b/includes/media.variables.inc
index 0d2c289..c11445a 100644
--- a/includes/media.variables.inc
+++ b/includes/media.variables.inc
@@ -148,6 +148,10 @@ function media_variable_default($name = NULL) {
       'type_icon_directory' => drupal_get_path('module', 'media') . '/images/types',
       'icon_base_directory' => drupal_get_path('module', 'media') . '/images/icons',
       'icon_set' => 'default',
+      
+       // This is set in media_enable().  It will show a persistant dsm on every page
+       // until the user runs the batch operation provided by media_admin_rebuild_types_form().
+      'show_file_type_rebuild_nag' => FALSE,
     );
   }
 
diff --git a/media.admin.inc b/media.admin.inc
index 1582b1a..dbb5d64 100644
--- a/media.admin.inc
+++ b/media.admin.inc
@@ -604,3 +604,56 @@ function media_admin_config_browser_pre_submit(&$form, &$form_state) {
     unset($form_state['values'][media_variable_name('dialog_theme')]);
   }
 }
+
+/**
+ * Confirmation form for rebuliding the file_managed table to include type
+ * in rows where there is no type.
+ */
+function media_admin_rebuild_types_form($form, &$form_state) {
+  $total = media_type_invalid_files_count();
+  if ($total == 0) {
+    media_variable_del('show_file_type_rebuild_nag');
+    // @TODO: Make this not sound stupid.
+    drupal_set_message('All files in the system have been assigned types. Media installation complete.');
+    drupal_goto('admin');
+  }
+  $form['total'] = array('#type' => 'value', '#value' => $total);
+  return confirm_form($form, 'Update types for existing files', 'admin/config/media', 'This process is required when installing media on an existing site.  Media needs to scan through existing files and identify the file type. <br/><strong>Update types for ' . $total . ' files?</strogn>');
+}
+
+/**
+ * @see media_admin_rebuild_types_form().
+ */
+function media_admin_rebuild_types_form_submit(&$form, &$form_state) {
+  $total = $form_state['values']['total'];
+
+  $batch = array(
+    'title' => t('Rebuilding type information for ' . $total . ' files'),
+    'operations' => array(
+      array('media_admin_rebuild_types_batch_op', array($total)),
+    ),
+    'finished' => 'media_admin_rebuild_types_batch_complete',
+    'file' => drupal_get_path('module', 'media') . '/media.admin.inc',
+  );
+  batch_set($batch);
+}
+
+/**
+ * Batch operation for fixing the file_managed table for media, adding type values
+ * where no value exists.
+ */
+function media_admin_rebuild_types_batch_op($total, &$context) {
+  $per_run = media_variable_get('media_type_batch_update_per_run', 100);
+  $context['results'] = array_merge($context['results'], media_type_batch_update(FALSE, $per_run));
+  $context['finished'] = count($context['results']) / $total;
+}
+/**
+ * Sets a message informing the user how many file records were updated.
+ */
+function media_admin_rebuild_types_batch_complete($success, $results, $operations) {
+  if ($success) {
+    $message = format_plural(count($results), 'One file identified and given a type.', '@count files identified and given a type.');
+    media_variable_del('show_file_type_rebuild_nag');
+  }
+  drupal_set_message($message);
+}
\ No newline at end of file
diff --git a/media.install b/media.install
index 9ddb7aa..eae4621 100644
--- a/media.install
+++ b/media.install
@@ -5,6 +5,8 @@
  * Install, update and uninstall functions for the Media module.
  */
 
+define('MEDIA_UPDATE_RECORDS_ON_INSTALL', 200);
+
 /**
  * Implements hook_install().
  */
@@ -55,7 +57,6 @@ function media_enable() {
     'media_preview' => 'media_large_icon',
     //@TODO: We need a real "original" formatter
     'media_original' => 'file_generic',
-    //@TODO: Non-sequiter small == medium.  Why medium if there is no small?
     'media_small'   => 'hidden',
     'media_large'   => 'file_generic',
   );
@@ -141,6 +142,19 @@ function media_enable() {
   foreach ($roles as $rid => $role) {
     user_role_grant_permissions($rid, array('view media'));
   }
+
+  // Updates the type field for the first MEDIA_UPDATE_RECORDS_ON_INSTALL files.
+  $invalid_files = media_type_invalid_files_count();
+  if ($invalid_files <= MEDIA_UPDATE_RECORDS_ON_INSTALL) {
+    media_type_batch_update(FALSE, MEDIA_UPDATE_RECORDS_ON_INSTALL);
+  }
+
+  $invalid_files = media_type_invalid_files_count();
+  if ($invalid_files > 0) {
+    // Not all files could be converted. Display a persistant nag message on
+    // every page for the administrator, urging them to finish the process.
+    media_variable_set('show_file_type_rebuild_nag', TRUE);
+  }
 }
 
 /**
diff --git a/media.module b/media.module
index 4a18f57..807924e 100644
--- a/media.module
+++ b/media.module
@@ -67,6 +67,15 @@ function media_menu() {
     'file' => 'media.admin.inc',
   );
   // For managing different types of media and the fields associated with them.
+  $items['admin/config/media/rebuild_types'] = array(
+    'title' => 'Rebuild type information for media',
+    'description' => 'In case there are files in file_managed w/o a type, this function rebuilds them',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('media_admin_rebuild_types_form'),
+    'access arguments' => array('administer media'),
+    'file' => 'media.admin.inc',
+  );
+  // For managing different types of media and the fields associated with them.
   $items['admin/config/media/types'] = array(
     'title' => 'Media Types',
     'description' => 'Manage files used on your site.',
@@ -427,6 +436,15 @@ function media_styles_style_flush($style) {
  * in the URL.
  */
 function media_page_alter(&$page) {
+  // Show a nagging message when the media installation needs to be completed.
+  if (user_access('administer media') && media_variable_get('show_file_type_rebuild_nag')
+    // Prevent form submissions from creating duplicate messages.
+    && ($_SERVER['REQUEST_METHOD'] == 'GET')
+    // Show on all the admin pages, except the batch and the rebuild form.
+    && path_is_admin(current_path()) && (arg(0) != 'batch') && (current_path() != 'admin/config/media/rebuild_types')) {
+    drupal_set_message(t('Media module install is not complete. <a href="@type_rebuild_link">Finish the install</a>.', array('@type_rebuild_link' => url('admin/config/media/rebuild_types'))), 'warning', FALSE);
+  }
+
   if (isset($_GET['render']) && $_GET['render'] == 'media-popup') {
     $page['#theme'] = 'media_dialog_page';
     // temporary fix while awaiting fix for 914786
diff --git a/media.types.inc b/media.types.inc
index c3c23c7..8f7a813 100644
--- a/media.types.inc
+++ b/media.types.inc
@@ -252,7 +252,6 @@ function media_is_type($media, $args) {
 
 /**
  * Implement hook_media_format_form_prepare_alter
- * @return unknown_type
  */
 function media_media_format_form_prepare_alter(&$form, &$form_state, $media) {
   switch($media->type) {
@@ -267,4 +266,58 @@ function media_media_format_form_prepare_alter(&$form, &$form_state, $media) {
       );
       break;
   }
-}
\ No newline at end of file
+}
+
+/**
+ * Returns the number of files that need to be converted to media.
+ */
+function media_type_invalid_files_count() {
+  return db_select('file_managed', 'fm')
+    ->condition('type', NULL)
+    ->countQuery()
+    ->execute()
+    ->fetchField();
+}
+
+/**
+ * Adds a value for the type column in files_managed.
+ *
+ * If $update_existing is TRUE, will update the type of files with an existing type value.
+ *
+ * @param boolean $update_existing
+ * @param integer $no_to_update
+ * @param integer $offset
+ *
+ * @return array
+ *  A list of updated file ids
+ */
+function media_type_batch_update($update_existing = FALSE, $no_to_update = NULL, $offset = 0) {
+  $results = array();
+  
+  $query = db_select('file_managed', 'fm')
+    ->fields('fm', array('fid'));
+
+  if (!$update_existing) {
+    $query->condition('type', NULL);
+  }
+
+  if ($no_to_update) {
+    $query->range($offset, $no_to_update);
+  }
+  elseif ($offset) {
+    $query->range($offset);
+  }
+
+  $fids = $query->execute()->fetchCol();
+  foreach ($fids as $fid) {
+    $file = file_load($fid);
+    if (!$file->fid) {
+      throw new Exception('Unable to continue, file was not loaded.');
+    }
+    $file->type = media_get_type($file);
+    file_save($file);
+    $results[] = $fid;
+  }
+
+  return $results;
+}
