Issue #1346032 by xjm, aspilicious: Fixed Ordering of hook_entity_delete() is inconsistent.

8.0.x
catch 2011-12-17 21:43:37 +09:00
parent 463a710b0d
commit a3ebad0633
27 changed files with 506 additions and 166 deletions

View File

@ -1225,6 +1225,7 @@ function file_create_filename($basename, $directory) {
* @see file_unmanaged_delete()
* @see file_usage_list()
* @see file_usage_delete()
* @see hook_file_predelete()
* @see hook_file_delete()
*/
function file_delete(stdClass $file, $force = FALSE) {
@ -1246,15 +1247,20 @@ function file_delete(stdClass $file, $force = FALSE) {
return $references;
}
// Let other modules clean up any references to the deleted file.
module_invoke_all('file_delete', $file);
module_invoke_all('entity_delete', $file, 'file');
// Let other modules clean up any references to the file prior to deletion.
module_invoke_all('file_predelete', $file);
module_invoke_all('entity_predelete', $file, 'file');
// Make sure the file is deleted before removing its row from the
// database, so UIs can still find the file in the database.
if (file_unmanaged_delete($file->uri)) {
db_delete('file_managed')->condition('fid', $file->fid)->execute();
db_delete('file_usage')->condition('fid', $file->fid)->execute();
// Let other modules respond to file deletion.
module_invoke_all('file_delete', $file);
module_invoke_all('entity_delete', $file, 'file');
return TRUE;
}
return FALSE;

View File

@ -959,9 +959,9 @@ function book_node_update($node) {
}
/**
* Implements hook_node_delete().
* Implements hook_node_predelete().
*/
function book_node_delete($node) {
function book_node_predelete($node) {
if (!empty($node->book['bid'])) {
if ($node->nid == $node->book['bid']) {
// Handle deletion of a top-level post.

View File

@ -129,12 +129,39 @@ function hook_comment_unpublish($comment) {
}
/**
* The comment is being deleted by the moderator.
* Act before comment deletion.
*
* This hook is invoked from comment_delete_multiple() before
* field_attach_delete() is called and before the comment is actually removed
* from the database.
*
* @param $comment
* Passes in the comment the action is being performed on.
* @return
* Nothing.
* The comment object for the comment that is about to be deleted.
*
* @see hook_comment_delete()
* @see comment_delete_multiple()
* @see entity_delete_multiple()
*/
function hook_comment_predelete($comment) {
// Delete a record associated with the comment in a custom table.
db_delete('example_comment_table')
->condition('cid', $comment->cid)
->execute();
}
/**
* Respond to comment deletion.
*
* This hook is invoked from comment_delete_multiple() after
* field_attach_delete() has called and after the comment has been removed from
* the database.
*
* @param $comment
* The comment object for the comment that has been deleted.
*
* @see hook_comment_predelete()
* @see comment_delete_multiple()
* @see entity_delete_multiple()
*/
function hook_comment_delete($comment) {
drupal_set_message(t('Comment: @subject has been deleted', array('@subject' => $comment->subject)));

View File

@ -1304,9 +1304,9 @@ function comment_node_insert($node) {
}
/**
* Implements hook_node_delete().
* Implements hook_node_predelete().
*/
function comment_node_delete($node) {
function comment_node_predelete($node) {
$cids = db_query('SELECT cid FROM {comment} WHERE nid = :nid', array(':nid' => $node->nid))->fetchCol();
comment_delete_multiple($cids);
db_delete('node_comment_statistics')
@ -1402,9 +1402,9 @@ function comment_user_cancel($edit, $account, $method) {
}
/**
* Implements hook_user_delete().
* Implements hook_user_predelete().
*/
function comment_user_delete($account) {
function comment_user_predelete($account) {
$cids = db_query('SELECT c.cid FROM {comment} c WHERE uid = :uid', array(':uid' => $account->uid))->fetchCol();
comment_delete_multiple($cids);
}
@ -1457,6 +1457,9 @@ function comment_delete($cid) {
*
* @param $cids
* The comment to delete.
*
* @see hook_comment_predelete()
* @see hook_comment_delete()
*/
function comment_delete_multiple($cids) {
entity_delete_multiple('comment', $cids);

View File

@ -270,7 +270,7 @@ function hook_entity_insert($entity, $type) {
* @param $entity
* The entity object.
* @param $type
* The type of entity being updated (i.e. node, user, comment).
* The type of entity being updated (e.g. node, user, comment).
*/
function hook_entity_update($entity, $type) {
// Update the entity's entry in a fictional table of all entities.
@ -286,10 +286,42 @@ function hook_entity_update($entity, $type) {
}
/**
* Act on entities when deleted.
* Act before entity deletion.
*
* This hook runs after the entity type-specific predelete hook.
*
* @param $entity
* The entity object.
* The entity object for the entity that is about to be deleted.
* @param $type
* The type of entity being deleted (e.g. node, user, comment).
*/
function hook_entity_predelete($entity, $type) {
// Count references to this entity in a custom table before they are removed
// upon entity deletion.
list($id) = entity_extract_ids($type, $entity);
$count = db_select('example_entity_data')
->condition('type', $type)
->condition('id', $id)
->countQuery()
->execute()
->fetchField();
// Log the count in a table that records this statistic for deleted entities.
$ref_count_record = (object) array(
'count' => $count,
'type' => $type,
'id' => $id,
);
drupal_write_record('example_deleted_entity_statistics', $ref_count_record);
}
/**
* Respond to entity deletion.
*
* This hook runs after the entity type-specific delete hook.
*
* @param $entity
* The entity object for the entity that has been deleted.
* @param $type
* The type of entity being deleted (i.e. node, user, comment).
*/

View File

@ -454,6 +454,9 @@ class EntityDatabaseStorageController extends DrupalDefaultEntityController impl
try {
$this->preDelete($entities);
foreach ($entities as $id => $entity) {
$this->invokeHook('predelete', $entity);
}
$ids = array_keys($entities);
db_delete($this->entityInfo['base table'])
@ -548,8 +551,8 @@ class EntityDatabaseStorageController extends DrupalDefaultEntityController impl
/**
* Invokes a hook on behalf of the entity.
*
* @param $op
* One of 'presave', 'insert', 'update', or 'delete'.
* @param $hook
* One of 'presave', 'insert', 'update', 'predelete', or 'delete'.
* @param $entity
* The entity object.
*/

View File

@ -212,6 +212,59 @@ function entity_crud_hook_test_user_update() {
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
}
//
// Predelete hooks
//
/**
* Implements hook_entity_predelete().
*/
function entity_crud_hook_test_entity_predelete($entity, $type) {
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called for type ' . $type);
}
/**
* Implements hook_comment_predelete().
*/
function entity_crud_hook_test_comment_predelete() {
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
}
/**
* Implements hook_file_predelete().
*/
function entity_crud_hook_test_file_predelete() {
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
}
/**
* Implements hook_node_predelete().
*/
function entity_crud_hook_test_node_predelete() {
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
}
/**
* Implements hook_taxonomy_term_predelete().
*/
function entity_crud_hook_test_taxonomy_term_predelete() {
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
}
/**
* Implements hook_taxonomy_vocabulary_predelete().
*/
function entity_crud_hook_test_taxonomy_vocabulary_predelete() {
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
}
/**
* Implements hook_user_predelete().
*/
function entity_crud_hook_test_user_predelete() {
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
}
//
// Delete hooks
//

View File

@ -6,6 +6,7 @@
* - hook_entity_insert()
* - hook_entity_load()
* - hook_entity_update()
* - hook_entity_predelete()
* - hook_entity_delete()
* As well as all type-specific hooks, like hook_node_insert(),
* hook_comment_update(), etc.
@ -27,24 +28,28 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
}
/**
* Pass if the message $text was set by one of the CRUD hooks in
* entity_crud_hook_test.module, i.e., if the $text is an element of
* $_SESSION['entity_crud_hook_test'].
* Checks the order of CRUD hook execution messages.
*
* @param $text
* Plain text to look for.
* @param $message
* Message to display.
* @param $group
* The group this message belongs to, defaults to 'Other'.
* @return
* TRUE on pass, FALSE on fail.
* entity_crud_hook_test.module implements all core entity CRUD hooks and
* stores a message for each in $_SESSION['entity_crud_hook_test'].
*
* @param $messages
* An array of plain-text messages in the order they should appear.
*/
protected function assertHookMessage($text, $message = NULL, $group = 'Other') {
if (!isset($message)) {
$message = $text;
protected function assertHookMessageOrder($messages) {
$positions = array();
foreach ($messages as $message) {
// Verify that each message is found and record its position.
$position = array_search($message, $_SESSION['entity_crud_hook_test']);
if ($this->assertTrue($position !== FALSE, $message)) {
$positions[] = $position;
}
}
return $this->assertTrue(array_search($text, $_SESSION['entity_crud_hook_test']) !== FALSE, $message, $group);
// Sort the positions and ensure they remain in the same order.
$sorted = $positions;
sort($sorted);
$this->assertTrue($sorted == $positions, 'The hook messages appear in the correct order.');
}
/**
@ -77,34 +82,45 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
'status' => 1,
'language' => LANGUAGE_NONE,
));
$_SESSION['entity_crud_hook_test'] = array();
comment_save($comment);
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type comment');
$this->assertHookMessage('entity_crud_hook_test_comment_presave called');
$this->assertHookMessage('entity_crud_hook_test_entity_insert called for type comment');
$this->assertHookMessage('entity_crud_hook_test_comment_insert called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_comment_presave called',
'entity_crud_hook_test_entity_presave called for type comment',
'entity_crud_hook_test_comment_insert called',
'entity_crud_hook_test_entity_insert called for type comment',
));
$_SESSION['entity_crud_hook_test'] = array();
$comment = comment_load($comment->cid);
$this->assertHookMessage('entity_crud_hook_test_entity_load called for type comment');
$this->assertHookMessage('entity_crud_hook_test_comment_load called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_entity_load called for type comment',
'entity_crud_hook_test_comment_load called',
));
$_SESSION['entity_crud_hook_test'] = array();
$comment->subject = 'New subject';
comment_save($comment);
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type comment');
$this->assertHookMessage('entity_crud_hook_test_comment_presave called');
$this->assertHookMessage('entity_crud_hook_test_entity_update called for type comment');
$this->assertHookMessage('entity_crud_hook_test_comment_update called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_comment_presave called',
'entity_crud_hook_test_entity_presave called for type comment',
'entity_crud_hook_test_comment_update called',
'entity_crud_hook_test_entity_update called for type comment',
));
$_SESSION['entity_crud_hook_test'] = array();
comment_delete($comment->cid);
$this->assertHookMessage('entity_crud_hook_test_entity_delete called for type comment');
$this->assertHookMessage('entity_crud_hook_test_comment_delete called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_comment_predelete called',
'entity_crud_hook_test_entity_predelete called for type comment',
'entity_crud_hook_test_comment_delete called',
'entity_crud_hook_test_entity_delete called for type comment',
));
}
/**
@ -126,31 +142,41 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
$_SESSION['entity_crud_hook_test'] = array();
file_save($file);
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type file');
$this->assertHookMessage('entity_crud_hook_test_file_presave called');
$this->assertHookMessage('entity_crud_hook_test_entity_insert called for type file');
$this->assertHookMessage('entity_crud_hook_test_file_insert called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_file_presave called',
'entity_crud_hook_test_entity_presave called for type file',
'entity_crud_hook_test_file_insert called',
'entity_crud_hook_test_entity_insert called for type file',
));
$_SESSION['entity_crud_hook_test'] = array();
$file = file_load($file->fid);
$this->assertHookMessage('entity_crud_hook_test_entity_load called for type file');
$this->assertHookMessage('entity_crud_hook_test_file_load called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_entity_load called for type file',
'entity_crud_hook_test_file_load called',
));
$_SESSION['entity_crud_hook_test'] = array();
$file->filename = 'new.entity_crud_hook_test.file';
file_save($file);
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type file');
$this->assertHookMessage('entity_crud_hook_test_file_presave called');
$this->assertHookMessage('entity_crud_hook_test_entity_update called for type file');
$this->assertHookMessage('entity_crud_hook_test_file_update called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_file_presave called',
'entity_crud_hook_test_entity_presave called for type file',
'entity_crud_hook_test_file_update called',
'entity_crud_hook_test_entity_update called for type file',
));
$_SESSION['entity_crud_hook_test'] = array();
file_delete($file);
$this->assertHookMessage('entity_crud_hook_test_entity_delete called for type file');
$this->assertHookMessage('entity_crud_hook_test_file_delete called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_file_predelete called',
'entity_crud_hook_test_entity_predelete called for type file',
'entity_crud_hook_test_file_delete called',
'entity_crud_hook_test_entity_delete called for type file',
));
}
/**
@ -172,31 +198,41 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
$_SESSION['entity_crud_hook_test'] = array();
node_save($node);
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type node');
$this->assertHookMessage('entity_crud_hook_test_node_presave called');
$this->assertHookMessage('entity_crud_hook_test_entity_insert called for type node');
$this->assertHookMessage('entity_crud_hook_test_node_insert called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_node_presave called',
'entity_crud_hook_test_entity_presave called for type node',
'entity_crud_hook_test_node_insert called',
'entity_crud_hook_test_entity_insert called for type node',
));
$_SESSION['entity_crud_hook_test'] = array();
$node = node_load($node->nid);
$this->assertHookMessage('entity_crud_hook_test_entity_load called for type node');
$this->assertHookMessage('entity_crud_hook_test_node_load called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_entity_load called for type node',
'entity_crud_hook_test_node_load called',
));
$_SESSION['entity_crud_hook_test'] = array();
$node->title = 'New title';
node_save($node);
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type node');
$this->assertHookMessage('entity_crud_hook_test_node_presave called');
$this->assertHookMessage('entity_crud_hook_test_entity_update called for type node');
$this->assertHookMessage('entity_crud_hook_test_node_update called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_node_presave called',
'entity_crud_hook_test_entity_presave called for type node',
'entity_crud_hook_test_node_update called',
'entity_crud_hook_test_entity_update called for type node',
));
$_SESSION['entity_crud_hook_test'] = array();
node_delete($node->nid);
$this->assertHookMessage('entity_crud_hook_test_entity_delete called for type node');
$this->assertHookMessage('entity_crud_hook_test_node_delete called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_node_predelete called',
'entity_crud_hook_test_entity_predelete called for type node',
'entity_crud_hook_test_node_delete called',
'entity_crud_hook_test_entity_delete called for type node',
));
}
/**
@ -220,31 +256,41 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
$_SESSION['entity_crud_hook_test'] = array();
taxonomy_term_save($term);
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_term');
$this->assertHookMessage('entity_crud_hook_test_taxonomy_term_presave called');
$this->assertHookMessage('entity_crud_hook_test_entity_insert called for type taxonomy_term');
$this->assertHookMessage('entity_crud_hook_test_taxonomy_term_insert called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_taxonomy_term_presave called',
'entity_crud_hook_test_entity_presave called for type taxonomy_term',
'entity_crud_hook_test_taxonomy_term_insert called',
'entity_crud_hook_test_entity_insert called for type taxonomy_term',
));
$_SESSION['entity_crud_hook_test'] = array();
$term = taxonomy_term_load($term->tid);
$this->assertHookMessage('entity_crud_hook_test_entity_load called for type taxonomy_term');
$this->assertHookMessage('entity_crud_hook_test_taxonomy_term_load called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_entity_load called for type taxonomy_term',
'entity_crud_hook_test_taxonomy_term_load called',
));
$_SESSION['entity_crud_hook_test'] = array();
$term->name = 'New name';
taxonomy_term_save($term);
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_term');
$this->assertHookMessage('entity_crud_hook_test_taxonomy_term_presave called');
$this->assertHookMessage('entity_crud_hook_test_entity_update called for type taxonomy_term');
$this->assertHookMessage('entity_crud_hook_test_taxonomy_term_update called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_taxonomy_term_presave called',
'entity_crud_hook_test_entity_presave called for type taxonomy_term',
'entity_crud_hook_test_taxonomy_term_update called',
'entity_crud_hook_test_entity_update called for type taxonomy_term',
));
$_SESSION['entity_crud_hook_test'] = array();
taxonomy_term_delete($term->tid);
$this->assertHookMessage('entity_crud_hook_test_entity_delete called for type taxonomy_term');
$this->assertHookMessage('entity_crud_hook_test_taxonomy_term_delete called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_taxonomy_term_predelete called',
'entity_crud_hook_test_entity_predelete called for type taxonomy_term',
'entity_crud_hook_test_taxonomy_term_delete called',
'entity_crud_hook_test_entity_delete called for type taxonomy_term',
));
}
/**
@ -260,31 +306,41 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
$_SESSION['entity_crud_hook_test'] = array();
taxonomy_vocabulary_save($vocabulary);
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_vocabulary');
$this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_presave called');
$this->assertHookMessage('entity_crud_hook_test_entity_insert called for type taxonomy_vocabulary');
$this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_insert called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_taxonomy_vocabulary_presave called',
'entity_crud_hook_test_entity_presave called for type taxonomy_vocabulary',
'entity_crud_hook_test_taxonomy_vocabulary_insert called',
'entity_crud_hook_test_entity_insert called for type taxonomy_vocabulary',
));
$_SESSION['entity_crud_hook_test'] = array();
$vocabulary = taxonomy_vocabulary_load($vocabulary->vid);
$this->assertHookMessage('entity_crud_hook_test_entity_load called for type taxonomy_vocabulary');
$this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_load called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_entity_load called for type taxonomy_vocabulary',
'entity_crud_hook_test_taxonomy_vocabulary_load called',
));
$_SESSION['entity_crud_hook_test'] = array();
$vocabulary->name = 'New name';
taxonomy_vocabulary_save($vocabulary);
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_vocabulary');
$this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_presave called');
$this->assertHookMessage('entity_crud_hook_test_entity_update called for type taxonomy_vocabulary');
$this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_update called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_taxonomy_vocabulary_presave called',
'entity_crud_hook_test_entity_presave called for type taxonomy_vocabulary',
'entity_crud_hook_test_taxonomy_vocabulary_update called',
'entity_crud_hook_test_entity_update called for type taxonomy_vocabulary',
));
$_SESSION['entity_crud_hook_test'] = array();
taxonomy_vocabulary_delete($vocabulary->vid);
$this->assertHookMessage('entity_crud_hook_test_entity_delete called for type taxonomy_vocabulary');
$this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_delete called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_taxonomy_vocabulary_predelete called',
'entity_crud_hook_test_entity_predelete called for type taxonomy_vocabulary',
'entity_crud_hook_test_taxonomy_vocabulary_delete called',
'entity_crud_hook_test_entity_delete called for type taxonomy_vocabulary',
));
}
/**
@ -302,31 +358,41 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
$_SESSION['entity_crud_hook_test'] = array();
$account = user_save($account, $edit);
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type user');
$this->assertHookMessage('entity_crud_hook_test_user_presave called');
$this->assertHookMessage('entity_crud_hook_test_entity_insert called for type user');
$this->assertHookMessage('entity_crud_hook_test_user_insert called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_user_presave called',
'entity_crud_hook_test_entity_presave called for type user',
'entity_crud_hook_test_user_insert called',
'entity_crud_hook_test_entity_insert called for type user',
));
$_SESSION['entity_crud_hook_test'] = array();
$account = user_load($account->uid);
$this->assertHookMessage('entity_crud_hook_test_entity_load called for type user');
$this->assertHookMessage('entity_crud_hook_test_user_load called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_entity_load called for type user',
'entity_crud_hook_test_user_load called',
));
$_SESSION['entity_crud_hook_test'] = array();
$edit['name'] = 'New name';
$account = user_save($account, $edit);
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type user');
$this->assertHookMessage('entity_crud_hook_test_user_presave called');
$this->assertHookMessage('entity_crud_hook_test_entity_update called for type user');
$this->assertHookMessage('entity_crud_hook_test_user_update called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_user_presave called',
'entity_crud_hook_test_entity_presave called for type user',
'entity_crud_hook_test_user_update called',
'entity_crud_hook_test_entity_update called for type user',
));
$_SESSION['entity_crud_hook_test'] = array();
user_delete($account->uid);
$this->assertHookMessage('entity_crud_hook_test_entity_delete called for type user');
$this->assertHookMessage('entity_crud_hook_test_user_delete called');
$this->assertHookMessageOrder(array(
'entity_crud_hook_test_user_predelete called',
'entity_crud_hook_test_entity_predelete called for type user',
'entity_crud_hook_test_user_delete called',
'entity_crud_hook_test_entity_delete called for type user',
));
}
}

View File

@ -347,9 +347,9 @@ function file_progress_implementation() {
}
/**
* Implements hook_file_delete().
* Implements hook_file_predelete().
*/
function file_file_delete($file) {
function file_file_predelete($file) {
// TODO: Remove references to a file that is in-use.
}

View File

@ -404,9 +404,9 @@ function forum_node_insert($node) {
}
/**
* Implements hook_node_delete().
* Implements hook_node_predelete().
*/
function forum_node_delete($node) {
function forum_node_predelete($node) {
if (_forum_node_check_node_type($node)) {
db_delete('forum')
->condition('nid', $node->nid)

View File

@ -323,9 +323,9 @@ function image_file_move($file, $source) {
}
/**
* Implements hook_file_delete().
* Implements hook_file_predelete().
*/
function image_file_delete($file) {
function image_file_predelete($file) {
// Delete any image derivatives of this image.
image_path_flush($file->uri);
}

View File

@ -550,9 +550,9 @@ function menu_node_save($node) {
}
/**
* Implements hook_node_delete().
* Implements hook_node_predelete().
*/
function menu_node_delete($node) {
function menu_node_predelete($node) {
// Delete all menu module links that point to this node.
$result = db_query("SELECT mlid FROM {menu_links} WHERE link_path = :path AND module = 'menu'", array(':path' => 'node/' . $node->nid), array('fetch' => PDO::FETCH_ASSOC));
foreach ($result as $m) {

View File

@ -88,10 +88,12 @@
* - Deleting a node (calling node_delete() or node_delete_multiple()):
* - Node is loaded (see Loading section above)
* - hook_delete() (node-type-specific)
* - hook_node_delete() (all)
* - hook_entity_delete() (all)
* - hook_node_predelete() (all)
* - hook_entity_predelete() (all)
* - field_attach_delete()
* - Node and revision information are deleted from database
* - hook_node_delete() (all)
* - hook_entity_delete() (all)
* - Deleting a node revision (calling node_revision_delete()):
* - Node is loaded (see Loading section above)
* - Revision information is deleted from database
@ -447,24 +449,43 @@ function hook_node_operations() {
}
/**
* Respond to node deletion.
* Act before node deletion.
*
* This hook is invoked from node_delete_multiple() after the type-specific
* hook_delete() has been invoked, but before hook_entity_delete and
* hook_delete() has been invoked, but before hook_entity_predelete() and
* field_attach_delete() are called, and before the node is removed from the
* node table in the database.
*
* @param $node
* The node that is being deleted.
* The node that is about to be deleted.
*
* @see hook_node_predelete()
* @see node_delete_multiple()
* @ingroup node_api_hooks
*/
function hook_node_delete($node) {
function hook_node_predelete($node) {
db_delete('mytable')
->condition('nid', $node->nid)
->execute();
}
/**
* Respond to node deletion.
*
* This hook is invoked from node_delete_multiple() after field_attach_delete()
* has been called and after the node has been removed from the database.
*
* @param $node
* The node that has been deleted.
*
* @see hook_node_predelete()
* @see node_delete_multiple()
* @ingroup node_api_hooks
*/
function hook_node_delete($node) {
drupal_set_message(t('Node: @title has been deleted', array('@title' => $node->title)));
}
/**
* Respond to deletion of a node revision.
*

View File

@ -1221,6 +1221,9 @@ function node_delete($nid) {
*
* @param $nids
* An array of node IDs.
*
* @see hook_node_predelete()
* @see hook_node_delete()
*/
function node_delete_multiple($nids) {
$transaction = db_transaction();
@ -1231,8 +1234,11 @@ function node_delete_multiple($nids) {
foreach ($nodes as $nid => $node) {
// Call the node-specific callback (if any):
node_invoke($node, 'delete');
module_invoke_all('node_delete', $node);
module_invoke_all('entity_delete', $node, 'node');
// Allow modules to act prior to node deletion.
module_invoke_all('node_predelete', $node);
module_invoke_all('entity_predelete', $node, 'node');
field_attach_delete('node', $node);
// Remove this node from the search index if needed.
@ -1257,6 +1263,12 @@ function node_delete_multiple($nids) {
db_delete('node_access')
->condition('nid', $nids, 'IN')
->execute();
foreach ($nodes as $nid => $node) {
// Allow modules to respond to node deletion.
module_invoke_all('node_delete', $node);
module_invoke_all('entity_delete', $node, 'node');
}
}
catch (Exception $e) {
$transaction->rollback();
@ -1815,9 +1827,9 @@ function node_user_cancel($edit, $account, $method) {
}
/**
* Implements hook_user_delete().
* Implements hook_user_predelete().
*/
function node_user_delete($account) {
function node_user_predelete($account) {
// Delete nodes (current revisions).
// @todo Introduce node_mass_delete() or make node_mass_update() more flexible.
$nodes = db_select('node', 'n')

View File

@ -192,10 +192,10 @@ function node_access_test_node_load($nodes, $types) {
}
/**
* Implements hook_node_delete().
* Implements hook_node_predelete().
*/
function node_access_test_node_delete($node) {
function node_access_test_node_predelete($node) {
db_delete('node_access_test')->condition('nid', $node->nid)->execute();
}

View File

@ -217,9 +217,9 @@ function path_node_update($node) {
}
/**
* Implements hook_node_delete().
* Implements hook_node_predelete().
*/
function path_node_delete($node) {
function path_node_predelete($node) {
// Delete all aliases associated with this node.
path_delete(array('source' => 'node/' . $node->nid));
}

View File

@ -986,9 +986,9 @@ function poll_user_cancel($edit, $account, $method) {
}
/**
* Implements hook_user_delete().
* Implements hook_user_predelete().
*/
function poll_user_delete($account) {
function poll_user_predelete($account) {
db_delete('poll_vote')
->condition('uid', $account->uid)
->execute();

View File

@ -303,9 +303,9 @@ function file_test_file_move($file, $source) {
}
/**
* Implements hook_file_delete().
* Implements hook_file_predelete().
*/
function file_test_file_delete($file) {
function file_test_file_predelete($file) {
_file_test_log_call('delete', array($file));
}

View File

@ -218,9 +218,9 @@ function statistics_user_cancel($edit, $account, $method) {
}
/**
* Implements hook_user_delete().
* Implements hook_user_predelete().
*/
function statistics_user_delete($account) {
function statistics_user_predelete($account) {
db_delete('accesslog')
->condition('uid', $account->uid)
->execute();
@ -391,9 +391,9 @@ function _statistics_format_item($title, $path) {
}
/**
* Implements hook_node_delete().
* Implements hook_node_predelete().
*/
function statistics_node_delete($node) {
function statistics_node_predelete($node) {
// clean up statistics table when node is deleted
db_delete('node_counter')
->condition('nid', $node->nid)

View File

@ -2394,11 +2394,33 @@ function hook_file_move($file, $source) {
}
/**
* Respond to a file being deleted.
* Act prior to file deletion.
*
* This hook is invoked from file_delete() before the file is removed from the
* filesystem and before its records are removed from the database.
*
* @param $file
* The file that is about to be deleted.
*
* @see hook_file_delete()
* @see file_delete()
* @see upload_file_delete()
*/
function hook_file_predelete($file) {
// Delete all information associated with the file.
db_delete('upload')->condition('fid', $file->fid)->execute();
}
/**
* Respond to file deletion.
*
* This hook is invoked from file_delete() after the file has been removed from
* the filesystem and after its records have been removed from the database.
*
* @param $file
* The file that has just been deleted.
*
* @see hook_file_predelete()
* @see file_delete()
*/
function hook_file_delete($file) {

View File

@ -70,13 +70,37 @@ function hook_taxonomy_vocabulary_update($vocabulary) {
}
/**
* Respond to the deletion of taxonomy vocabularies.
* Act before taxonomy vocabulary deletion.
*
* Modules implementing this hook can respond to the deletion of taxonomy
* vocabularies from the database.
* This hook is invoked from taxonomy_vocabulary_delete() before
* field_attach_delete_bundle() is called and before the vocabulary is actually
* removed from the database.
*
* @param $vocabulary
* A taxonomy vocabulary object.
* The taxonomy vocabulary object for the vocabulary that is about to be
* deleted.
*
* @see hook_taxonomy_vocabulary_delete()
* @see taxonomy_vocabulary_delete()
*/
function hook_taxonomy_vocabulary_predelete($vocabulary) {
if (variable_get('taxonomy_' . $vocabulary->vid . '_synonyms', FALSE)) {
variable_del('taxonomy_' . $vocabulary->vid . '_synonyms');
}
}
/**
* Respond to taxonomy vocabulary deletion.
*
* This hook is invoked from taxonomy_vocabulary_delete() after
* field_attach_delete_bundle() has been called and after the vocabulary has
* been removed from the database.
*
* @param $vocabulary
* The taxonomy vocabulary object for the vocabulary that has been deleted.
*
* @see hook_taxonomy_vocabulary_predelete()
* @see taxonomy_vocabulary_delete()
*/
function hook_taxonomy_vocabulary_delete($vocabulary) {
if (variable_get('taxonomy_' . $vocabulary->vid . '_synonyms', FALSE)) {
@ -169,13 +193,31 @@ function hook_taxonomy_term_update($term) {
}
/**
* Respond to the deletion of taxonomy terms.
* Act before taxonomy term deletion.
*
* Modules implementing this hook can respond to the deletion of taxonomy
* terms from the database.
* This hook is invoked from taxonomy_term_delete() before
* field_attach_delete() is called and before the term is actually removed from
* the database.
*
* @param $term
* A taxonomy term object.
* The taxonomy term object for the term that is about to be deleted.
*
* @see taxonomy_term_delete()
*/
function hook_taxonomy_term_predelete($term) {
db_delete('term_synoynm')->condition('tid', $term->tid)->execute();
}
/**
* Respond to taxonomy term deletion.
*
* This hook is invoked from taxonomy_term_delete() after field_attach_delete()
* has been called and after the term has been removed from the database.
*
* @param $term
* The taxonomy term object for the term that has been deleted.
*
* @see taxonomy_term_delete()
*/
function hook_taxonomy_term_delete($term) {
db_delete('term_synoynm')->condition('tid', $term->tid)->execute();

View File

@ -449,12 +449,19 @@ function taxonomy_vocabulary_save($vocabulary) {
* A vocabulary ID.
* @return
* Constant indicating items were deleted.
*
* @see hook_taxonomy_vocabulary_predelete()
* @see hook_taxonomy_vocabulary_delete()
*/
function taxonomy_vocabulary_delete($vid) {
$vocabulary = taxonomy_vocabulary_load($vid);
$transaction = db_transaction();
try {
// Allow modules to act before vocabulary deletion.
module_invoke_all('taxonomy_vocabulary_predelete', $vocabulary);
module_invoke_all('entity_predelete', $vocabulary, 'taxonomy_vocabulary');
// Only load terms without a parent, child terms will get deleted too.
$result = db_query('SELECT t.tid FROM {taxonomy_term_data} t INNER JOIN {taxonomy_term_hierarchy} th ON th.tid = t.tid WHERE t.vid = :vid AND th.parent = 0', array(':vid' => $vid))->fetchCol();
foreach ($result as $tid) {
@ -465,6 +472,8 @@ function taxonomy_vocabulary_delete($vid) {
->execute();
field_attach_delete_bundle('taxonomy_term', $vocabulary->machine_name);
// Allow modules to respond to vocabulary deletion.
module_invoke_all('taxonomy_vocabulary_delete', $vocabulary);
module_invoke_all('entity_delete', $vocabulary, 'taxonomy_vocabulary');
@ -659,6 +668,9 @@ function taxonomy_term_save($term) {
* The term ID.
* @return
* Status constant indicating deletion.
*
* @see hook_taxonomy_term_predelete()
* @see hook_taxonomy_term_delete()
*/
function taxonomy_term_delete($tid) {
$transaction = db_transaction();
@ -667,6 +679,12 @@ function taxonomy_term_delete($tid) {
while ($tids) {
$children_tids = $orphans = array();
foreach ($tids as $tid) {
// Allow modules to act before term deletion.
if ($term = taxonomy_term_load($tid)) {
module_invoke_all('taxonomy_term_predelete', $term);
module_invoke_all('entity_predelete', $term, 'taxonomy_term');
}
// See if any of the term's children are about to be become orphans:
if ($children = taxonomy_get_children($tid)) {
foreach ($children as $child) {
@ -678,7 +696,7 @@ function taxonomy_term_delete($tid) {
}
}
if ($term = taxonomy_term_load($tid)) {
if ($term) {
db_delete('taxonomy_term_data')
->condition('tid', $tid)
->execute();
@ -687,6 +705,8 @@ function taxonomy_term_delete($tid) {
->execute();
field_attach_delete('taxonomy_term', $term);
// Allow modules to respond to term deletion.
module_invoke_all('taxonomy_term_delete', $term);
module_invoke_all('entity_delete', $term, 'taxonomy_term');
taxonomy_terms_static_reset();
@ -1806,9 +1826,9 @@ function taxonomy_node_update($node) {
}
/**
* Implements hook_node_delete().
* Implements hook_node_predelete().
*/
function taxonomy_node_delete($node) {
function taxonomy_node_predelete($node) {
// Clean up the {taxonomy_index} table when nodes are deleted.
taxonomy_delete_node_index($node);
}

View File

@ -177,9 +177,9 @@ function tracker_node_update($node, $arg = 0) {
}
/**
* Implements hook_node_delete().
* Implements hook_node_predelete().
*/
function tracker_node_delete($node, $arg = 0) {
function tracker_node_predelete($node, $arg = 0) {
db_delete('tracker_node')
->condition('nid', $node->nid)
->execute();

View File

@ -387,9 +387,9 @@ function translation_node_validate($node, $form) {
}
/**
* Implements hook_node_delete().
* Implements hook_node_predelete().
*/
function translation_node_delete($node) {
function translation_node_predelete($node) {
// Only act if we are dealing with a content type supporting translations.
if (translation_supported_type($node->type)) {
translation_remove_from_set($node);

View File

@ -309,9 +309,9 @@ function trigger_node_insert($node) {
}
/**
* Implements hook_node_delete().
* Implements hook_node_predelete().
*/
function trigger_node_delete($node) {
function trigger_node_predelete($node) {
_trigger_node($node, 'node_delete');
}
@ -501,9 +501,9 @@ function trigger_user_cancel($edit, $account, $method) {
}
/**
* Implements hook_user_delete().
* Implements hook_user_predelete().
*/
function trigger_user_delete($account) {
function trigger_user_predelete($account) {
$edit = array();
_trigger_user('user_delete', $edit, $account);
}

View File

@ -31,25 +31,46 @@ function hook_user_load($users) {
}
/**
* Respond to user deletion.
* Act before user deletion.
*
* This hook is invoked from user_delete_multiple() before field_attach_delete()
* is called and before users are actually removed from the database.
* This hook is invoked from user_delete_multiple() before
* field_attach_delete() is called and before the user is actually removed from
* the database.
*
* Modules should additionally implement hook_user_cancel() to process stored
* user data for other account cancellation methods.
*
* @param $account
* The account that is being deleted.
* The account that is about to be deleted.
*
* @see hook_user_delete()
* @see user_delete_multiple()
*/
function hook_user_delete($account) {
function hook_user_predelete($account) {
db_delete('mytable')
->condition('uid', $account->uid)
->execute();
}
/**
* Respond to user deletion.
*
* This hook is invoked from user_delete_multiple() after field_attach_delete()
* has been called and after the user has been removed from the database.
*
* Modules should additionally implement hook_user_cancel() to process stored
* user data for other account cancellation methods.
*
* @param $account
* The account that has been deleted.
*
* @see hook_user_predelete()
* @see user_delete_multiple()
*/
function hook_user_delete($account) {
drupal_set_message(t('User: @name has been deleted.', array('@name' => $account->name)));
}
/**
* Act on user account cancellations.
*
@ -60,7 +81,8 @@ function hook_user_delete($account) {
* Modules may add further methods via hook_user_cancel_methods_alter().
*
* This hook is NOT invoked for the 'user_cancel_delete' account cancellation
* method. To react on this method, implement hook_user_delete() instead.
* method. To react to that method, implement hook_user_predelete() or
* hook_user_delete() instead.
*
* Expensive operations should be added to the global account cancellation batch
* by using batch_set().

View File

@ -844,9 +844,9 @@ function user_file_move($file, $source) {
}
/**
* Implements hook_file_delete().
* Implements hook_file_predelete().
*/
function user_file_delete($file) {
function user_file_predelete($file) {
// Remove any references to the file.
db_update('users')
->fields(array('picture' => 0))
@ -2356,7 +2356,9 @@ function user_cancel($edit, $uid, $method) {
);
batch_set($batch);
// Modules use hook_user_delete() to respond to deletion.
// When the 'user_cancel_delete' method is used, user_delete() is called,
// which invokes hook_user_predelete() and hook_user_delete(). Modules
// should use those hooks to respond to the account deletion.
if ($method != 'user_cancel_delete') {
// Allow modules to add further sets to this batch.
module_invoke_all('user_cancel', $edit, $account, $method);
@ -2436,6 +2438,9 @@ function user_delete($uid) {
*
* @param $uids
* An array of user IDs.
*
* @see hook_user_predelete()
* @see hook_user_delete()
*/
function user_delete_multiple(array $uids) {
if (!empty($uids)) {
@ -2444,8 +2449,10 @@ function user_delete_multiple(array $uids) {
$transaction = db_transaction();
try {
foreach ($accounts as $uid => $account) {
module_invoke_all('user_delete', $account);
module_invoke_all('entity_delete', $account, 'user');
// Allow modules to act prior to user deletion.
module_invoke_all('user_predelete', $account);
module_invoke_all('entity_predelete', $account, 'user');
field_attach_delete('user', $account);
drupal_session_destroy_uid($account->uid);
}
@ -2459,6 +2466,10 @@ function user_delete_multiple(array $uids) {
db_delete('authmap')
->condition('uid', $uids, 'IN')
->execute();
// Allow modules to respond to user deletion.
module_invoke_all('user_delete', $account);
module_invoke_all('entity_delete', $account, 'user');
}
catch (Exception $e) {
$transaction->rollback();