PicoraSearchQuery

Parses a search query string into a 'WHERE' SQL fragment.

This implementation is specific to MySQL's fulltext search functionality. It will not work with SQLite at this time. The search query string supports the following constructs:

  • single_words
  • multiple words
  • "quoted words"
  • -negative -words
  • -"negative quoted words"
  • wildcard*

For example:

  • apple
  • apple -computer
  • apple "wenatchee valley"
  • appl* stock -"wenatchee valley"
$search = new PicoraSearchQuery($this->params['query'],'title,body');
$articles = PicoraActiveRecord::findAll(array('where'=>$search->display()));
if(count($articles) == 0){
    $search->wildCardWords();
    $articles = PicoraActiveRecord::findAll(array('where'=>$search->display()));
}

Method Overview

Return Visibility Name Parameters
object public __construct (string $query_string, string $index_string)
string public display ()
void public wildCardWords ()

Method Detail

public __construct()

Parameter Type Name Description
string $query_string
string $index_string The fulltext index to search against

public display()

Generates a SQL where fragment for use in a full SQL query.

public wildCardWords()

Appends "*" to the end of each search term.

Declared in: PicoraSearchQuery.php

class PicoraSearchQuery {    
    protected $queryString;
    protected $indexString;
    protected $negativeQuoted = array();
    protected $quoted = array();
    protected $words = array();
    protected $negativeWords = array();
    /**
     * @param string $query_string
     * @param string $index_string The fulltext index to search against
     * @return object
     */
    public function __construct($query_string,$index_string){
        $this->queryString = strtolower($query_string);
        $this->indexString = (is_array($index_string) ? implode(',',$index_string) : $index_string);
        //turn "multi word stirngs" with single quotes into double quotes
        $working_string = preg_replace('/\'([^\']+)\'( ?)/','"\1"\2',$query_string);
        //match quoted strings and remove them from the string
        preg_match_all('/(\-)?"([^"]+)"/',$working_string,$quote_matches);
        foreach($quote_matches[2] as $i => $subject){
            //add the match to an index
            if(!empty($quote_matches[1][$i]))
                $this->{(!empty($quote_matches[1][$i]) ? 'negativeQuoted' : 'quoted')}[] = $quote_matches[2][$i];
            //remove the match from the string
            $string = str_replace($quote_matches[0][$i],'',$working_string);
        }
        //match all remaining subjects
        preg_match_all('/(\-)?([^\s]+)/',$working_string,$matches);
        foreach($matches[2] as $i => $subject)
            $this->{(!empty($matches[1][$i]) ? 'negativeWords' : 'words')}[] = $matches[2][$i];
    }
    /**
     * Appends "*" to the end of each search term.
     * @return void
     */
    public function wildCardWords(){
        foreach($this->words as $key => $word)
            if(strpos($word,'*') === false)
                $this->words[$key] .= '*';
    }
    /**
     * Generates a SQL where fragment for use in a full SQL query.
     * @return string SQL where fragment.
     */
    public function display(){
        $sql_substr = '';
        foreach($this->words as $word)
            $sql_substr .= addslashes($word).' ';
        foreach($this->quoted as $word)
            $sql_substr .= '"'.addslashes($word).'" ';
        foreach($this->negativeWords as $word)
            $sql_substr .= '-'.addslashes($word).' ';
        foreach($this->negativeQuoted as $word)
            $sql_substr .= '-"'.addslashes($word).'" ';
        return 'MATCH ('.$this->indexString.') AGAINST (\''.substr($sql_substr,0,-1).'\' IN BOOLEAN MODE)';
    }
    public function __toString(){
        return $this->display();
    }
}