#147723: Deletion API (by hunmonk). Woop woop.
parent
c5443d739e
commit
38a1300df2
|
@ -1229,7 +1229,7 @@ function url($path = NULL, $options = array()) {
|
|||
|
||||
// Preserve the original path before aliasing.
|
||||
$original_path = $path;
|
||||
|
||||
|
||||
// The special path '<front>' links to the default front page.
|
||||
if (!empty($path) && $path != '<front>') {
|
||||
if (!$options['alias']) {
|
||||
|
@ -2847,6 +2847,376 @@ function drupal_common_themes() {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup deletionapi
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Used to begin a new deletion package. A package is set of deletion
|
||||
* queries associated with a particular kind of deletion -- for example,
|
||||
* all the queries associated with a node deletion. Most often it will
|
||||
* not be necessary to start a new package, as most non-core deletions will
|
||||
* already be part of a package initiated by core. Once a package has
|
||||
* been started, all metadata, callbacks, and queries are added to the package.
|
||||
* A package is complete when either a new package is started, or when a
|
||||
* confirm or execute command is given.
|
||||
*
|
||||
* @param $type
|
||||
* The deletion type for the package, ex. 'node', 'user', 'comment'.
|
||||
* @param $id
|
||||
* A unique identifier for the package. By convention this is the primary
|
||||
* key of the 'root' deletion, ex. the nid for node type deletions, the uid
|
||||
* for user type deletions, etc.
|
||||
*/
|
||||
function drupal_delete_initiate($type, $id) {
|
||||
_drupal_delete('new package', array('type' => $type, 'id' => $id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass a deletion query into a deletion package.
|
||||
*
|
||||
* @param $query
|
||||
* The query to be passed, followed by any additional arguments for escaped values.
|
||||
* ex. drupal_delete_add_query('DELETE FROM {comments} WHERE nid = %d', $node->nid);
|
||||
* The additional arguments can be passed in any fashion that db_query() accepts.
|
||||
*/
|
||||
function drupal_delete_add_query($query) {
|
||||
$all_args = func_get_args();
|
||||
array_unshift($all_args, 'query', '');
|
||||
call_user_func_array('_drupal_delete', $all_args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates the confirmation cycle. This command fully builds all packages
|
||||
* for deletion, and returns a confirm form array containing any injected messages
|
||||
* which can be used to print a confirmation screen.
|
||||
*
|
||||
* @param $confirm
|
||||
* An associative array with the following key/value pairs:
|
||||
* 'form' => Optional. An array representing the form elements to pass to the confirm form.
|
||||
* 'question' => Optional. The question for the confirm form.
|
||||
* 'path' => Optional. The cancellation path for the confirm form.
|
||||
*
|
||||
* Also, any valid options from the $options argument of confirm_form() may be passed,
|
||||
* and they will be passed through to the confirm form.
|
||||
* ex. drupal_delete_confirm(
|
||||
* array(
|
||||
* 'form' => $form,
|
||||
* 'question' => t('Are you sure you want to delete these items?'),
|
||||
* 'path' => 'admin/content/node',
|
||||
* 'yes' => t('Delete all'),
|
||||
* 'destination' => 'admin/content/node',
|
||||
* )
|
||||
* );
|
||||
*/
|
||||
function drupal_delete_confirm($confirm) {
|
||||
return _drupal_delete('confirm', '', $confirm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates the deletion of all constructed packages. Confirmation messages
|
||||
* are bypassed, but abort messages are respected.
|
||||
*/
|
||||
function drupal_delete_execute() {
|
||||
_drupal_delete('execute');
|
||||
}
|
||||
|
||||
/**
|
||||
* Register post-deletion callback functions for a package. The functions are called after the package
|
||||
* has been deleted. Useful for miscellaneous cleanup, user messages, etc.
|
||||
*
|
||||
* @param $callbacks
|
||||
* An associative array of callback functions, key = name of function,
|
||||
* value = an array of arguments to pass to the function.
|
||||
* ex. drupal_delete_add_callback(
|
||||
* array(
|
||||
* 'node_delete_post' => array($node->nid, $node->title, $node->type),
|
||||
* )
|
||||
* );
|
||||
*/
|
||||
function drupal_delete_add_callback($callbacks) {
|
||||
_drupal_delete('callback', '', $callbacks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass metadata related to the deletion or package to the API. This is made
|
||||
* available to all hooks called during the deletion cycle.
|
||||
*
|
||||
* @param $metadata
|
||||
* An associative array of metadata.
|
||||
* ex. drupal_delete_add_metadata(
|
||||
* array(
|
||||
* 'comment_messages' => $messages,
|
||||
* )
|
||||
* );
|
||||
*/
|
||||
function drupal_delete_add_metadata($metadata) {
|
||||
_drupal_delete('metadata', '', $metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass in a package-specific set of form elements, to be displayed in the
|
||||
* confirm form. Use this in multiple deletion scenarios where the confirm
|
||||
* information shouldn't be displayed if the package is aborted.
|
||||
*
|
||||
* @param $elements
|
||||
* An array representing the package-specific form elements to pass to the confirm form.
|
||||
* ex. drupal_delete_add_form_elements(
|
||||
* array(
|
||||
* "node_$node->nid" => array(
|
||||
* '#value' => check_plain($node->title),
|
||||
* '#prefix' => '<li>',
|
||||
* '#suffix' => "</li>\n",
|
||||
* ),
|
||||
* )
|
||||
* );
|
||||
*/
|
||||
function drupal_delete_add_form_elements($elements) {
|
||||
_drupal_delete('form', '', $elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "ingroup deletionapi".
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create/build/execute deletion packages.
|
||||
*
|
||||
* Note that this function should not be called directly, but through the following helper functions:
|
||||
*
|
||||
* drupal_delete_initiate()
|
||||
* drupal_delete_add_query()
|
||||
* drupal_delete_confirm()
|
||||
* drupal_delete_execute()
|
||||
* drupal_delete_add_callback()
|
||||
* drupal_delete_add_metadata()
|
||||
* drupal_delete_add_form_elements()
|
||||
*
|
||||
* @param $op
|
||||
* An operation to be performed.
|
||||
*
|
||||
* @param $id
|
||||
* A unique string identifier for the deletion being performed.
|
||||
*/
|
||||
function _drupal_delete($op, $id = '') {
|
||||
static $delete_type = NULL,
|
||||
$delete_id = NULL,
|
||||
$deletion_data = array(),
|
||||
$built = NULL,
|
||||
$form = array();
|
||||
|
||||
$confirm = NULL;
|
||||
$execute = NULL;
|
||||
$destination = FALSE;
|
||||
|
||||
// Process additional arguments.
|
||||
$all_args = func_get_args();
|
||||
if (count($all_args) > 2) {
|
||||
// Get any additional arguments.
|
||||
$args = array_slice($all_args, 2);
|
||||
// Shift off query string if present.
|
||||
if ($op == 'query') {
|
||||
$query = array_shift($args);
|
||||
}
|
||||
// Clean up args passed as an array.
|
||||
if (is_array($args[0])) {
|
||||
$args = $args[0];
|
||||
}
|
||||
}
|
||||
else {
|
||||
$args = array();
|
||||
}
|
||||
|
||||
switch ($op) {
|
||||
// Query to add to a package
|
||||
case 'query':
|
||||
// Add the information for this deletion into the package array.
|
||||
$deletion_data[$delete_type][$delete_id]['queries'][] = array('query' => $query, 'args' => $args);
|
||||
break;
|
||||
// New package -- mark it as such and get the next deletion ID.
|
||||
case 'new package':
|
||||
$delete_type = $id['type'];
|
||||
$delete_id = $id['id'];
|
||||
$deletion_data[$delete_type][$delete_id] = array(
|
||||
'metadata' => array(),
|
||||
'callback' => array(),
|
||||
'form' => array(),
|
||||
);
|
||||
break;
|
||||
// Confirm all packages.
|
||||
case 'confirm':
|
||||
// Set execute switch and destination if bypass is enabled.
|
||||
if (variable_get('bypass_delete_confirmation', 0)) {
|
||||
$execute = TRUE;
|
||||
$destination = isset($args['destination']) ? $args['destination'] : NULL;
|
||||
}
|
||||
else {
|
||||
$confirm = TRUE;
|
||||
}
|
||||
break;
|
||||
// Add package-specific form array pieces, callbacks, metadata.
|
||||
case 'form':
|
||||
case 'callback':
|
||||
case 'metadata':
|
||||
$deletion_data[$delete_type][$delete_id][$op] += $args;
|
||||
break;
|
||||
// Execute all packages.
|
||||
case 'execute':
|
||||
$execute = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
// Allow modules to inject confirm/abort data.
|
||||
if (isset($confirm) || isset($execute)) {
|
||||
// $built is kept as a static and checked to avoid calling this code twice
|
||||
// when the package is executed.
|
||||
if (!isset($built)) {
|
||||
$built = TRUE;
|
||||
|
||||
// Main confirm form.
|
||||
if (isset($args['form'])) {
|
||||
$form = $args['form'];
|
||||
}
|
||||
$count = 0;
|
||||
foreach ($deletion_data as $type => $deletion_info) {
|
||||
// Reset $delete_type to the type being checked.
|
||||
$delete_type = $type;
|
||||
foreach ($deletion_info as $package_id => $package_info) {
|
||||
$package_confirm_data = array();
|
||||
// Reset $delete_id to the package to be passed.
|
||||
$delete_id = $package_id;
|
||||
// Call hook_delete_pre() once for each package.
|
||||
foreach (module_implements('delete_pre') as $module) {
|
||||
$confirm_data = module_invoke($module, 'delete_pre', $type, $package_id, $package_info);
|
||||
// Check for an aborted package.
|
||||
if (isset($confirm_data['abort'])) {
|
||||
// Set abort message.
|
||||
if (isset($confirm_data['abort']['message'])) {
|
||||
drupal_set_message($confirm_data['abort']['message'], 'error');
|
||||
}
|
||||
// Set abort destination.
|
||||
if (isset($confirm_data['abort']['destination'])) {
|
||||
$abort_destination = $confirm_data['abort']['destination'];
|
||||
}
|
||||
// Remove the package.
|
||||
unset($deletion_data[$type][$package_id]);
|
||||
}
|
||||
else {
|
||||
// Add elements to confirm form data for the package.
|
||||
$package_confirm_data = array_merge_recursive($package_confirm_data, $confirm_data);
|
||||
}
|
||||
}
|
||||
// Add in package-specific confirm form elements if the package still exists.
|
||||
if (isset($deletion_data[$type][$package_id])) {
|
||||
$form = array_merge_recursive($form, $package_confirm_data);
|
||||
if (!empty($package_info['form'])) {
|
||||
$form = array_merge_recursive($form, $package_info['form']);
|
||||
}
|
||||
// If queries exist, then add to the count of executable packages.
|
||||
if (isset($package_info['queries'])) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($confirm)) {
|
||||
// Generate the confirm form if any packages remain.
|
||||
if ($count) {
|
||||
$question = isset($args['question']) ? $args['question'] : t('Delete the item?');
|
||||
$path = isset($args['path']) ? $args['path'] : 'node';
|
||||
unset($args['question'], $args['path']);
|
||||
$args['name'] = 'delete';
|
||||
// Submit handler - triggers execute operation for the API.
|
||||
$form['#submit'] = array('delete_confirm_submit');
|
||||
return confirm_form($form, $question, $path, $args);
|
||||
}
|
||||
// No packages left after aborts -- go to an abort destination if it exists.
|
||||
elseif (isset($abort_destination)) {
|
||||
drupal_goto($abort_destination);
|
||||
}
|
||||
// Fallback to cancel path.
|
||||
elseif (isset($args['path'])) {
|
||||
drupal_goto($args['path']);
|
||||
}
|
||||
// Last fallback, front page.
|
||||
else {
|
||||
drupal_goto('<front>');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute all constructed packages.
|
||||
if (isset($execute)) {
|
||||
|
||||
// Explicitly reset the package information.
|
||||
$delete_type = NULL;
|
||||
$delete_id = NULL;
|
||||
$package_data = $deletion_data;
|
||||
$deletion_data = array();
|
||||
$built = NULL;
|
||||
|
||||
// Execute the deletion of all packages.
|
||||
_drupal_delete_execute($package_data, $destination);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes all database deletions in all packages of a single page call.
|
||||
*
|
||||
* @param $package_data
|
||||
* The complete array of deletion data for all packages.
|
||||
* @param $destination
|
||||
* A destination for operations that bypass the confirm step.
|
||||
*/
|
||||
function _drupal_delete_execute($package_data, $destination = NULL) {
|
||||
foreach ($package_data as $type => $package) {
|
||||
foreach ($package as $package_id => $package_info) {
|
||||
// Allow modules to perform any operations just prior to the deletion of the package.
|
||||
drupal_alter('delete', $type, $package_id, $package_info);
|
||||
// Perform the deletions.
|
||||
if (isset($package_info['queries'])) {
|
||||
foreach ($package_info['queries'] as $deletion) {
|
||||
db_query($deletion['query'], $deletion['args']);
|
||||
}
|
||||
}
|
||||
// Execute post-deletion callbacks.
|
||||
foreach ($package_info['callback'] as $function => $args) {
|
||||
if (function_exists($function)) {
|
||||
call_user_func_array($function, $args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Redirect for confirmation bypass.
|
||||
drupal_redirect($destination);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a drupal_goto() based on the value of $goto.
|
||||
*
|
||||
* @param $goto
|
||||
* Can be any of the following values:
|
||||
* - A string representing a valid Drupal path.
|
||||
* - An array containing arguments to pass to drupal_goto().
|
||||
* - NULL to redirect to $_GET['q'].
|
||||
* - FALSE to bypass the redirection.
|
||||
*/
|
||||
function drupal_redirect($goto) {
|
||||
if ($goto !== FALSE) {
|
||||
if (isset($goto)) {
|
||||
if (is_array($goto)) {
|
||||
call_user_func_array('drupal_goto', $goto);
|
||||
}
|
||||
else {
|
||||
drupal_goto($goto);
|
||||
}
|
||||
}
|
||||
drupal_goto($_GET['q']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup schemaapi
|
||||
* @{
|
||||
|
|
|
@ -485,17 +485,7 @@ function drupal_redirect_form($form, $redirect = NULL) {
|
|||
if ($goto !== FALSE && isset($form['#redirect'])) {
|
||||
$goto = $form['#redirect'];
|
||||
}
|
||||
if (!isset($goto) || ($goto !== FALSE)) {
|
||||
if (isset($goto)) {
|
||||
if (is_array($goto)) {
|
||||
call_user_func_array('drupal_goto', $goto);
|
||||
}
|
||||
else {
|
||||
drupal_goto($goto);
|
||||
}
|
||||
}
|
||||
drupal_goto($_GET['q']);
|
||||
}
|
||||
drupal_redirect(isset($goto) ? $goto : NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -466,10 +466,10 @@ function book_nodeapi(&$node, $op, $teaser, $page) {
|
|||
}
|
||||
break;
|
||||
case 'delete revision':
|
||||
db_query('DELETE FROM {book} WHERE vid = %d', $node->vid);
|
||||
drupal_delete_add_query('DELETE FROM {book} WHERE vid = %d', $node->vid);
|
||||
break;
|
||||
case 'delete':
|
||||
db_query('DELETE FROM {book} WHERE nid = %d', $node->nid);
|
||||
drupal_delete_add_query('DELETE FROM {book} WHERE nid = %d', $node->nid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -232,7 +232,8 @@ function comment_menu() {
|
|||
|
||||
$items['comment/delete'] = array(
|
||||
'title' => 'Delete comment',
|
||||
'page callback' => 'comment_delete',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('comment_delete', 2),
|
||||
'access arguments' => array('administer comments'),
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
|
@ -474,8 +475,8 @@ function comment_nodeapi(&$node, $op, $arg = 0) {
|
|||
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);
|
||||
drupal_delete_add_query('DELETE FROM {comments} WHERE nid = %d', $node->nid);
|
||||
drupal_delete_add_query('DELETE FROM {node_comment_statistics} WHERE nid = %d', $node->nid);
|
||||
break;
|
||||
|
||||
case 'update index':
|
||||
|
@ -1093,50 +1094,44 @@ function comment_render($node, $cid = 0) {
|
|||
/**
|
||||
* Menu callback; delete a comment.
|
||||
*/
|
||||
function comment_delete($cid = NULL) {
|
||||
function comment_delete(&$form_state, $cid = NULL) {
|
||||
$comment = db_fetch_object(db_query('SELECT c.*, u.name AS registered_name, u.uid FROM {comments} c INNER JOIN {users} u ON u.uid = c.uid WHERE c.cid = %d', $cid));
|
||||
$comment->name = $comment->uid ? $comment->registered_name : $comment->name;
|
||||
|
||||
$output = '';
|
||||
|
||||
if (is_object($comment) && is_numeric($comment->cid)) {
|
||||
$output = drupal_get_form('comment_confirm_delete', $comment);
|
||||
drupal_delete_initiate('comment', $comment->cid);
|
||||
drupal_delete_add_callback(
|
||||
array(
|
||||
'comment_delete_post' => array($comment),
|
||||
// Clear the cache so an anonymous poster can see the node being deleted.
|
||||
'cache_clear_all' => array(),
|
||||
)
|
||||
);
|
||||
|
||||
// Delete comment and its replies.
|
||||
_comment_delete_thread($comment);
|
||||
|
||||
return drupal_delete_confirm(
|
||||
array(
|
||||
'question' => t('Are you sure you want to delete the comment %title?', array('%title' => $comment->subject)),
|
||||
'path' => 'node/'. $comment->nid,
|
||||
'description' => t('Any replies to this comment will be lost. This action cannot be undone.'),
|
||||
'destination' => 'node/'. $comment->nid,
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('The comment no longer exists.'));
|
||||
drupal_set_message(t('The comment no longer exists.'), 'error');
|
||||
drupal_goto('<front>');
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
function comment_confirm_delete(&$form_state, $comment) {
|
||||
$form = array();
|
||||
$form['#comment'] = $comment;
|
||||
return confirm_form(
|
||||
$form,
|
||||
t('Are you sure you want to delete the comment %title?', array('%title' => $comment->subject)),
|
||||
'node/'. $comment->nid,
|
||||
t('Any replies to this comment will be lost. This action cannot be undone.'),
|
||||
t('Delete'),
|
||||
t('Cancel'),
|
||||
'comment_confirm_delete');
|
||||
}
|
||||
function comment_delete_post($comment) {
|
||||
|
||||
function comment_confirm_delete_submit($form, &$form_state) {
|
||||
drupal_set_message(t('The comment and all its replies have been deleted.'));
|
||||
|
||||
$comment = $form['#comment'];
|
||||
|
||||
// Delete comment and its replies.
|
||||
_comment_delete_thread($comment);
|
||||
drupal_set_message(t('The comment %subject and all its replies have been deleted.', array('%subject' => $comment->subject)));
|
||||
watchdog('content', 'Comment: deleted %subject and all its replies.', array('%subject' => $comment->subject));
|
||||
|
||||
_comment_update_node_statistics($comment->nid);
|
||||
|
||||
// Clear the cache so an anonymous user sees that his comment was deleted.
|
||||
cache_clear_all();
|
||||
|
||||
$form_state['redirect'] = "node/$comment->nid";
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1291,45 +1286,78 @@ function theme_comment_admin_overview($form) {
|
|||
function comment_multiple_delete_confirm(&$form_state) {
|
||||
$edit = $form_state['post'];
|
||||
|
||||
$form['comments'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
|
||||
$form['comments']['#tree'] = TRUE;
|
||||
$form['prefix'] = array('#value' => '<ul>');
|
||||
// array_filter() returns only elements with actual values
|
||||
$comment_counter = 0;
|
||||
foreach (array_filter($edit['comments']) as $cid => $value) {
|
||||
foreach (array_filter($edit['comments']) as $cid) {
|
||||
$comment = _comment_load($cid);
|
||||
if (is_object($comment) && is_numeric($comment->cid)) {
|
||||
$subject = db_result(db_query('SELECT subject FROM {comments} WHERE cid = %d', $cid));
|
||||
$form['comments'][$cid] = array('#type' => 'hidden', '#value' => $cid, '#prefix' => '<li>', '#suffix' => check_plain($subject) .'</li>');
|
||||
// This is a placeholder -- preserves proper ordering in the confirm form.
|
||||
$form["comment_$cid"] = array();
|
||||
|
||||
// Start a new package for each comment.
|
||||
drupal_delete_initiate('comment', $comment->cid);
|
||||
drupal_delete_add_callback(array('comment_delete_post' => array($comment)));
|
||||
|
||||
_comment_delete_thread($comment);
|
||||
|
||||
// Add the confirm form piece for this comment.
|
||||
drupal_delete_add_form_elements(
|
||||
array(
|
||||
"comment_$cid" => array(
|
||||
'#value' => check_plain($subject),
|
||||
'#prefix' => '<li>',
|
||||
'#suffix' => "</li>\n",
|
||||
),
|
||||
'comments' => array(
|
||||
"comment_$cid" => array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => $cid,
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$comment_counter++;
|
||||
}
|
||||
}
|
||||
$form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
|
||||
$form['suffix'] = array('#value' => '</ul>');
|
||||
$form['operation'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => 'delete'
|
||||
);
|
||||
|
||||
// New package for the main admin callback.
|
||||
drupal_delete_initiate('comment', 'admin');
|
||||
|
||||
// Add the main callback for the mass deletion last.
|
||||
drupal_delete_add_callback(array('comment_multiple_delete_confirm_post' => array()));
|
||||
|
||||
if (!$comment_counter) {
|
||||
drupal_set_message(t('There do not appear to be any comments to delete or your selected comment was deleted by another administrator.'));
|
||||
drupal_goto('admin/content/comment');
|
||||
}
|
||||
else {
|
||||
return confirm_form($form,
|
||||
t('Are you sure you want to delete these comments and all their children?'),
|
||||
'admin/content/comment', t('This action cannot be undone.'),
|
||||
t('Delete comments'), t('Cancel'));
|
||||
return drupal_delete_confirm(
|
||||
array(
|
||||
'form' => $form,
|
||||
'question' => t('Are you sure you want to delete these comments and all their children?'),
|
||||
'path' => 'admin/content/comment',
|
||||
'yes' => t('Delete all'),
|
||||
'destination' => 'admin/content/comment',
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the actual comment deletion.
|
||||
* Post deletion callback for multiple comment deletion.
|
||||
*/
|
||||
function comment_multiple_delete_confirm_submit($form, &$form_state) {
|
||||
if ($form_state['values']['confirm']) {
|
||||
foreach ($form_state['values']['comments'] as $cid => $value) {
|
||||
$comment = _comment_load($cid);
|
||||
_comment_delete_thread($comment);
|
||||
_comment_update_node_statistics($comment->nid);
|
||||
}
|
||||
function comment_multiple_delete_confirm_post() {
|
||||
cache_clear_all();
|
||||
drupal_set_message(t('The comments have been deleted.'));
|
||||
}
|
||||
drupal_goto('admin/content/comment');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1892,8 +1920,7 @@ function _comment_delete_thread($comment) {
|
|||
}
|
||||
|
||||
// Delete the comment:
|
||||
db_query('DELETE FROM {comments} WHERE cid = %d', $comment->cid);
|
||||
watchdog('content', 'Comment: deleted %subject.', array('%subject' => $comment->subject));
|
||||
drupal_delete_add_query('DELETE FROM {comments} WHERE cid = %d', $comment->cid);
|
||||
|
||||
comment_invoke_comment($comment, 'delete');
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ function forum_perm() {
|
|||
function forum_nodeapi(&$node, $op, $teaser, $page) {
|
||||
switch ($op) {
|
||||
case 'delete revision':
|
||||
db_query('DELETE FROM {forum} WHERE vid = %d', $node->vid);
|
||||
drupal_delete_add_query('DELETE FROM {forum} WHERE vid = %d', $node->vid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -453,7 +453,7 @@ function forum_insert($node) {
|
|||
* Implementation of hook_delete().
|
||||
*/
|
||||
function forum_delete(&$node) {
|
||||
db_query('DELETE FROM {forum} WHERE nid = %d', $node->nid);
|
||||
drupal_delete_add_query('DELETE FROM {forum} WHERE nid = %d', $node->nid);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1685,29 +1685,67 @@ function theme_node_admin_nodes($form) {
|
|||
function node_multiple_delete_confirm(&$form_state) {
|
||||
$edit = $form_state['post'];
|
||||
|
||||
$form['nodes'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
|
||||
// array_filter returns only elements with TRUE values
|
||||
foreach (array_filter($edit['nodes']) as $nid => $value) {
|
||||
$title = db_result(db_query('SELECT title FROM {node} WHERE nid = %d', $nid));
|
||||
$form['nodes'][$nid] = array('#type' => 'hidden', '#value' => $nid, '#prefix' => '<li>', '#suffix' => check_plain($title) ."</li>\n");
|
||||
}
|
||||
$form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
|
||||
$form['nodes']['#tree'] = TRUE;
|
||||
$form['prefix'] = array('#value' => '<ul>');
|
||||
|
||||
return confirm_form($form,
|
||||
t('Are you sure you want to delete these items?'),
|
||||
'admin/content/node', t('This action cannot be undone.'),
|
||||
t('Delete all'), t('Cancel'));
|
||||
// array_filter() returns only elements with TRUE values.
|
||||
$nids = array_filter($edit['nodes']);
|
||||
$nodes = db_query('SELECT nid, title, type FROM {node} WHERE nid IN(%s)', implode(', ', $nids));
|
||||
while ($node = db_fetch_object($nodes)) {
|
||||
|
||||
// This is a placeholder -- preserves proper ordering in the confirm form.
|
||||
$form["node_$node->nid"] = array();
|
||||
|
||||
// Start a new package for each node.
|
||||
drupal_delete_initiate('node', $node->nid);
|
||||
|
||||
// Add the confirm form piece for this node.
|
||||
drupal_delete_add_form_elements(
|
||||
array(
|
||||
"node_$node->nid" => array(
|
||||
'#value' => check_plain($node->title),
|
||||
'#prefix' => '<li>',
|
||||
'#suffix' => "</li>\n",
|
||||
),
|
||||
'nodes' => array(
|
||||
"node_$node->nid" => array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => $node->nid,
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
drupal_delete_add_callback(array('node_delete_post' => array($node->nid, $node->title, $node->type)));
|
||||
node_delete($node->nid);
|
||||
}
|
||||
$form['suffix'] = array('#value' => '</ul>');
|
||||
|
||||
$form['operation'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => 'delete',
|
||||
);
|
||||
|
||||
// New package for the main admin callback.
|
||||
drupal_delete_initiate('node', 'admin');
|
||||
|
||||
// Add the main callback for the mass deletion last.
|
||||
drupal_delete_add_callback(array('node_multiple_delete_confirm_post' => array()));
|
||||
|
||||
return drupal_delete_confirm(
|
||||
array(
|
||||
'form' => $form,
|
||||
'question' => t('Are you sure you want to delete these items?'),
|
||||
'path' => 'admin/content/node',
|
||||
'yes' => t('Delete all'),
|
||||
'destination' => 'admin/content/node',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function node_multiple_delete_confirm_submit($form, &$form_state) {
|
||||
if ($form_state['values']['confirm']) {
|
||||
foreach ($form_state['values']['nodes'] as $nid => $value) {
|
||||
node_delete($nid);
|
||||
}
|
||||
drupal_set_message(t('The items have been deleted.'));
|
||||
}
|
||||
$form_state['redirect'] = 'admin/content/node';
|
||||
return;
|
||||
function node_multiple_delete_confirm_post() {
|
||||
// Clear the cache so an anonymous poster can see the nodes being deleted.
|
||||
cache_clear_all();
|
||||
drupal_set_message(t('The items have been deleted.'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1789,32 +1827,44 @@ function node_revision_revert($nid, $revision) {
|
|||
* revision is deleted.
|
||||
*/
|
||||
function node_revision_delete($nid, $revision) {
|
||||
if (user_access('administer nodes')) {
|
||||
$node = node_load($nid);
|
||||
if (node_access('delete', $node)) {
|
||||
// Don't delete the current revision
|
||||
if ($revision != $node->vid) {
|
||||
$node = node_load($nid, $revision);
|
||||
$node = node_load($nid);
|
||||
|
||||
db_query("DELETE FROM {node_revisions} WHERE nid = %d AND vid = %d", $nid, $revision);
|
||||
node_invoke_nodeapi($node, 'delete revision');
|
||||
drupal_set_message(t('Deleted %title revision %revision.', array('%title' => $node->title, '%revision' => $revision)));
|
||||
watchdog('content', '@type: deleted %title revision %revision.', array('@type' => $node->type, '%title' => $node->title, '%revision' => $revision));
|
||||
}
|
||||
if (user_access('administer nodes') && node_access('delete', $node)) {
|
||||
|
||||
else {
|
||||
drupal_set_message(t('Deletion failed. You tried to delete the current revision.'));
|
||||
}
|
||||
if (db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d', $nid)) > 1) {
|
||||
drupal_goto("node/$nid/revisions");
|
||||
}
|
||||
else {
|
||||
drupal_goto("node/$nid");
|
||||
}
|
||||
// Don't delete the current revision
|
||||
if ($revision != $node->vid) {
|
||||
$node = node_load($nid, $revision);
|
||||
|
||||
drupal_delete_initiate('node_revision', $revision);
|
||||
drupal_delete_add_callback(array('node_revision_delete_post' => array($node, $revision)));
|
||||
drupal_delete_add_query('DELETE FROM {node_revisions} WHERE vid = %d', $revision);
|
||||
node_invoke_nodeapi($node, 'delete revision');
|
||||
drupal_delete_execute();
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Deletion failed. You tried to delete the current revision.'));
|
||||
}
|
||||
}
|
||||
else {
|
||||
drupal_access_denied();
|
||||
}
|
||||
}
|
||||
|
||||
drupal_access_denied();
|
||||
/**
|
||||
* Post revision deletion opertations.
|
||||
*/
|
||||
function node_revision_delete_post($node, $revision) {
|
||||
|
||||
drupal_set_message(t('Deleted %title revision %revision.', array('%title' => $node->title, '%revision' => $revision)));
|
||||
watchdog('content', '@type: deleted %title revision %revision.', array('@type' => t($node->type), '%title' => $node->title, '%revision' => $revision));
|
||||
|
||||
|
||||
if (db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d', $node->nid)) > 1) {
|
||||
drupal_goto("node/$node->nid/revisions");
|
||||
}
|
||||
else {
|
||||
drupal_goto("node/$node->nid");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2371,25 +2421,25 @@ function node_form_submit($form, &$form_state) {
|
|||
* Menu callback -- ask for confirmation of node deletion
|
||||
*/
|
||||
function node_delete_confirm(&$form_state, $node) {
|
||||
$form['nid'] = array('#type' => 'value', '#value' => $node->nid);
|
||||
|
||||
return confirm_form($form,
|
||||
t('Are you sure you want to delete %title?', array('%title' => $node->title)),
|
||||
isset($_GET['destination']) ? $_GET['destination'] : 'node/'. $node->nid,
|
||||
t('This action cannot be undone.'),
|
||||
t('Delete'), t('Cancel'));
|
||||
}
|
||||
drupal_delete_initiate('node', $node->nid);
|
||||
drupal_delete_add_callback(
|
||||
array(
|
||||
'node_delete_post' => array($node->nid, $node->title, $node->type),
|
||||
// Clear the cache so an anonymous poster can see the node being deleted.
|
||||
'cache_clear_all' => array(),
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Execute node deletion
|
||||
*/
|
||||
function node_delete_confirm_submit($form, &$form_state) {
|
||||
if ($form_state['values']['confirm']) {
|
||||
node_delete($form_state['values']['nid']);
|
||||
}
|
||||
node_delete($node->nid, FALSE);
|
||||
|
||||
$form_state['redirect'] = '<front>';
|
||||
return;
|
||||
return drupal_delete_confirm(
|
||||
array(
|
||||
'question' => t('Are you sure you want to delete %title?', array('%title' => $node->title)),
|
||||
'path' => isset($_GET['destination']) ? $_GET['destination'] : 'node/'. $node->nid,
|
||||
'destination' => isset($_GET['destination']) ? $_GET['destination'] : '<front>',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2400,25 +2450,25 @@ 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);
|
||||
drupal_delete_add_query('DELETE FROM {node} WHERE nid = %d', $node->nid);
|
||||
drupal_delete_add_query('DELETE FROM {node_revisions} WHERE nid = %d', $node->nid);
|
||||
|
||||
// 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();
|
||||
|
||||
// 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', '@type: deleted %title.', array('@type' => $node->type, '%title' => $node->title));
|
||||
}
|
||||
}
|
||||
|
||||
function node_delete_post($nid, $title, $type) {
|
||||
|
||||
// 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', '@type: deleted %title.', array('@type' => t($type), '%title' => $title));
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback for revisions related activities.
|
||||
*/
|
||||
|
|
|
@ -127,12 +127,12 @@ function path_admin_delete($pid = 0) {
|
|||
function path_set_alias($path = NULL, $alias = NULL, $pid = NULL, $language = '') {
|
||||
if ($path && !$alias) {
|
||||
// Delete based on path
|
||||
db_query("DELETE FROM {url_alias} WHERE src = '%s' AND language = '%s'", $path, $language);
|
||||
drupal_delete_add_query("DELETE FROM {url_alias} WHERE src = '%s' AND language = '%s'", $path, $language);
|
||||
drupal_clear_path_cache();
|
||||
}
|
||||
else if (!$path && $alias) {
|
||||
// Delete based on alias
|
||||
db_query("DELETE FROM {url_alias} WHERE dst = '%s' AND language = '%s'", $alias, $language);
|
||||
drupal_delete_add_query("DELETE FROM {url_alias} WHERE dst = '%s' AND language = '%s'", $alias, $language);
|
||||
drupal_clear_path_cache();
|
||||
}
|
||||
else if ($path && $alias) {
|
||||
|
|
|
@ -91,9 +91,9 @@ function poll_cron() {
|
|||
* Implementation of hook_delete().
|
||||
*/
|
||||
function poll_delete($node) {
|
||||
db_query("DELETE FROM {poll} WHERE nid = %d", $node->nid);
|
||||
db_query("DELETE FROM {poll_choices} WHERE nid = %d", $node->nid);
|
||||
db_query("DELETE FROM {poll_votes} WHERE nid = %d", $node->nid);
|
||||
drupal_delete_add_query('DELETE FROM {poll} WHERE nid = %d', $node->nid);
|
||||
drupal_delete_add_query('DELETE FROM {poll_choices} WHERE nid = %d', $node->nid);
|
||||
drupal_delete_add_query('DELETE FROM {poll_votes} WHERE nid = %d', $node->nid);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -553,7 +553,7 @@ function statistics_nodeapi(&$node, $op, $arg = 0) {
|
|||
switch ($op) {
|
||||
case 'delete':
|
||||
// clean up statistics table when node is deleted
|
||||
db_query('DELETE FROM {node_counter} WHERE nid = %d', $node->nid);
|
||||
drupal_delete_add_query('DELETE FROM {node_counter} WHERE nid = %d', $node->nid);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2420,21 +2420,26 @@ function system_node_type($op, $info) {
|
|||
* block <em>foo</em>?").
|
||||
* @param $path
|
||||
* The page to go to if the user denies the action.
|
||||
* Can be either a drupal path, or an array with the keys 'path', 'query', 'fragment'.
|
||||
* @param $description
|
||||
* Additional text to display (defaults to "This action cannot be undone.").
|
||||
* @param $yes
|
||||
* A caption for the button which confirms the action (e.g. "Delete",
|
||||
* "Replace", ...).
|
||||
* @param $no
|
||||
* A caption for the link which denies the action (e.g. "Cancel").
|
||||
* @param $name
|
||||
* The internal name used to refer to the confirmation item.
|
||||
* Can be either a Drupal path, or an array with the keys 'path', 'query', 'fragment'.
|
||||
* @param $options
|
||||
* An associative array of options, with the following key/value pairs:
|
||||
* 'description' => Additional text to display.
|
||||
* Default is "This action cannot be undone".
|
||||
* 'yes' => A caption for the button which confirms the action (e.g. "Confirm",
|
||||
* "Replace", ...). Default is "Delete".
|
||||
* 'no' => A caption for the link which denies the action (e.g. "Cancel").
|
||||
* Default is "Cancel".
|
||||
* 'name' => The internal name used to refer to the confirmation item.
|
||||
* Default is "confirm".
|
||||
* 'destination' => A destination page to go to after form submission -- the value can
|
||||
* be of any form of the $goto argument accepted by drupal_redirect().
|
||||
*
|
||||
* @return
|
||||
* The form.
|
||||
*/
|
||||
function confirm_form($form, $question, $path, $description = NULL, $yes = NULL, $no = NULL, $name = 'confirm') {
|
||||
$description = isset($description) ? $description : t('This action cannot be undone.');
|
||||
function confirm_form($form, $question, $path, $options = array()) {
|
||||
$description = isset($options['description']) ? $options['description'] : t('This action cannot be undone.');
|
||||
$name = isset($options['name']) ? $options['name'] : 'confirm';
|
||||
|
||||
// Prepare cancel link
|
||||
$query = $fragment = NULL;
|
||||
|
@ -2443,24 +2448,37 @@ function confirm_form($form, $question, $path, $description = NULL, $yes = NULL,
|
|||
$fragment = isset($path['fragment']) ? $path['fragment'] : NULL;
|
||||
$path = isset($path['path']) ? $path['path'] : NULL;
|
||||
}
|
||||
$cancel = l($no ? $no : t('Cancel'), $path, array('query' => $query, 'fragment' => $fragment));
|
||||
$cancel = l(isset($options['no']) ? $options['no'] : t('Cancel'), $path, array('query' => $query, 'fragment' => $fragment));
|
||||
|
||||
drupal_set_title($question);
|
||||
|
||||
// Confirm form fails duplication check, as the form values rarely change -- so skip it.
|
||||
$form['#skip_duplicate_check'] = TRUE;
|
||||
|
||||
$form['#attributes'] = array('class' => 'confirmation');
|
||||
$form['description'] = array('#value' => $description);
|
||||
$form[$name] = array('#type' => 'hidden', '#value' => 1);
|
||||
if (isset($options['destination'])) {
|
||||
$form['destination'] = array('#type' => 'value', '#value' => $options['destination']);
|
||||
}
|
||||
|
||||
$form['actions'] = array('#prefix' => '<div class="container-inline">', '#suffix' => '</div>');
|
||||
$form['actions']['submit'] = array('#type' => 'submit', '#value' => $yes ? $yes : t('Confirm'));
|
||||
$form['actions']['submit'] = array('#type' => 'submit', '#value' => isset($options['yes']) ? $options['yes'] : t('Delete'));
|
||||
$form['actions']['cancel'] = array('#value' => $cancel);
|
||||
|
||||
$form['#theme'] = 'confirm_form';
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes confirmation pages for the Deletion API.
|
||||
*/
|
||||
function delete_confirm_submit($form, &$form_state) {
|
||||
if ($form_state['values']['delete']) {
|
||||
drupal_delete_execute();
|
||||
}
|
||||
if (isset($form_state['values']['destination'])) {
|
||||
$form_state['redirect'] = $form_state['values']['destination'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a user is in compact mode.
|
||||
*/
|
||||
|
|
|
@ -876,14 +876,14 @@ function taxonomy_node_save($node, $terms) {
|
|||
* 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_add_query('DELETE FROM {term_node} WHERE nid = %d', $node->nid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove associations of a node to its terms.
|
||||
*/
|
||||
function taxonomy_node_delete_revision($node) {
|
||||
db_query('DELETE FROM {term_node} WHERE vid = %d', $node->vid);
|
||||
drupal_delete_add_query('DELETE FROM {term_node} WHERE vid = %d', $node->vid);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -575,31 +575,44 @@ function upload_delete($node) {
|
|||
}
|
||||
|
||||
foreach ($files as $fid => $file) {
|
||||
// Delete all files associated with the node
|
||||
db_query('DELETE FROM {files} WHERE fid = %d', $fid);
|
||||
file_delete($file->filepath);
|
||||
// Delete all file revision information associated with the node
|
||||
drupal_delete_add_query('DELETE FROM {files} WHERE fid = %d', $fid);
|
||||
}
|
||||
|
||||
// Delete all file revision information associated with the node
|
||||
db_query('DELETE FROM {upload} WHERE nid = %d', $node->nid);
|
||||
// Delete all files associated with the node
|
||||
drupal_delete_add_query('DELETE FROM {upload} WHERE nid = %d', $node->nid);
|
||||
|
||||
// Register a callback to delete the files.
|
||||
drupal_delete_add_callback(array('upload_delete_post' => array($files)));
|
||||
}
|
||||
|
||||
function upload_delete_revision($node) {
|
||||
if (is_array($node->files)) {
|
||||
$files = array();
|
||||
foreach ($node->files as $file) {
|
||||
// Check if the file will be used after this revision is deleted
|
||||
$count = db_result(db_query('SELECT COUNT(fid) FROM {upload} WHERE fid = %d', $file->fid));
|
||||
|
||||
// if the file won't be used, delete it
|
||||
if ($count < 2) {
|
||||
db_query('DELETE FROM {files} WHERE fid = %d', $file->fid);
|
||||
file_delete($file->filepath);
|
||||
drupal_delete_add_query('DELETE FROM {files} WHERE fid = %d', $file->fid);
|
||||
$files[$file->fid] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delete the revision
|
||||
db_query('DELETE FROM {upload} WHERE vid = %d', $node->vid);
|
||||
// Delete the revision.
|
||||
drupal_delete_add_query('DELETE FROM {upload} WHERE vid = %d', $node->vid);
|
||||
|
||||
// Register a callback to delete the files.
|
||||
drupal_delete_add_callback(array('upload_delete_post' => array($files)));
|
||||
}
|
||||
|
||||
function upload_delete_post($files) {
|
||||
foreach ($files as $file) {
|
||||
// Delete all files associated with the node or revision.
|
||||
file_delete($file->filepath);
|
||||
}
|
||||
}
|
||||
|
||||
function _upload_form($node) {
|
||||
|
|
Loading…
Reference in New Issue