=== modified file 'includes/common.inc' --- includes/common.inc 2007-02-16 07:42:13 +0000 +++ includes/common.inc 2007-03-05 00:16:55 +0000 @@ -2263,3 +2263,159 @@ function int2vancode($i = 0) { $length = strlen($num); return chr($length + ord('0') - 1) . $num; } + +/** + * Perform a deletion from the database. + * + * @param $id A unique string identifier for the deletion statement being performed, or one of the following special values: + * + * 'new package' => Used to begin a new deletion package. Most often this will not be necessary, as most non-core deletions will already be part of a package. Also note that if drupal_delete is called and no package has been started, the deletion will be performed as it's own package. + * 'confirm' => Initiates the confirmation cycle of a deletion. This command fully builds all packages for deletion, and returns a form array containing any injected messages which can be used to print a confirmation screen. + * 'execute' => Initiates the actual deletion. Confirmation messages are bypassed, but abort messages are respected. + * 'custom' => Forces the deletion to be performed immediately and separately from any currently building package. No confirm or abort messages are built or consulted. + * + * Alternatively, an array can be passed, which will become metadata for the package. The following special keys exist in this case: + * + * 'id' => Required. Value should the same as $id listed above. + * 'callback' => A string representing a function to be called after the deletion completes. Useful for performing other cleanup, setting user messages, etc. + * 'callback arguments' => An array of arguments to pass to the callback function. + * + * Other than the above, any metadata that might be useful to outside modules during the confirmation/deletion cycle can be passed, and will be included in all hooks that are called. + * + * @param $query The deletion query to be performed, properly escaped. ex. 'DELETE FROM {comment} WHERE nid = %d', $nid + */ +function drupal_delete($id, $query = NULL) { + static $delete_id = 0; + static $is_package = NULL; + static $deletion_data = array(); + + $confirm = NULL; + $execute = NULL; + + // Process metadata if present. + if (is_array($id)) { + $op = $id['id']; + unset($id['id']); + $metadata = $id; + } + else { + $op = $id; + $metadata = array(); + } + + // New package -- mark it as such and get the next deletion ID. + if ($op == 'new package') { + $delete_id++; + $is_package = TRUE; + $deletion_data[$delete_id]['metadata'] = array(); + } + // Execute all packages. + elseif ($op == 'confirm') { + $confirm = TRUE; + } + // Execute all packages. + elseif ($op == 'execute') { + $execute = TRUE; + } + // This is a new deletion to add to a package + else { + // Grab the args for the deletion query itself. + $all_args = func_get_args(); + if (count($all_args) > 2) { + $args = array_slice($all_args, 2); + // Clean up args passed as an array. + if (is_array($args[0])) { + $args = $args[0]; + } + } + else { + $args = array(); + } + + // Special case for single deletions. + if (!isset($is_package) || $op == 'custom') { + db_query($query, $args); + return; + } + // Add the information for this deletion into the package array. + else { + $deletion_data[$delete_id][$op][] = array('query' => $query, 'args' => $args); + } + } + + // Merge in metadata + $deletion_data[$delete_id]['metadata'] += $metadata; + + // Allow modules to inject confirm/abort data. + if (isset($confirm) || isset($execute)) { + $form = array(); + $abort = array(); + // Call the delete pre hook once for each package. + foreach ($deletion_data as $temp_id => $package_info) { + foreach (module_implements('delete_pre') as $module) { + $function = $module .'_delete_pre'; + $confirm_data = $function($package_info); + } + // Check for an aborted package. + if (in_array('abort', array_keys($confirm_data))) { + foreach ($confirm_data as $key => $message) { + if ($key == 'abort') { + $abort[$temp_id][] = $confirm_data['abort']; + } + } + } + // Add elements to confirm form return value. + else { + $form = array_merge_recursive($form, $confirm_data); + } + } + if ($confirm) { + return $form; + } + } + + // Execute all constructed packages. + if (isset($execute)) { + // Some messages were generated. + if (count($abort)) { + // Process the abort messages for each package--they cancel out deletion of the package. + foreach ($abort as $temp_id => $messages) { + if (count($messages)) { + drupal_set_message(theme('item_list', $messages), 'error'); + } + // Unset this package from the $deletion_data array, since it's deletion was aborted. + unset($deletion_data[$temp_id]); + } + } + drupal_delete_execute($deletion_data); + + // Explicitly reset the package information. + $delete_id = 0; + $is_package = NULL; + $deletion_data = array(); + } +} + +/** + * Executes all the database deletions in all packages of a single page call. + * + * @param $deletion_data The complete array of deletion data for all packages. + */ +function drupal_delete_execute($deletion_data) { + foreach ($deletion_data as $package_info) { + // Allow modules to perform any operations just prior to the deletion of the packages. + module_invoke_all('delete_execute', $package_info); + // Extract metadata. + $metadata = $package_info['metadata']; + unset($package_info['metadata']); + foreach ($package_info as $deletions) { + foreach ($deletions as $deletion) { + db_query($deletion['query'], $deletion['args']); + } + } + // Execute a post-delete callback if present. + if ($metadata['callback'] && function_exists($metadata['callback'])) { + call_user_func_array($metadata['callback'], $metadata['callback arguments']); + } + } +} === modified file 'modules/comment/comment.module' --- modules/comment/comment.module 2007-03-02 15:07:59 +0000 +++ modules/comment/comment.module 2007-03-04 23:53:49 +0000 @@ -425,8 +425,9 @@ function comment_nodeapi(&$node, $op, $a break; case 'delete': - db_query('DELETE FROM {comments} WHERE nid = %d', $node->nid); - db_query('DELETE FROM {node_comment_statistics} WHERE nid = %d', $node->nid); + $args = array('nid' => $node->nid); + drupal_delete('comments', 'DELETE FROM {comments} WHERE nid = %d', $args); + drupal_delete('node_comment_statistics', 'DELETE FROM {node_comment_statistics} WHERE nid = %d', $args); break; case 'update index': @@ -451,6 +452,22 @@ function comment_nodeapi(&$node, $op, $a } } +function comment_delete_pre($package_info) { + if (in_array('node', array_keys($package_info))) { + $form = array(); + foreach ($package_info['node'] as $data) { + $nid = $data['args']['nid']; + if ($count = db_num_rows(db_query('SELECT nid FROM {comments} WHERE nid = %d', $nid))) { + $form["nid_$nid"]["comment_$nid"] = array( + '#value' => t('!count will be deleted. ', array('!count' => format_plural($count, '@count comment', '@count comments'))), + ); + } + } + + return $form; + } +} + /** * Implementation of hook_user(). * === modified file 'modules/menu/menu.module' --- modules/menu/menu.module 2007-02-01 06:29:50 +0000 +++ modules/menu/menu.module 2007-03-04 23:21:23 +0000 @@ -584,10 +584,10 @@ function menu_delete_item($item) { } if ($item['mid']) { - db_query('DELETE FROM {menu} WHERE mid = %d', $item['mid']); + drupal_delete('menu', 'DELETE FROM {menu} WHERE mid = %d', array('mid' => $item['mid'])); } elseif ($item['path']) { - db_query("DELETE FROM {menu} WHERE path = '%s'", $item['path']); + drupal_delete('menu', "DELETE FROM {menu} WHERE path = '%s'", array('path' => $item['path'])); } } === modified file 'modules/node/node.module' --- modules/node/node.module 2007-03-02 15:08:00 +0000 +++ modules/node/node.module 2007-03-04 23:22:18 +0000 @@ -2239,9 +2239,19 @@ function node_form_submit($form_id, $for * Menu callback -- ask for confirmation of node deletion */ function node_delete_confirm($node) { - $form['nid'] = array('#type' => 'value', '#value' => $node->nid); - return confirm_form($form, + + drupal_delete( + array( + 'id' => 'new package', + 'callback' => 'node_delete_post', + 'callback arguments' => array($node->nid, $node->title, $node->type), + ) + ); + node_delete($node->nid, FALSE); + $form = drupal_delete('confirm'); + + return confirm_form($form, t('Are you sure you want to delete %title?', array('%title' => $node->title)), $_GET['destination'] ? $_GET['destination'] : 'node/'. $node->nid, t('This action cannot be undone.'), @@ -2253,7 +2263,7 @@ function node_delete_confirm($node) { */ function node_delete_confirm_submit($form_id, $form_values) { if ($form_values['confirm']) { - node_delete($form_values['nid']); + drupal_delete('execute'); } return ''; @@ -2267,23 +2277,26 @@ function node_delete($nid) { $node = node_load($nid); if (node_access('delete', $node)) { - db_query('DELETE FROM {node} WHERE nid = %d', $node->nid); - db_query('DELETE FROM {node_revisions} WHERE nid = %d', $node->nid); + $args = array('nid' => $node->nid); + drupal_delete('node', 'DELETE FROM {node} WHERE nid = %d', $args); + drupal_delete('node_revision', 'DELETE FROM {node_revisions} WHERE nid = %d', $args); // Call the node-specific callback (if any): node_invoke($node, 'delete'); node_invoke_nodeapi($node, 'delete'); + } +} - // Clear the cache so an anonymous poster can see the node being deleted. - cache_clear_all(); +function node_delete_post($nid, $title, $type) { + // Clear the cache so an anonymous poster can see the node being deleted. + cache_clear_all(); - // Remove this node from the search index if needed. - if (function_exists('search_wipe')) { - search_wipe($node->nid, 'node'); - } - drupal_set_message(t('%title has been deleted.', array('%title' => $node->title))); - watchdog('content', t('@type: deleted %title.', array('@type' => t($node->type), '%title' => $node->title))); + // Remove this node from the search index if needed. + if (function_exists('search_wipe')) { + search_wipe($nid, 'node'); } + drupal_set_message(t('%title has been deleted.', array('%title' => $title))); + watchdog('content', t('@type: deleted %title.', array('@type' => t($type), '%title' => $title))); } /** === modified file 'modules/taxonomy/taxonomy.module' --- modules/taxonomy/taxonomy.module 2007-02-28 07:01:56 +0000 +++ modules/taxonomy/taxonomy.module 2007-03-04 23:21:52 +0000 @@ -853,7 +853,7 @@ function taxonomy_node_save($node, $term * Remove associations of a node to its terms. */ function taxonomy_node_delete($node) { - db_query('DELETE FROM {term_node} WHERE nid = %d', $node->nid); + drupal_delete('term_node', 'DELETE FROM {term_node} WHERE nid = %d', array('nid' => $node->nid)); } /**