X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FSearchEngine.php;h=c3b38519a7f3e1085fe52df29a13c8ce57a39e75;hb=cdbbe0ad4aaf40c1872d204a68a014d77981e8b7;hp=a49f8e5043ce829ad13f4fbd39eade6948b8a805;hpb=eb0489b5da4ee3a3e1824a1741bdf60fc67bf2a5;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/SearchEngine.php b/includes/SearchEngine.php index a49f8e5043..c3b38519a7 100644 --- a/includes/SearchEngine.php +++ b/includes/SearchEngine.php @@ -2,6 +2,7 @@ /** * Contain a class for special pages * @package MediaWiki + * @subpackage Search */ /** @@ -11,69 +12,100 @@ class SearchEngine { var $limit = 10; var $offset = 0; var $searchTerms = array(); - var $namespaces = array( 0 ); + var $namespaces = array( NS_MAIN ); var $showRedirects = false; - + /** * Perform a full text search query and return a result set. + * If title searches are not supported or disabled, return null. * * @param string $term - Raw search term - * @param array $namespaces - List of namespaces to search - * @return ResultWrapper + * @return SearchResultSet * @access public + * @abstract */ function searchText( $term ) { - return $this->db->resultObject( $this->db->query( $this->getQuery( $this->filter( $term ), true ) ) ); + return null; } /** * Perform a title-only search query and return a result set. + * If title searches are not supported or disabled, return null. * * @param string $term - Raw search term - * @param array $namespaces - List of namespaces to search - * @return ResultWrapper + * @return SearchResultSet * @access public + * @abstract */ function searchTitle( $term ) { - return $this->db->resultObject( $this->db->query( $this->getQuery( $this->filter( $term ), false ) ) ); + return null; } - + /** * If an exact title match can be find, or a very slightly close match, * return the title. If no match, returns NULL. * + * @static * @param string $term * @return Title - * @access private + * @private */ function getNearMatch( $term ) { # Exact match? No need to look further. $title = Title::newFromText( $term ); - if ( $title->getNamespace() == NS_SPECIAL || 0 != $title->getArticleID() ) { + if (is_null($title)) + return NULL; + + if ( $title->getNamespace() == NS_SPECIAL || $title->exists() ) { return $title; } # Now try all lower case (i.e. first letter capitalized) # $title = Title::newFromText( strtolower( $term ) ); - if ( 0 != $title->getArticleID() ) { + if ( $title->exists() ) { return $title; } # Now try capitalized string # $title = Title::newFromText( ucwords( strtolower( $term ) ) ); - if ( 0 != $title->getArticleID() ) { + if ( $title->exists() ) { return $title; } # Now try all upper case # $title = Title::newFromText( strtoupper( $term ) ); - if ( 0 != $title->getArticleID() ) { + if ( $title->exists() ) { return $title; } + # Now try Word-Caps-Breaking-At-Word-Breaks, for hyphenated names etc + $title = Title::newFromText( preg_replace_callback( + '/\b([\w\x80-\xff]+)\b/', + create_function( '$matches', ' + global $wgContLang; + return $wgContLang->ucfirst($matches[1]); + ' ), + $term ) ); + if ( $title->exists() ) { + return $title; + } + + global $wgCapitalLinks, $wgContLang; + if( !$wgCapitalLinks ) { + // Catch differs-by-first-letter-case-only + $title = Title::newFromText( $wgContLang->ucfirst( $term ) ); + if ( $title->exists() ) { + return $title; + } + $title = Title::newFromText( $wgContLang->lcfirst( $term ) ); + if ( $title->exists() ) { + return $title; + } + } + $title = Title::newFromText( $term ); # Entering an IP address goes to the contributions page @@ -87,10 +119,15 @@ class SearchEngine { if ( $title->getNamespace() == NS_USER ) { return $title; } - + + # Quoted term? Try without the quotes... + if( preg_match( '/^"([^"]+)"$/', $term, $matches ) ) { + return SearchEngine::getNearMatch( $matches[1] ); + } + return NULL; } - + function legalSearchChars() { return "A-Za-z_'0-9\\x80-\\xFF\\-"; } @@ -104,10 +141,10 @@ class SearchEngine { * @access public */ function setLimitOffset( $limit, $offset = 0 ) { - $this->limit = IntVal( $limit ); - $this->offset = IntVal( $offset ); + $this->limit = intval( $limit ); + $this->offset = intval( $offset ); } - + /** * Set which namespaces the search should include. * Give an array of namespace index numbers. @@ -118,7 +155,7 @@ class SearchEngine { function setNamespaces( $namespaces ) { $this->namespaces = $namespaces; } - + /** * Make a list of searchable namespaces and their canonical names. * @return array @@ -134,18 +171,7 @@ class SearchEngine { } return $arr; } - - /** - * Fetch an array of regular expression fragments for matching - * the search terms as parsed by this engine in a text extract. - * - * @return array - * @access public - */ - function termMatches() { - return $this->searchTerms; - } - + /** * Return a 'cleaned up' search string * @@ -156,96 +182,150 @@ class SearchEngine { $lc = $this->legalSearchChars(); return trim( preg_replace( "/[^{$lc}]/", " ", $text ) ); } - /** - * Return a partial WHERE clause to exclude redirects, if so set - * @return string - * @access private + * Load up the appropriate search engine class for the currently + * active database backend, and return a configured instance. + * + * @return SearchEngine + * @private */ - function queryRedirect() { - if( $this->showRedirects ) { - return 'AND cur_is_redirect=0'; + function create() { + global $wgDBtype, $wgSearchType; + if( $wgSearchType ) { + $class = $wgSearchType; + } elseif( $wgDBtype == 'mysql' ) { + $class = 'SearchMySQL4'; + } else if ( $wgDBtype == 'postgres' ) { + $class = 'SearchPostgres'; } else { - return ''; + $class = 'SearchEngineDummy'; } + $search = new $class( wfGetDB( DB_SLAVE ) ); + $search->setLimitOffset(0,0); + return $search; } - + /** - * Return a partial WHERE clause to limit the search to the given namespaces - * @return string - * @access private + * Create or update the search index record for the given page. + * Title and text should be pre-processed. + * + * @param int $id + * @param string $title + * @param string $text + * @abstract */ - function queryNamespaces() { - $namespaces = implode( ',', $this->namespaces ); - if ($namespaces == '') { - $namespaces = '0'; - } - return 'AND page_namespace IN (' . $namespaces . ')'; + function update( $id, $title, $text ) { + // no-op } - + /** - * Return a LIMIT clause to limit results on the query. - * @return string - * @access private + * Update a search index record's title only. + * Title should be pre-processed. + * + * @param int $id + * @param string $title + * @abstract + */ + function updateTitle( $id, $title ) { + // no-op + } +} + +/** @package MediaWiki */ +class SearchResultSet { + /** + * Fetch an array of regular expression fragments for matching + * the search terms as parsed by this engine in a text extract. + * + * @return array + * @access public + * @abstract + */ + function termMatches() { + return array(); + } + + function numRows() { + return 0; + } + + /** + * Return true if results are included in this result set. + * @return bool + * @abstract */ - function queryLimit() { - return $this->db->limitResult( $this->limit, $this->offset ); + function hasResults() { + return false; } /** - * Does not do anything for generic search engine - * subclasses may define this though + * Some search modes return a total hit count for the query + * in the entire article database. This may include pages + * in namespaces that would not be matched on the given + * settings. + * + * Return null if no total hits number is supported. + * + * @return int + * @access public + */ + function getTotalHits() { + return null; + } + + /** + * Some search modes return a suggested alternate term if there are + * no exact hits. Returns true if there is one on this set. + * + * @return bool + * @access public + */ + function hasSuggestion() { + return false; + } + + /** + * Some search modes return a suggested alternate term if there are + * no exact hits. Check hasSuggestion() first. + * * @return string - * @access private + * @access public */ - function queryRanking($filteredTerm,$fulltext) { - return ""; + function getSuggestion() { + return ''; } - + /** - * Construct the full SQL query to do the search. - * The guts shoulds be constructed in queryMain() - * @param string $filteredTerm - * @param bool $fulltext - * @access private + * Fetches next search result, or false. + * @return SearchResult + * @access public + * @abstract */ - function getQuery( $filteredTerm, $fulltext ) { - return $this->queryMain( $filteredTerm, $fulltext ) . ' ' . - $this->queryRedirect() . ' ' . - $this->queryNamespaces() . ' ' . - $this->queryRanking($filteredTerm, $fulltext) . ' ' . - $this->queryLimit(); + function next() { + return false; + } +} + +/** @package MediaWiki */ +class SearchResult { + function SearchResult( $row ) { + $this->mTitle = Title::makeTitle( $row->page_namespace, $row->page_title ); } /** - * Load up the appropriate search engine class for the currently - * active database backend, and return a configured instance. - * - * @return SearchEngine - * @access private - */ - function create() { - global $wgDBtype, $wgDBmysql4, $wgSearchType; - if( $wgDBtype == 'mysql' ) { - if( $wgDBmysql4 ) { - $class = 'SearchMySQL4'; - require_once( 'SearchMySQL4.php' ); - } else { - $class = 'SearchMysql3'; - require_once( 'SearchMySQL3.php' ); - } - } else if ( $wgDBtype == 'PostgreSQL' ) { - $class = 'SearchTsearch2'; - require_once( 'SearchTsearch2.php' ); - } else { - $class = 'SearchEngineDummy'; - } - $search = new $class( wfGetDB( DB_SLAVE ) ); - $search->setLimitOffset(0,0); - return $search; + * @return Title + * @access public + */ + function getTitle() { + return $this->mTitle; } - + /** + * @return double or null if not supported + */ + function getScore() { + return null; + } } /** @@ -255,5 +335,11 @@ class SearchEngineDummy { function search( $term ) { return null; } + function setLimitOffset($l, $o) {} + function legalSearchChars() {} + function update() {} + function setnamespaces() {} + function searchtitle() {} + function searchtext() {} } - +?>