Commit 87567f89 authored by Dries's avatar Dries

- Patch #310212 by justinrandell: killed in _node hook, as well as twelve sable tooth tigers.

parent 026af5df
......@@ -221,7 +221,7 @@ function blogapi_blogger_new_post($appkey, $blogid, $username, $password, $conte
$edit['date'] = format_date(REQUEST_TIME, 'custom', 'Y-m-d H:i:s O');
}
node_invoke_nodeapi($edit, 'blogapi new');
node_invoke_nodeapi($edit, 'blogapi_new');
node_validate($edit);
if ($errors = form_get_errors()) {
......@@ -273,7 +273,7 @@ function blogapi_blogger_edit_post($appkey, $postid, $username, $password, $cont
$node->body = $content;
}
node_invoke_nodeapi($node, 'blogapi edit');
node_invoke_nodeapi($node, 'blogapi_edit');
node_validate($node);
if ($errors = form_get_errors()) {
......
......@@ -668,14 +668,9 @@ function book_build_active_trail($book_link) {
}
/**
* Implementation of hook_nodeapi().
*
* Appends book navigation to all nodes in the book, and handles book outline
* insertions and updates via the node form.
* Implementation of hook_nodeapi_load().
*/
function book_nodeapi(&$node, $op, $teaser, $page) {
switch ($op) {
case 'load':
function book_nodeapi_load(&$node, $teaser, $page) {
// Note - we cannot use book_link_load() because it will call node_load().
$info['book'] = db_fetch_array(db_query('SELECT * FROM {book} b INNER JOIN {menu_links} ml ON b.mlid = ml.mlid WHERE b.nid = %d', $node->nid));
......@@ -686,9 +681,12 @@ function book_nodeapi(&$node, $op, $teaser, $page) {
return $info;
}
break;
}
case 'view':
/**
* Implementation of hook_nodeapi_view().
*/
function book_nodeapi_view(&$node, $teaser, $page) {
if (!$teaser) {
if (!empty($node->book['bid']) && $node->build_mode == NODE_BUILD_NORMAL) {
$node->content['book_navigation'] = array(
......@@ -702,9 +700,12 @@ function book_nodeapi(&$node, $op, $teaser, $page) {
}
}
}
break;
}
case 'presave':
/**
* Implementation of hook_nodeapi_presave().
*/
function book_nodeapi_presave(&$node, $teaser, $page) {
// Always save a revision for non-administrators.
if (!empty($node->book['bid']) && !user_access('administer nodes')) {
$node->revision = 1;
......@@ -713,10 +714,12 @@ function book_nodeapi(&$node, $op, $teaser, $page) {
if (empty($node->nid)) {
$node->book['mlid'] = NULL;
}
break;
}
case 'insert':
case 'update':
/**
* Implementation of hook_nodeapi_insert().
*/
function book_nodeapi_insert(&$node, $teaser, $page) {
if (!empty($node->book['bid'])) {
if ($node->book['bid'] == 'new') {
// New nodes that are their own book.
......@@ -726,9 +729,27 @@ function book_nodeapi(&$node, $op, $teaser, $page) {
$node->book['menu_name'] = book_menu_name($node->book['bid']);
_book_update_outline($node);
}
break;
}
case 'delete':
/**
* Implementation of hook_nodeapi_update().
*/
function book_nodeapi_update(&$node, $teaser, $page) {
if (!empty($node->book['bid'])) {
if ($node->book['bid'] == 'new') {
// New nodes that are their own book.
$node->book['bid'] = $node->nid;
}
$node->book['nid'] = $node->nid;
$node->book['menu_name'] = book_menu_name($node->book['bid']);
_book_update_outline($node);
}
}
/**
* Implementation of hook_nodeapi_delete().
*/
function book_nodeapi_delete(&$node, $teaser, $page) {
if (!empty($node->book['bid'])) {
if ($node->nid == $node->book['bid']) {
// Handle deletion of a top-level post.
......@@ -742,9 +763,12 @@ function book_nodeapi(&$node, $op, $teaser, $page) {
menu_link_delete($node->book['mlid']);
db_query('DELETE FROM {book} WHERE mlid = %d', $node->book['mlid']);
}
break;
}
case 'prepare':
/**
* Implementation of hook_nodeapi_prepare().
*/
function book_nodeapi_prepare(&$node, $teaser, $page) {
// Prepare defaults for the add/edit form.
if (empty($node->book) && (user_access('add content to books') || user_access('administer book outlines'))) {
$node->book = array();
......@@ -771,8 +795,6 @@ function book_nodeapi(&$node, $op, $teaser, $page) {
if (isset($node->book['bid']) && !isset($node->book['parent_depth_limit'])) {
$node->book['parent_depth_limit'] = _book_parent_depth_limit($node->book);
}
break;
}
}
/**
......
......@@ -552,51 +552,69 @@ function comment_form_alter(&$form, $form_state, $form_id) {
}
/**
* Implementation of hook_nodeapi().
* Implementation of hook_nodeapi_load().
*/
function comment_nodeapi(&$node, $op, $arg = 0) {
switch ($op) {
case 'load':
function comment_nodeapi_load(&$node, $arg = 0) {
if ($node->comment != COMMENT_NODE_DISABLED) {
return db_fetch_array(db_query("SELECT last_comment_timestamp, last_comment_name, comment_count FROM {node_comment_statistics} WHERE nid = %d", $node->nid));
}
return array('last_comment_timestamp' => $node->created, 'last_comment_name' => '', 'comment_count' => 0);
}
case 'prepare':
/**
* Implementation of hook_nodeapi_prepare().
*/
function comment_nodeapi_prepare(&$node, $arg = 0) {
if (!isset($node->comment)) {
$node->comment = variable_get("comment_$node->type", COMMENT_NODE_READ_WRITE);
}
break;
}
case 'insert':
/**
* Implementation of hook_nodeapi_insert().
*/
function comment_nodeapi_insert(&$node, $arg = 0) {
db_query('INSERT INTO {node_comment_statistics} (nid, last_comment_timestamp, last_comment_name, last_comment_uid, comment_count) VALUES (%d, %d, NULL, %d, 0)', $node->nid, $node->changed, $node->uid);
break;
}
case 'delete':
/**
* Implementation of hook_nodeapi_delete().
*/
function comment_nodeapi_delete(&$node, $arg = 0) {
db_query('DELETE FROM {comments} WHERE nid = %d', $node->nid);
db_query('DELETE FROM {node_comment_statistics} WHERE nid = %d', $node->nid);
break;
}
case 'update index':
/**
* Implementation of hook_nodeapi_update_index().
*/
function comment_nodeapi_update_index(&$node, $arg = 0) {
$text = '';
$comments = db_query('SELECT subject, comment, format FROM {comments} WHERE nid = %d AND status = %d', $node->nid, COMMENT_PUBLISHED);
while ($comment = db_fetch_object($comments)) {
$text .= '<h2>' . check_plain($comment->subject) . '</h2>' . check_markup($comment->comment, $comment->format, FALSE);
}
return $text;
}
case 'search result':
/**
* Implementation of hook_nodeapi_search_result().
*/
function comment_nodeapi_search_result(&$node, $arg = 0) {
$comments = db_result(db_query('SELECT comment_count FROM {node_comment_statistics} WHERE nid = %d', $node->nid));
return format_plural($comments, '1 comment', '@count comments');
}
case 'rss item':
/**
* Implementation of hook_nodeapi_rss_item().
*/
function comment_nodeapi_rss_item(&$node, $arg = 0) {
if ($node->comment != COMMENT_NODE_DISABLED) {
return array(array('key' => 'comments', 'value' => url('node/' . $node->nid, array('fragment' => 'comments', 'absolute' => TRUE))));
}
else {
return array();
}
}
}
/**
......
......@@ -156,26 +156,37 @@ function forum_init() {
}
/**
* Implementation of hook_nodeapi().
* _forum_nodeapi_check_node_type
*
* @param mixed $node
* @param mixed $vocabulary
* @access protected
* @return bool
*/
function forum_nodeapi(&$node, $op, $teaser, $page) {
function _forum_nodeapi_check_node_type($node, $vocabulary) {
// We are going to return if $node->type is not one of the node
// types assigned to the forum vocabulary. If forum_nav_vocabulary
// is undefined or the vocabulary does not exist, it clearly cannot
// be assigned to $node->type, so return to avoid E_ALL warnings.
$vid = variable_get('forum_nav_vocabulary', '');
$vocabulary = taxonomy_vocabulary_load($vid);
if (empty($vocabulary)) {
return;
return FALSE;
}
// Operate only on node types assigned for the forum vocabulary.
if (!in_array($node->type, $vocabulary->nodes)) {
return;
return FALSE;
}
switch ($op) {
case 'view':
return TRUE;
}
/**
* Implementation of hook_nodeapi_view().
*/
function forum_nodeapi_view(&$node, $teaser, $page) {
$vid = variable_get('forum_nav_vocabulary', '');
$vocabulary = taxonomy_vocabulary_load($vid);
if (_forum_nodeapi_check_node_type($node, $vocabulary)) {
if ($page && taxonomy_node_get_terms_by_vocabulary($node, $vid) && $tree = taxonomy_get_tree($vid)) {
// Get the forum terms from the (cached) tree
foreach ($tree as $term) {
......@@ -204,19 +215,34 @@ function forum_nodeapi(&$node, $op, $teaser, $page) {
);
}
}
break;
}
}
case 'prepare':
/**
* Implementation of hook_nodeapi_prepare().
*/
function forum_nodeapi_prepare(&$node, $teaser, $page) {
$vid = variable_get('forum_nav_vocabulary', '');
$vocabulary = taxonomy_vocabulary_load($vid);
if (_forum_nodeapi_check_node_type($node, $vocabulary)) {
if (empty($node->nid)) {
// New topic
$node->taxonomy[arg(3)]->vid = $vid;
$node->taxonomy[arg(3)]->tid = arg(3);
}
break;
}
}
// Check in particular that only a "leaf" term in the associated taxonomy
/**
* Implementation of hook_nodeapi_validate().
*
* Check in particular that only a "leaf" term in the associated taxonomy.
*/
function forum_nodeapi_validate(&$node, $teaser, $page) {
$vid = variable_get('forum_nav_vocabulary', '');
$vocabulary = taxonomy_vocabulary_load($vid);
if (_forum_nodeapi_check_node_type($node, $vocabulary)) {
// vocabulary is selected, not a "container" term.
case 'validate':
if ($node->taxonomy) {
// Extract the node's proper topic ID.
$vocabulary = $vid;
......@@ -230,10 +256,18 @@ function forum_nodeapi(&$node, $op, $teaser, $page) {
}
}
}
break;
}
}
// Assign forum taxonomy when adding a topic from within a forum.
case 'presave':
/**
* Implementation of hook_nodeapi_presave().
*
* Assign forum taxonomy when adding a topic from within a forum.
*/
function forum_nodeapi_presave(&$node, $teaser, $page) {
$vid = variable_get('forum_nav_vocabulary', '');
$vocabulary = taxonomy_vocabulary_load($vid);
if (_forum_nodeapi_check_node_type($node, $vocabulary)) {
// Make sure all fields are set properly:
$node->icon = !empty($node->icon) ? $node->icon : '';
......@@ -253,9 +287,16 @@ function forum_nodeapi(&$node, $op, $teaser, $page) {
$node->taxonomy[] = $old_tid;
}
}
break;
}
}
case 'update':
/**
* Implementation of hook_nodeapi_update().
*/
function forum_nodeapi_update(&$node, $teaser, $page) {
$vid = variable_get('forum_nav_vocabulary', '');
$vocabulary = taxonomy_vocabulary_load($vid);
if (_forum_nodeapi_check_node_type($node, $vocabulary)) {
if (empty($node->revision) && db_result(db_query('SELECT tid FROM {forum} WHERE nid=%d', $node->nid))) {
if (!empty($node->tid)) {
db_query('UPDATE {forum} SET tid = %d WHERE vid = %d', $node->tid, $node->vid);
......@@ -264,25 +305,48 @@ function forum_nodeapi(&$node, $op, $teaser, $page) {
else {
db_query('DELETE FROM {forum} WHERE nid = %d', $node->nid);
}
break;
}
// Deliberate no break -- for new revisions and for previously unassigned terms we need an insert.
else {
if (!empty($node->tid)) {
db_query('INSERT INTO {forum} (tid, vid, nid) VALUES (%d, %d, %d)', $node->tid, $node->vid, $node->nid);
}
}
}
}
case 'insert':
/**
* Implementation of hook_nodeapi_insert().
*/
function forum_nodeapi_insert(&$node, $teaser, $page) {
$vid = variable_get('forum_nav_vocabulary', '');
$vocabulary = taxonomy_vocabulary_load($vid);
if (_forum_nodeapi_check_node_type($node, $vocabulary)) {
if (!empty($node->tid)) {
db_query('INSERT INTO {forum} (tid, vid, nid) VALUES (%d, %d, %d)', $node->tid, $node->vid, $node->nid);
}
break;
}
}
case 'delete':
/**
* Implementation of hook_nodeapi_delete().
*/
function forum_nodeapi_delete(&$node, $teaser, $page) {
$vid = variable_get('forum_nav_vocabulary', '');
$vocabulary = taxonomy_vocabulary_load($vid);
if (_forum_nodeapi_check_node_type($node, $vocabulary)) {
db_query('DELETE FROM {forum} WHERE nid = %d', $node->nid);
break;
}
}
case 'load':
/**
* Implementation of hook_nodeapi_load().
*/
function forum_nodeapi_load(&$node, $teaser, $page) {
$vid = variable_get('forum_nav_vocabulary', '');
$vocabulary = taxonomy_vocabulary_load($vid);
if (_forum_nodeapi_check_node_type($node, $vocabulary)) {
return db_fetch_array(db_query('SELECT tid AS forum_tid FROM {forum} WHERE vid = %d', $node->vid));
}
return;
}
/**
......
......@@ -277,12 +277,9 @@ function menu_block($op = 'list', $delta = '') {
}
/**
* Implementation of hook_nodeapi().
* Implementation of hook_nodeapi_insert().
*/
function menu_nodeapi(&$node, $op) {
switch ($op) {
case 'insert':
case 'update':
function menu_nodeapi_insert(&$node) {
if (isset($node->menu)) {
$item = $node->menu;
if (!empty($item['delete'])) {
......@@ -299,15 +296,45 @@ function menu_nodeapi(&$node, $op) {
}
}
}
break;
case 'delete':
}
/**
* Implementation of hook_nodeapi_update().
*/
function menu_nodeapi_update(&$node) {
if (isset($node->menu)) {
$item = $node->menu;
if (!empty($item['delete'])) {
menu_link_delete($item['mlid']);
}
elseif (trim($item['link_title'])) {
$item['link_title'] = trim($item['link_title']);
$item['link_path'] = "node/$node->nid";
if (!$item['customized']) {
$item['options']['attributes']['title'] = trim($node->title);
}
if (!menu_link_save($item)) {
drupal_set_message(t('There was an error saving the menu link.'), 'error');
}
}
}
}
/**
* Implementation of hook_nodeapi_delete().
*/
function menu_nodeapi_delete(&$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));
while ($m = db_fetch_array($result)) {
menu_link_delete($m['mlid']);
}
break;
case 'prepare':
}
/**
* Implementation of hook_nodeapi_prepare().
*/
function menu_nodeapi_prepare(&$node) {
if (empty($node->menu)) {
// Prepare the node for the edit form so that $node->menu always exists.
$menu_name = variable_get('menu_default_node_menu', 'main-menu');
......@@ -335,8 +362,6 @@ function menu_nodeapi(&$node, $op) {
if (!isset($node->menu['parent_depth_limit'])) {
$node->menu['parent_depth_limit'] = _menu_parent_depth_limit($node->menu);
}
break;
}
}
/**
......
......@@ -704,9 +704,10 @@ function node_invoke(&$node, $hook, $a2 = NULL, $a3 = NULL, $a4 = NULL) {
*/
function node_invoke_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
$return = array();
foreach (module_implements('nodeapi') as $name) {
$function = $name . '_nodeapi';
$result = $function($node, $op, $a3, $a4);
$hook = 'nodeapi_' . $op;
foreach (module_implements($hook) as $name) {
$function = $name . '_' . $hook;
$result = $function($node, $a3, $a4);
if (isset($result) && is_array($result)) {
$return = array_merge($return, $result);
}
......@@ -1321,9 +1322,9 @@ function node_search($op = 'search', $keys = NULL) {
$node->body = drupal_render($node->content);
// Fetch comments for snippet.
$node->body .= module_invoke('comment', 'nodeapi', $node, 'update index');
$node->body .= module_invoke('comment', 'nodeapi', $node, 'update_index');
// Fetch terms for snippet.
$node->body .= module_invoke('taxonomy', 'nodeapi', $node, 'update index');
$node->body .= module_invoke('taxonomy', 'nodeapi', $node, 'update_index');
$extra = node_invoke_nodeapi($node, 'search result');
......@@ -1742,7 +1743,7 @@ function node_feed($nids = FALSE, $channel = array()) {
}
// Allow modules to add additional item fields and/or modify $item
$extra = node_invoke_nodeapi($item, 'rss item');
$extra = node_invoke_nodeapi($item, 'rss_item');
$extra = array_merge($extra, array(array('key' => 'pubDate', 'value' => gmdate('r', $item->created)), array('key' => 'dc:creator', 'value' => $item->name), array('key' => 'guid', 'value' => $item->nid . ' at ' . $base_url, 'attributes' => array('isPermaLink' => 'false'))));
foreach ($extra as $element) {
if (isset($element['namespace'])) {
......
......@@ -576,7 +576,7 @@ function node_revision_delete_confirm($form_state, $node_revision) {
function node_revision_delete_confirm_submit($form, &$form_state) {
$node_revision = $form['#node_revision'];
db_query("DELETE FROM {node_revisions} WHERE nid = %d AND vid = %d", $node_revision->nid, $node_revision->vid);
node_invoke_nodeapi($node_revision, 'delete revision');
node_invoke_nodeapi($node_revision, 'delete_revision');
watchdog('content', '@type: deleted %title revision %revision.', array('@type' => $node_revision->type, '%title' => $node_revision->title, '%revision' => $node_revision->vid));
drupal_set_message(t('Revision from %revision-date of @type %title has been deleted.', array('%revision-date' => format_date($node_revision->revision_timestamp), '@type' => node_get_types('name', $node_revision), '%title' => $node_revision->title)));
$form_state['redirect'] = 'node/' . $node_revision->nid;
......
......@@ -117,54 +117,67 @@ function path_set_alias($path = NULL, $alias = NULL, $pid = NULL, $language = ''
drupal_clear_path_cache();
}
/**
* Implementation of hook_nodeapi().
*
* Allows URL aliases for nodes to be specified at node edit time rather
* than through the administrative interface.
* Implementation of hook_nodeapi_validate().
*/
function path_nodeapi(&$node, $op, $arg) {
// Permissions are required for everything except node loading.
if (user_access('create url aliases') || user_access('administer url aliases') || ($op == 'load')) {
$language = isset($node->language) ? $node->language : '';
switch ($op) {
case 'validate':
function path_nodeapi_validate(&$node, $arg) {
if (user_access('create url aliases') || user_access('administer url aliases')) {
if (isset($node->path)) {
$language = isset($node->language) ? $node->language : '';
$node->path = trim($node->path);
if (db_result(db_query("SELECT COUNT(dst) FROM {url_alias} WHERE dst = '%s' AND src != '%s' AND language = '%s'", $node->path, "node/$node->nid", $language))) {
form_set_error('path', t('The path is already in use.'));
}
}
break;
}
}
case 'load':
/**
* Implementation of hook_nodeapi_load().
*/
function path_nodeapi_load(&$node, $arg) {
$language = isset($node->language) ? $node->language : '';
$path = 'node/' . $node->nid;
$alias = drupal_get_path_alias($path, $language);
if ($path != $alias) {
$node->path = $alias;
}
break;
}
case 'insert':
/**
* Implementation of hook_nodeapi_insert().
*/
function path_nodeapi_insert(&$node, $arg) {
if (user_access('create url aliases') || user_access('administer url aliases')) {
$language = isset($node->language) ? $node->language : '';
// Don't try to insert if path is NULL. We may have already set
// the alias ahead of time.
if (isset($node->path)) {
path_set_alias('node/' . $node->nid, $node->path, NULL, $language);
}
break;
}
}
case 'update':
/**
* Implementation of hook_nodeapi_update().
*/
function path_nodeapi_update(&$node, $arg) {
if (user_access('create url aliases') || user_access('administer url aliases')) {
$language = isset($node->language) ? $node->language : '';
path_set_alias('node/' . $node->nid, isset($node->path) ? $node->path : NULL, isset($node->pid) ? $node->pid : NULL, $language);
break;
}
}
case 'delete':
/**
* Implementation of hook_nodeapi_delete().
*/
function path_nodeapi_delete(&$node, $arg) {
if (user_access('create url aliases') || user_access('administer url aliases')) {
$language = isset($node->language) ? $node->language : '';
$path = 'node/' . $node->nid;
if (drupal_get_path_alias($path) != $path) {
path_set_alias($path);
}
break;
}
}
}
......
......@@ -626,24 +626,25 @@ function search_touch_node($nid) {
}
/**
* Implementation of hook_nodeapi().
* Implementation of hook_nodeapi_update_index().
*/
function search_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
switch ($op) {
function search_nodeapi_update_index(&$node, $teaser = NULL, $page = NULL) {
// Transplant links to a node into the target node.
case 'update index':
$result = db_query("SELECT caption FROM {search_node_links} WHERE nid = %d", $node->nid);
$output = array();
while ($link = db_fetch_object($result)) {
$output[] = $link->caption;
}
return '<a>(' . implode(', ', $output) . ')</a>';
}
/**
* Implementation of hook_nodeapi_update().
*/
function search_nodeapi_update(&$node, $teaser = NULL, $page = NULL) {
// Reindex the node when it is updated. The node is automatically indexed
// when it is added, simply by being added to the node table.
case 'update':
search_touch_node($node->nid);
break;
}
}
/**
......
......@@ -317,14 +317,11 @@ function _statistics_format_item($title, $path) {
}
/**
* Implementation of hook_nodeapi().
* Implementation of hook_nodeapi_delete().
*/
function statistics_nodeapi(&$node, $op, $arg = 0) {
switch ($op) {
case 'delete':
function statistics_nodeapi_delete(&$node, $arg = 0) {
// clean up statistics table when node is deleted
db_query('DELETE FROM {node_counter} WHERE nid = %d', $node->nid);
}
}
/**
......
......@@ -1175,44 +1175,64 @@ function taxonomy_render_nodes($result) {
}
/**
* Implementation of hook_nodeapi().
* Implementation of hook_nodeapi_load().
*/
function taxonomy_nodeapi($node, $op, $arg = 0) {
switch ($op) {
case 'load':
function taxonomy_nodeapi_load($node, $arg = 0) {
$output['taxonomy'] = taxonomy_node_get_terms($node);
return $output;
}
case 'insert':
/**
* Implementation of hook_nodeapi_insert().
*/
function taxonomy_nodeapi_insert($node, $arg = 0) {
if (!empty($node->taxonomy)) {