Public feed #381682

delete api

public text v1 · immutable
Raw Edit
·published 2007-03-05 00:31 UTC
rendered paste body
=== 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. <em>'DELETE FROM {comment} WHERE nid = %d', $nid</em>
+ */
+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 '<front>';
@@ -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));
 }
 
 /**