### Eclipse Workspace Patch 1.0 #P prev_next Index: prev_next.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/prev_next/prev_next.module,v retrieving revision 1.1 diff -u -r1.1 prev_next.module --- prev_next.module 7 May 2009 22:12:04 -0000 1.1 +++ prev_next.module 27 Oct 2009 22:23:58 -0000 @@ -2,7 +2,8 @@ // $Id: prev_next.module,v 1.1 2009/05/07 22:12:04 kbahey Exp $ define('PREV_NEXT_BATCH_SIZE_DEFAULT', 200); -define('PREV_NEXT_NODE_TYPE', 'prev_next_node_type_'); +define('PREV_NEXT_INDEXING_CRITERIA_DEFAULT', 'nid'); +define('PREV_NEXT_NODE_TYPE', 'prev_next_node_type_'); /** * Implementation of hook_menu(). @@ -32,8 +33,8 @@ */ function prev_next_admin() { $form['status'] = array( - '#type' => 'fieldset', - '#title' => t('Indexing status'), + '#type' => 'fieldset', + '#title' => t('Indexing status'), ); $max_nid = variable_get('prev_next_index_nid', 0); @@ -50,14 +51,14 @@ '%remaining' => $remaining, '%total' => $total, )); - $status .= ($max_nid) ? t('

Max node ID for indexing on the next cron run: @max

', array('@max' => $max_nid)) : t('

Existing nodes have finished prev/next indexing.

'); + $status .= ($max_nid) ? t('

Max node ID for indexing on the next cron run: @max.

', array('@max' => $max_nid)) : t('

Existing nodes have finished prev/next indexing.

