Index: signup_status.admin.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/signup_status/signup_status.admin.inc,v retrieving revision 1.2 diff -u -p -r1.2 signup_status.admin.inc --- signup_status.admin.inc 19 Sep 2009 18:24:22 -0000 1.2 +++ signup_status.admin.inc 19 Sep 2009 20:49:27 -0000 @@ -202,36 +202,180 @@ function signup_status_admin_settings_fo */ function signup_status_admin_delete(&$form_state, $cid) { $codes = signup_status_codes(); - if (array_key_exists($cid, $codes)) { - $form['cid'] = array( - '#type' => 'value', - '#value' => $cid, - ); - $form['name'] = array( - '#type' => 'value', - '#value' => $codes[$cid]['name'], - ); - return confirm_form( - $form, - t('Are you sure you want to delete the status code %name?', array('%name' => $codes[$cid]['name'])), - 'admin/settings/signup_status/list', - t('
This action cannot be undone.
'), - t('Delete'), - t('Cancel') + if (empty($codes[$cid])) { + drupal_set_message(t('The status you are trying to delete does not exist.'), 'error'); + return drupal_goto('admin/settings/signup_status'); + } + + $name = $codes[$cid]['name']; + $form['cid'] = array( + '#type' => 'value', + '#value' => $cid, + ); + $form['name'] = array( + '#type' => 'value', + '#value' => $name, + ); + + $total = db_result(db_query('SELECT COUNT(sid) AS total FROM {signup_log} WHERE status = %d', $cid)); + if ($total > 0) { + foreach ($codes as $id => $status) { + $options[$id] = $status['name']; + } + $form['new_status'] = array( + '#type' => 'select', + '#title' => t('Reassign status'), + '#default_value' => $cid, + '#options' => $options, + '#description' => t('There are !total existing signups with the status of @name. Please select a new status for these signups.', array('!total' => $total, '@name' => $name)), ); } - drupal_goto('admin/settings/signup_status/list'); + + return confirm_form( + $form, + t('Are you sure you want to delete the status code %name?', array('%name' => $name)), + 'admin/settings/signup_status', + t('This action cannot be undone.'), + t('Delete status'), + t('Cancel') + ); +} + +/** + * Validation callback for the signup status code delete page. + */ +function signup_status_admin_delete_validate($form, &$form_state) { + if ($form_state['values']['new_status'] == $form_state['values']['cid']) { + form_set_error('new_status', t('Choose a new signup status for existing signups of status %name.', array('%name' => $form_state['values']['name']))); + } } /** - * Submit hook for the signup status code delete page. + * Submit callback for the signup status code delete page. */ function signup_status_admin_delete_submit($form, &$form_state) { $values = $form_state['values']; - if ($values['confirm'] && $values['cid']) { - db_query("DELETE FROM {signup_status_codes} WHERE cid = %d", $values['cid']); - drupal_set_message(t('Status code %name has been deleted.', array('%name' => $values['name']))); - watchdog('signup_status', 'Status code %name has been deleted.', array('%name' => $values['name'])); + $codes = signup_status_codes(); + + db_query("DELETE FROM {signup_status_codes} WHERE cid = %d", $values['cid']); + drupal_set_message(t('Status code %name has been deleted.', array('%name' => $values['name']))); + watchdog('signup_status', 'Status code %name has been deleted.', array('%name' => $values['name'])); + + if (isset($values['new_status'])) { + // We could update all of the signups to the new status in a single query, + // but we need to invoke the hook that the status was changed, and that's + // potentially expensive, so we do it via the Batch API. + $old_status = $codes[$values['cid']]; + $new_status = $codes[$values['new_status']]; + signup_status_admin_reassign_status($old_status, $new_status); + } + else { + // Nothing to reassign, we're done. + $form_state['redirect'] ='admin/settings/signup_status'; + } +} + +/** + * Reassign all signups from one status to another using the Batch API. + * + * @param $old_status + * Array defining the old status to assign from. This array must contain at + * least the 'cid' and 'name' keys, as returned by signup_status_codes(). + * @param $new_status + * Array defining the new status to assign to. This array must contain at + * least the 'cid' and 'name' keys, as returned by signup_status_codes(). + * + * @see signup_status_codes() + * @see signup_status_admin_reassign_status_batch() + * @see signup_status_admin_reassign_status_finished() + */ +function signup_status_admin_reassign_status($old_status, $new_status) { + $batch = array( + 'operations' => array( + array('signup_status_admin_reassign_status_batch', array($old_status, $new_status)), + ), + 'finished' => 'signup_status_admin_reassign_status_finished', + 'title' => $title, + 'init_message' => $title, + 'progress_message' => t('Reassigning signups from %old_status status to %new_status status...', array('%old_status' => $old_status['name'], '%new_status' => $new_status['name'])), + 'error_message' => t('Error reassigning signups from %old_status status to %new_status status...', array('%old_status' => $old_status['name'], '%new_status' => $new_status['name'])), + 'file' => drupal_get_path('module', 'signup_status') . '/signup_status.admin.inc', + ); + batch_set($batch); +} + +/** + * Batch worker to reassign signups from one status to another. + * + * @param $old_status + * Array defining the old status to assign from. This array must contain at + * least the 'cid' and 'name' keys, as returned by signup_status_codes(). + * @param $new_status + * Array defining the new status to assign to. This array must contain at + * least the 'cid' and 'name' keys, as returned by signup_status_codes(). + * @param $context + * Reference to a Batch API context array to track progress of the batch. + * + * @see signup_status_admin_reassign_status() + * @see signup_status_admin_reassign_status_finished() + */ +function signup_status_admin_reassign_status_batch($old_status, $new_status, &$context) { + if (empty($context['sandbox']['signups'])) { + // Initialize the work to do -- remember all the signups we need to change + // the status on. + $query = db_query('SELECT sid FROM {signup_log} WHERE status = %d', $old_status['cid']); + while ($sid = db_result($query)) { + $context['sandbox']['signups'][] = $sid; + } + $context['finished'] = 0; + $context['sandbox']['max'] = count($context['sandbox']['signups']); + $context['sandbox']['progress'] = 0; + $context['message'] = t('Reassigning signups from %old_status status to %new_status status...', array('%old_status' => $old_status['name'], '%new_status' => $new_status['name'])); + $context['results']['updated'] = 0; + $context['results']['processed'] = 0; + $context['results']['old_status'] = $old_status; + $context['results']['new_status'] = $new_status; + + // In case of a race condition, ensure there's something to process. + if (empty($context['sandbox']['max'])) { + $context['finished'] = 1; + return; + } + } + + // If there's work to do, process a signup. + if (!empty($context['sandbox']['signups'])) { + $sid = array_pop($context['sandbox']['signups']); + $signup = signup_load_signup($sid); + $signup->old_status = $signup->status; + $signup->status = $new_status['cid']; + db_query("UPDATE {signup_log} SET status = %d WHERE sid = %d", $signup->status, $signup->sid); + _signup_status_change('update', $signup); + $context['results']['updated']++; + } + $context['sandbox']['progress']++; + $context['results']['processed']++; + $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max']; +} + +/** + * Batch API callback once all signups have been reassigned to a new status. + * + * @see signup_status_admin_reassign_status() + * @see signup_status_admin_reassign_status_batch() + */ +function signup_status_admin_reassign_status_finished($success, $results, $operations) { + if ($success) { + if (!empty($results)) { + drupal_set_message(format_plural($results['updated'], 'Reassigned one signup from the %old_status status to the %new_status status.', 'Reassigned @count signups from the %old_status status to the %new_status status.', array('%old_status' => $results['old_status']['name'], '%new_status' => $results['new_status']['name']))); + } + } + else { + // An error occurred. + // $operations contains the operations that remained unprocessed. + $error_operation = reset($operations); + drupal_set_message(t('An error occurred while processing with arguments: @error', array('@error' => var_export($error_operation[0], TRUE))), 'error'); } + drupal_goto('admin/settings/signup_status'); }