Exemple #1
0
    public function getResults(vB_Search_Criteria $criteria)
    {
        $config = vB::getConfig();
        $vBDBSearch_Core = new vBDBSearch_Core();
        $keywords = $criteria->get_raw_keywords();
        // if there are no keywords, fall back to DB search
        if (empty($keywords)) {
            return $vBDBSearch_Core->getResults($criteria);
        }
        $results = $this->getTwoPassResults($criteria);
        //getTwoPassResults will return an array of results or a string cache key
        if (is_array($results)) {
            $nodeids = array();
            foreach ($results as $nodeid => $node) {
                $nodeids[$nodeid] = $nodeid;
            }
            return $nodeids;
        } else {
            $cacheKey = $results;
        }
        $this->filters = array('make_equals_filter' => $criteria->get_equals_filters(), 'make_notequals_filter' => $criteria->get_notequals_filters(), 'make_range_filter' => $criteria->get_range_filters());
        $this->process_sort($criteria);
        if (!empty($this->filters['make_equals_filter']['view'])) {
            $this->process_view_filters($this->filters['make_equals_filter']['view']);
            unset($this->filters['make_equals_filter']['view']);
        }
        if (!empty($this->filters['make_equals_filter']['follow'])) {
            $this->process_follow_filters($this->filters['make_equals_filter']['follow'], $criteria);
            unset($this->filters['make_equals_filter']['follow']);
        }
        // my channels
        if (!empty($this->filters['make_equals_filter']['my_channels'])) {
            $this->process_my_channels_filter($this->filters['make_equals_filter']['my_channels']);
            unset($this->filters['make_equals_filter']['my_channels']);
        }
        //handle equals filters
        $this->process_filters($criteria, 'make_equals_filter', $cacheKey ? true : false);
        //handle notequals filters
        $this->process_filters($criteria, 'make_notequals_filter', $cacheKey ? true : false);
        //handle range filters
        $this->process_filters($criteria, 'make_range_filter', $cacheKey ? true : false);
        $this->setNodePermTerms($cacheKey ? true : false);
        //Sphinx doesn't recognize 'OR' as a valid operator.  Not only does this break our
        //search tests, it will confuse users who try to use db search queries on sphinx.
        $keywords = $criteria->get_raw_keywords();
        $keywords = str_replace(' OR ', ' | ', $keywords);
        $field = $criteria->is_title_only() ? '@title ' : '';
        array_unshift($this->where, "MATCH('{$field}" . $this->sphinxEscapeKeywords($keywords) . "')");
        $post_processors = $criteria->get_post_processors();
        $query_limit = false;
        if (!$criteria->getNoLimit()) {
            $maxresults = vB::getDatastore()->getOption('maxresults');
            $maxresults = $maxresults > 0 ? $maxresults : 0;
            /*	This is a hacky compromise (ew) and not fully tested, and we may end up taking it out or modifying it.
             *	This is to handle the possibility that a post sphinx-search process (like when using the unread_only
             *	filter) can severely limit the # of search results after it was already limited by $maxresults. Users
             *	might be expecting that the very end result set is limited by the maxresults option, meaning we should
             *	place the LIMIT after the post processes, but if we don't place a limit on sphinx search, it might
             *	happily return all the nodes ever (not a very useful search in that case, but could happen). So the
             *	compromise is to use an "expected post process cull ratio" so that the final result is closer to the
             *	$maxresults. This means that any post processors should limit the max results themselves!
             */
            if (!empty($post_processors)) {
                // 1.5 is a completely arbitrary value. We have absolutely no research to show that 1.5 is the best ratio, but
                // it just seems like a nice and conservative starting point.
                $maxresults = $maxresults * 1.5;
            }
            if (!empty($maxresults)) {
                $query_limit = "LIMIT " . $maxresults;
            }
        }
        $groupby = '';
        if (!empty($this->groupby)) {
            $groupby = '
				GROUP BY ' . $this->groupby;
        }
        $query = '
			SELECT ' . implode(', ', $this->what) . '
			FROM ' . $this->table . '
			WHERE ' . implode(' AND ', $this->where) . $groupby . '
			ORDER BY ' . implode(', ', $this->sort) . "\n\t\t\t\t{$query_limit}\n\t\t\t/**" . __FUNCTION__ . (defined('THIS_SCRIPT') ? '- ' . THIS_SCRIPT : '') . "**/";
        $res = $this->sphinxDB->query($query);
        if (!empty($config['Misc']['debug_sql']) or self::DEBUG) {
            echo "{$query};\n";
        }
        if ($cacheKey) {
            $this->what[] = 'starteruser';
            $this->what[] = 'starterparent';
        }
        $results = array();
        $nodeids = array();
        while ($row = $this->sphinxDB->fetch_array($res)) {
            $value = current($row);
            $nodeids[$value] = $value;
            if ($cacheKey) {
                $results[$value] = array('nodeid' => $value, 'parentid' => $row['starterparent'], 'userid' => $row['starteruser']);
            }
        }
        if (empty($nodeids)) {
            return array();
        }
        if (empty($post_processors)) {
            if ($cacheKey) {
                $nodeids = array();
                if (!empty($this->filters['make_equals_filter']['channelid'])) {
                    $results = vB_Search_Core::saveSecondPassResults($results, $cacheKey, $this->filters['make_equals_filter']['channelid']);
                } else {
                    $results = vB_Search_Core::saveSecondPassResults($results, $cacheKey);
                }
                foreach ($results as $nodeid => $node) {
                    $nodeids[$nodeid] = $nodeid;
                }
            }
        } else {
            foreach ($post_processors as $post_processor) {
                $vBSphinxSearch_Core = new vBSphinxSearch_Core();
                // why do we need a new instance every time...?
                $nodeids = $vBSphinxSearch_Core->{$post_processor}($nodeids, $criteria);
            }
            if (empty($nodeids)) {
                return array();
            }
            $criteria->reset_post_processors();
        }
        return $nodeids;
    }
 /**
  * Get the search query string in the mysql full text format
  *
  * Built to produce the same search strings as the search.php file.
  * The natural language hack is from search.php
  *
  * @param vB_Legacy_Current_User $user user requesting the search
  * @param vB_Search_Criteria $criteria search criteria to process
  */
 protected function get_search_text($user, $criteria)
 {
     //	If the user doesn't have permission to search full text boolean mode,
     // use natural language mode.
     if ($user->hasPermission('genericpermissions', 'cansearchft_bool')) {
         $words = $criteria->get_keywords();
         $search_text = "";
         $word_count = 0;
         foreach ($words as $word_item) {
             $word_count++;
             //The value of the first term is ambiguous.  If the second term is
             //an "or" both the the first and second terms should be treated as
             //ors.  If the second term is an "and" or "not" then the first term
             //should be an and.
             if ($word_count == 2 and $word_item['joiner'] != 'OR') {
                 $search_text = "+{$search_text}";
             }
             $word = $word_item['word'];
             switch ($word_item['joiner']) {
                 case 'OR':
                     // OR is no operator
                     $search_text .= " {$word}";
                     break;
                 case 'NOT':
                     $search_text .= " -{$word}";
                     break;
                 case 'AND':
                     // if we didn't have a joiner, default to and
                 // if we didn't have a joiner, default to and
                 default:
                     if ($search_text) {
                         $search_text .= " +{$word}";
                     } else {
                         //if this is the first token added, then we don't want to assume any
                         //join logic. We need to figure that out on the second term.
                         $search_text = $word;
                     }
                     break;
             }
         }
         //not 100% sure about this, but it matches the results in search.php
         $search_text = str_replace('"', '\\"', trim($search_text));
     } else {
         $search_text = $criteria->get_raw_keywords();
         //if we are using the raw search text, use the whole string as the display text
         $criteria->set_keyword_display_string('<b><u>' . htmlspecialchars_uni($search_text) . '</u></b>');
         $criteria->set_highlights(array($search_text));
     }
     return $search_text;
 }
 /**
  * Hack to get original (unparced) text from search request.
  * Because vBulletin transform it in very stupid way.
  * Then fill some dependent variables.
  *
  * The word build up is taken from the socialgroup/blog implementation
  * The natural language hack is from search.php
  *
  * @param vB_Legacy_Current_User $user user requesting the search
  * @param vB_Search_Criteria $criteria search criteria to process
  */
 protected function _get_search_text($user, $criteria)
 {
     $search_text = $criteria->get_raw_keywords();
     //if we are using the raw search text, use the whole string as the display text
     $criteria->set_keyword_display_string('<b><u>' . htmlspecialchars_uni($search_text) . '</u></b>');
     $criteria->set_highlights(array($search_text));
     return trim($search_text);
 }