'); $form['status']['status'] = array( '#value' => $status, ); $form['status']['reindex'] = array( - '#type' => 'submit', + '#type' => 'submit', '#value' => t('Re-index'), ); @@ -74,17 +75,59 @@ $form['node_types'] = array( '#type' => 'fieldset', '#title' => t('Content types'), - '#description' => t('Content types to include in prev/next. If you do not specify content types, then all of them will be included.'), + '#description' => t('Define settings for each content type. If none of them is included, then all of them will be.'), ); foreach (node_get_types() as $type => $name) { - $form['node_types'][PREV_NEXT_NODE_TYPE . $type] = array( + + $form['node_types'][$type] = array( + '#type' => 'fieldset', + '#description' => t('Note: changing one of these values will reset the entire Prev/Next index.'), + '#title' => node_get_types('name', $type), + '#collapsible' => TRUE, + '#collapsed' => !variable_get(PREV_NEXT_NODE_TYPE . $type, 0) + ); + + $form['node_types'][$type][PREV_NEXT_NODE_TYPE . $type] = array( '#type' => 'checkbox', - '#title' => node_get_types('name', $type), + '#title' => t('Include'), '#default_value' => variable_get(PREV_NEXT_NODE_TYPE . $type, 0), ); + $form['node_types'][$type][PREV_NEXT_NODE_TYPE . $type . '_current'] = array( + '#type' => 'hidden', + '#default_value' => variable_get(PREV_NEXT_NODE_TYPE . $type, 0) + ); + + $form['node_types'][$type][PREV_NEXT_NODE_TYPE . $type . '_indexing_criteria'] = array( + '#title' => t('Indexing criteria'), + '#type' => 'select', + '#options' => array( + 'nid' => t('Node ID'), + 'created' => t('Post date'), + 'changed' => t('Updated date'), + 'title' => t('Title') + ), + '#default_value' => variable_get(PREV_NEXT_NODE_TYPE . $type . '_indexing_criteria', PREV_NEXT_INDEXING_CRITERIA_DEFAULT) + ); + $form['node_types'][$type][PREV_NEXT_NODE_TYPE . $type . '_indexing_criteria_current'] = array( + '#type' => 'hidden', + '#value' => variable_get(PREV_NEXT_NODE_TYPE . $type . '_indexing_criteria', PREV_NEXT_INDEXING_CRITERIA_DEFAULT) + ); + + $form['node_types'][$type][PREV_NEXT_NODE_TYPE . $type . '_same_type'] = array( + '#type' => 'checkbox', + '#title' => t('Only nodes with same content type'), + '#default_value' => variable_get(PREV_NEXT_NODE_TYPE . $type . '_same_type', 0), + ); + $form['node_types'][$type][PREV_NEXT_NODE_TYPE . $type . '_same_type_current'] = array( + '#type' => 'hidden', + '#default_value' => variable_get(PREV_NEXT_NODE_TYPE . $type . '_same_type', 0) + ); + } + $form['#submit'][] = 'prev_next_admin_submit'; + return system_settings_form($form); } @@ -105,6 +148,29 @@ } } +/** + * Submit callback. + */ +function prev_next_admin_submit($form, &$form_state) { + $rebuild = FALSE; + + // Test sensitive values. + foreach (node_get_types() as $type => $name) { + if ($form_state['values'][PREV_NEXT_NODE_TYPE . $type . '_current'] != $form_state['values'][PREV_NEXT_NODE_TYPE . $type] + || $form_state['values'][PREV_NEXT_NODE_TYPE . $type . '_indexing_criteria_current'] != $form_state['values'][PREV_NEXT_NODE_TYPE . $type . '_indexing_criteria'] + || $form_state['values'][PREV_NEXT_NODE_TYPE . $type . '_same_type_current'] != $form_state['values'][PREV_NEXT_NODE_TYPE . $type . '_same_type'] + ) + $rebuild = TRUE; + } + + // If the search criterias has been changed, re-index. + if ($rebuild) { + prev_next_reindex(); + drupal_set_message(t('The Prev/Next index will be rebuilt.')); + } + $form_state['redirect'] = 'admin/settings/prev_next'; +} + function prev_next_reindex_confirm() { return confirm_form(array(), t('Are you sure you want to re-index Prev/Next?'), 'admin/settings/prev_next', t(' The entire Prev/Next index will be reset and rebuilt incrementally as cron runs. action cannot be undone.'), t('Re-index'), t('Cancel')); @@ -138,11 +204,10 @@ if ($max_nid) { $batch_size = variable_get('prev_next_batch_size', PREV_NEXT_BATCH_SIZE_DEFAULT); $last_nid = FALSE; - $cond = _prev_next_node_types_sql(); + $cond = _prev_next_node_types_sql(); timer_start('prev_next_cron'); - $result = db_query("SELECT nid FROM {node} WHERE nid <= %d AND status = 1 $cond ORDER BY nid DESC LIMIT %d", - $max_nid, $batch_size); + $result = db_query("SELECT nid FROM {node} WHERE nid <= %d AND status = 1 $cond ORDER BY nid DESC LIMIT %d", $max_nid, $batch_size); $count = 0; while ($row = db_fetch_object($result)) { @@ -161,24 +226,93 @@ if ($last_nid !== FALSE) { // Prepare a starting point for the next run. variable_set('prev_next_index_nid', $last_nid - 1); - watchdog('prev_next', 'Indexed %count nodes in %time milliseconds.', array('%count' => $count, '%time' => $time)); } else { // If all nodes have been indexed, set to zero to skip future cron runs. variable_set('prev_next_index_nid', 0); } + watchdog('prev_next', 'Indexed %count nodes in %time milliseconds.', array('%count' => $count, '%time' => $time)); + + $total = db_result(db_query("SELECT COUNT(nid) FROM {node} WHERE status = 1 $cond")); + $completed = db_result(db_query("SELECT COUNT(nid) FROM {prev_next_node}")); + $remaining = max(0, $total - $completed); + drupal_set_message(t('Indexed %count nodes for the Prev/Next index. There are %remaining items left to index.', array( + '%count' => $count, + '%remaining' => $remaining + ))); + } } /** + * Implementation of hook_block(). + */ +function prev_next_block($op) { + switch ($op) { + + case 'list': + $blocks[0] = array( + 'info' => t('Prev/Next links'), + 'status' => 1, + 'region' => 'content', + 'cache' => BLOCK_CACHE_PER_PAGE + ); + return $blocks; + break; + + case 'view': + $content = ''; + + if (arg(0) == 'node' && is_numeric(arg(1)) && !arg(2) ) { + $node = node_load(arg(1)); + $n_nid = prev_next_nid($node->nid, 'next'); + $p_nid = prev_next_nid($node->nid, 'prev'); + + if ($n_nid || $p_nid) { + + if ($p_nid) { + $p_node = node_load($p_nid); + $options = array('html' => TRUE); + $content .= ''; + } + + if ($n_nid) { + $n_node = node_load($n_nid); + $options = array('html' => TRUE); + $content .= ''; + } + + $block = array( + 'subject' => t('Prev/Next links'), + 'content' => '' + ); + + } + + } + + return $block; + + } + +} + +/** * Create or update the prev_next records. */ function _prev_next_add($nid) { - $cond = _prev_next_node_types_sql(); + $node_type = db_result(db_query("SELECT type FROM {node} WHERE nid = %d LIMIT 1", $nid)); + $search_criteria = variable_get(PREV_NEXT_NODE_TYPE . $node_type . '_indexing_criteria', PREV_NEXT_INDEXING_CRITERIA_DEFAULT); + + $criteria_value = db_result(db_query("SELECT %s FROM {node} WHERE nid = %d LIMIT 1", $search_criteria, $nid)); - $next_nid = db_result(db_query("SELECT nid FROM {node} WHERE nid > %d AND status = 1 $cond ORDER BY nid ASC LIMIT 1", $nid)); + $cond = _prev_next_node_types_sql($node_type); - $prev_nid = db_result(db_query("SELECT nid FROM {node} WHERE nid < %d AND status = 1 $cond ORDER BY nid DESC LIMIT 1", $nid)); + $next_nid = db_result(db_query("SELECT nid FROM {node} WHERE %s > %s AND status = 1 $cond ORDER BY %s ASC LIMIT 1", + $search_criteria, $criteria_value, $search_criteria)); + + $prev_nid = db_result(db_query("SELECT nid FROM {node} WHERE %s < %s AND status = 1 $cond ORDER BY %s DESC LIMIT 1", + $search_criteria, $criteria_value, $search_criteria)); // Update the node-level data $exists = db_result(db_query('SELECT COUNT(*) FROM {prev_next_node} WHERE nid = %d', $nid)); @@ -192,13 +326,34 @@ } // Update the other nodes pointing to this node - if ($prev_nid) { - // Update the previous node - db_query("UPDATE {prev_next_node} SET next_nid = %d WHERE nid = %d", $nid, $prev_nid); - } - if ($next_nid) { - db_query("UPDATE {prev_next_node} SET prev_nid = %d WHERE nid = %d", $nid, $next_nid); + foreach (node_get_types() as $type => $name) { + if (variable_get(PREV_NEXT_NODE_TYPE . $type, 0)) { + $search_criteria = variable_get(PREV_NEXT_NODE_TYPE . $type . '_indexing_criteria', PREV_NEXT_INDEXING_CRITERIA_DEFAULT); + $criteria_value = db_result(db_query("SELECT %s FROM {node} WHERE nid = %d LIMIT 1", $search_criteria, $nid)); + $cond = _prev_next_node_types_sql($node_type); + $next_nid = db_result(db_query("SELECT nid FROM {node} WHERE %s > %s AND status = 1 $cond ORDER BY %s ASC LIMIT 1", + $search_criteria, $criteria_value, $search_criteria)); + if ($next_nid == $nid) { + db_query("UPDATE {prev_next_node} SET next_nid = %d WHERE nid = %d", $nid, $next_nid); + } + $prev_nid = db_result(db_query("SELECT nid FROM {node} WHERE %s < %s AND status = 1 $cond ORDER BY %s DESC LIMIT 1", + $search_criteria, $criteria_value, $search_criteria)); + if ($prev_nid == $nid) { + db_query("UPDATE {prev_next_node} SET prev_nid = %d WHERE nid = %d", $nid, $prev_nid); + } + } } + +} + +/** + * Update the prev_next records. + */ +function _prev_next_modify($nid) { + // Find out if any other nodes point to this node and update them + _prev_next_modify_pointing_nodes($nid); + // Then update this one + _prev_next_add($nid); } /** @@ -212,13 +367,20 @@ db_query("DELETE FROM {prev_next_node} WHERE nid = %d", $nid); } // Find out if any other nodes point to this node and update them + _prev_next_modify_pointing_nodes($nid); +} + +/** + * Update other nodes pointing to a particular node + */ +function _prev_next_modify_pointing_nodes($nid) { // First for previous - $prev_nid = db_result(db_query("SELECT nid FROM {prev_next_node} WHERE prev_nid = %d", $nid)); - _prev_next_add($prev_nid); + $result = db_query("SELECT nid FROM {prev_next_node} WHERE prev_nid = %d", $nid); + while ($prev_row = db_fetch_object($result)) _prev_next_add($prev_row->nid); // Then for next - $next_nid = db_result(db_query("SELECT nid FROM {prev_next_node} WHERE next_nid = %d", $nid)); - _prev_next_add($next_nid); + $result = db_query("SELECT nid FROM {prev_next_node} WHERE next_nid = %d", $nid); + while ($next_row = db_fetch_object($result)) _prev_next_add($next_row->nid); } /** @@ -226,7 +388,7 @@ */ function prev_next_nodeapi(&$node, $op) { $found = FALSE; - foreach(_prev_next_node_types() as $type) { + foreach (_prev_next_node_types() as $type) { if ($node->type == $type) { $found = TRUE; break; @@ -236,19 +398,22 @@ return; } - switch($op) { + switch ($op) { case 'insert': - case 'update': _prev_next_add($node->nid); break; + case 'update': + _prev_next_modify($node->nid); + break; + case 'delete': _prev_next_remove($node->nid); break; } } -/* +/* * Callable API function to get the next/prev nid of a given nid */ function prev_next_nid($nid, $op = 'next') { @@ -288,18 +453,25 @@ /* * Helper function to return a SQL clause for types to be indexed */ -function _prev_next_node_types_sql() { - $types = _prev_next_node_types(); +function _prev_next_node_types_sql($node_type = '') { + + $same_type = variable_get(PREV_NEXT_NODE_TYPE . $node_type . '_same_type', 0); + + if (!$same_type) { + + $types = _prev_next_node_types(); + + $quoted_types = array(); + foreach (_prev_next_node_types() as $type) { + $quoted_types[] = "'" . $type . "'"; + } + $cond = ''; + if (count($types)) { + $cond = ' AND type IN (' . implode(',', $quoted_types) . ')'; + } - $quoted_types = array(); - foreach(_prev_next_node_types() as $type) { - $quoted_types[] = "'" . $type . "'"; - } - $cond = ''; - if (count($types)) { - $cond = ' AND type IN (' . implode(',', $quoted_types) . ')'; } + else $cond = " AND type = '" . $node_type . "'"; return $cond; } -