Same name and namespace in other branches
  1. 4.6.x modules/node.module \node_search()
  2. 5.x modules/node/node.module \node_search()
  3. 6.x modules/node/node.module \node_search()

Implementation of hook_search().

File

modules/node.module, line 605
The core that allows content to be submitted to the site.

Code

function node_search($op = 'search', $keys = null) {
  switch ($op) {
    case 'name':
      return t('content');
    case 'reset':
      variable_del('node_cron_last');
      variable_del('node_cron_last_nid');
      return;
    case 'status':
      $last = variable_get('node_cron_last', 0);
      $last_nid = variable_get('node_cron_last_nid', 0);
      $total = db_result(db_query('SELECT COUNT(*) FROM {node} WHERE status = 1'));
      $remaining = db_result(db_query('SELECT COUNT(*) FROM {node} n LEFT JOIN {node_comment_statistics} c ON n.nid = c.nid WHERE n.status = 1 AND ((GREATEST(n.created, n.changed, c.last_comment_timestamp) = %d AND n.nid > %d ) OR (n.created > %d OR n.changed > %d OR c.last_comment_timestamp > %d))', $last, $last_nid, $last, $last, $last));
      return array(
        'remaining' => $remaining,
        'total' => $total,
      );
    case 'admin':
      $form = array();

      // Output form for defining rank factor weights.
      $form['content_ranking'] = array(
        '#type' => 'fieldset',
        '#title' => t('Content ranking'),
      );
      $form['content_ranking']['#theme'] = 'node_search_admin';
      $form['content_ranking']['info'] = array(
        '#type' => 'markup',
        '#value' => '<em>' . t('The following numbers control which properties the content search should favor when ordering the results. Higher numbers mean more influence, zero means the property is ignored. Changing these numbers does not require the search index to be rebuilt.  Changes take effect immediately.') . '</em>',
      );
      $ranking = array(
        'node_rank_relevance' => t('Keyword relevance'),
        'node_rank_recent' => t('Recently posted'),
      );
      if (module_exist('comment')) {
        $ranking['node_rank_comments'] = t('Number of comments');
      }
      if (module_exist('statistics') && variable_get('statistics_count_content_views', 0)) {
        $ranking['node_rank_views'] = t('Number of views');
      }

      // Note: reversed to reflect that higher number = higher ranking.
      $options = drupal_map_assoc(range(0, 10));
      foreach ($ranking as $var => $title) {
        $form['content_ranking']['factors'][$var] = array(
          '#title' => $title,
          '#type' => 'select',
          '#options' => $options,
          '#default_value' => variable_get($var, 5),
        );
      }
      return $form;
    case 'search':

      // Build matching conditions
      list($join1, $where1) = _db_rewrite_sql();
      $arguments1 = array();
      $conditions1 = 'n.status = 1';
      if ($type = search_query_extract($keys, 'type')) {
        $types = array();
        foreach (explode(',', $type) as $t) {
          $types[] = "n.type = '%s'";
          $arguments1[] = $t;
        }
        $conditions1 .= ' AND (' . implode(' OR ', $types) . ')';
        $keys = search_query_insert($keys, 'type');
      }
      if ($category = search_query_extract($keys, 'category')) {
        $categories = array();
        foreach (explode(',', $category) as $c) {
          $categories[] = "tn.tid = %d";
          $arguments1[] = $c;
        }
        $conditions1 .= ' AND (' . implode(' OR ', $categories) . ')';
        $join1 .= ' INNER JOIN {term_node} tn ON n.nid = tn.nid';
        $keys = search_query_insert($keys, 'category');
      }

      // Build ranking expression (we try to map each parameter to a
      // uniform distribution in the range 0..1).
      $ranking = array();
      $arguments2 = array();
      $join2 = '';
      $total = 0;

      // Used to avoid joining on node_comment_statistics twice
      $stats_join = false;
      if ($weight = (int) variable_get('node_rank_relevance', 5)) {

        // Average relevance values hover around 0.15
        $ranking[] = '%d * i.relevance';
        $arguments2[] = $weight;
        $total += $weight;
      }
      if ($weight = (int) variable_get('node_rank_recent', 5)) {

        // Exponential decay with half-life of 6 months, starting at last indexed node
        $ranking[] = '%d * POW(2, (GREATEST(n.created, n.changed, c.last_comment_timestamp) - %d) * 6.43e-8)';
        $arguments2[] = $weight;
        $arguments2[] = (int) variable_get('node_cron_last', 0);
        $join2 .= ' INNER JOIN {node} n ON n.nid = i.sid LEFT JOIN {node_comment_statistics} c ON c.nid = i.sid';
        $stats_join = true;
        $total += $weight;
      }
      if (module_exist('comment') && ($weight = (int) variable_get('node_rank_comments', 5))) {

        // Inverse law that maps the highest reply count on the site to 1 and 0 to 0.
        $scale = variable_get('node_cron_comments_scale', 0.0);
        $ranking[] = '%d * (2.0 - 2.0 / (1.0 + c.comment_count * %f))';
        $arguments2[] = $weight;
        $arguments2[] = $scale;
        if (!$stats_join) {
          $join2 .= ' LEFT JOIN {node_comment_statistics} c ON c.nid = i.sid';
        }
        $total += $weight;
      }
      if (module_exist('statistics') && variable_get('statistics_count_content_views', 0) && ($weight = (int) variable_get('node_rank_views', 5))) {

        // Inverse law that maps the highest view count on the site to 1 and 0 to 0.
        $scale = variable_get('node_cron_views_scale', 0.0);
        $ranking[] = '%d * (2.0 - 2.0 / (1.0 + nc.totalcount * %f))';
        $arguments2[] = $weight;
        $arguments2[] = $scale;
        $join2 .= ' LEFT JOIN {node_counter} nc ON nc.nid = i.sid';
        $total += $weight;
      }
      $select2 = (count($ranking) ? implode(' + ', $ranking) : 'i.relevance') . ' AS score';

      // Do search
      $find = do_search($keys, 'node', 'INNER JOIN {node} n ON n.nid = i.sid ' . $join1 . ' INNER JOIN {users} u ON n.uid = u.uid', $conditions1 . (empty($where1) ? '' : ' AND ' . $where1), $arguments1, $select2, $join2, $arguments2);

      // Load results
      $results = array();
      foreach ($find as $item) {
        $node = node_load($item->sid);

        // Get node output (filtered and with module-specific fields).
        if (node_hook($node, 'view')) {
          node_invoke($node, 'view', false, false);
        }
        else {
          $node = node_prepare($node, false);
        }

        // Allow modules to change $node->body before viewing.
        node_invoke_nodeapi($node, 'view', false, false);

        // Fetch comments for snippet
        $node->body .= module_invoke('comment', 'nodeapi', $node, 'update index');

        // Fetch terms for snippet
        $node->body .= module_invoke('taxonomy', 'nodeapi', $node, 'update index');
        $extra = node_invoke_nodeapi($node, 'search result');
        $results[] = array(
          'link' => url('node/' . $item->sid),
          'type' => node_get_name($node),
          'title' => $node->title,
          'user' => theme('username', $node),
          'date' => $node->changed,
          'node' => $node,
          'extra' => $extra,
          'score' => $item->score / $total,
          'snippet' => search_excerpt($keys, $node->body),
        );
      }
      return $results;
  }
}