summaryrefslogtreecommitdiff
path: root/includes/search
diff options
context:
space:
mode:
authorPierre Schmitz <pierre@archlinux.de>2011-06-22 11:28:20 +0200
committerPierre Schmitz <pierre@archlinux.de>2011-06-22 11:28:20 +0200
commit9db190c7e736ec8d063187d4241b59feaf7dc2d1 (patch)
tree46d1a0dee7febef5c2d57a9f7b972be16a163b3d /includes/search
parent78677c7bbdcc9739f6c10c75935898a20e1acd9e (diff)
update to MediaWiki 1.17.0
Diffstat (limited to 'includes/search')
-rw-r--r--includes/search/SearchEngine.php761
-rw-r--r--includes/search/SearchIBM_DB2.php53
-rw-r--r--includes/search/SearchMssql.php254
-rw-r--r--includes/search/SearchMySQL.php52
-rw-r--r--includes/search/SearchMySQL4.php34
-rw-r--r--includes/search/SearchOracle.php62
-rw-r--r--includes/search/SearchPostgres.php64
-rw-r--r--includes/search/SearchSqlite.php82
-rw-r--r--includes/search/SearchUpdate.php31
9 files changed, 873 insertions, 520 deletions
diff --git a/includes/search/SearchEngine.php b/includes/search/SearchEngine.php
index f4ca700d..17482da2 100644
--- a/includes/search/SearchEngine.php
+++ b/includes/search/SearchEngine.php
@@ -1,12 +1,16 @@
<?php
/**
- * @defgroup Search Search
+ * Basic search engine
*
* @file
* @ingroup Search
*/
/**
+ * @defgroup Search Search
+ */
+
+/**
* Contain a class for special pages
* @ingroup Search
*/
@@ -18,6 +22,14 @@ class SearchEngine {
var $namespaces = array( NS_MAIN );
var $showRedirects = false;
+ function __construct($db = null) {
+ if ( $db ) {
+ $this->db = $db;
+ } else {
+ $this->db = wfGetDB( DB_SLAVE );
+ }
+ }
+
/**
* Perform a full text search query and return a result set.
* If title searches are not supported or disabled, return null.
@@ -41,12 +53,12 @@ class SearchEngine {
function searchTitle( $term ) {
return null;
}
-
+
/** If this search backend can list/unlist redirects */
function acceptListRedirects() {
return true;
}
-
+
/**
* When overridden in derived class, performs database-specific conversions
* on text to be used for searching or updating search index.
@@ -56,7 +68,10 @@ class SearchEngine {
* @return string
*/
public function normalizeText( $string ) {
- return $string;
+ global $wgContLang;
+
+ // Some languages such as Chinese require word segmentation
+ return $wgContLang->segmentByWord( $string );
}
/**
@@ -66,7 +81,7 @@ class SearchEngine {
function transformSearchTerm( $term ) {
return $term;
}
-
+
/**
* If an exact title match can be found, or a very slightly close match,
* return the title. If no match, returns NULL.
@@ -76,41 +91,53 @@ class SearchEngine {
*/
public static function getNearMatch( $searchterm ) {
$title = self::getNearMatchInternal( $searchterm );
-
+
wfRunHooks( 'SearchGetNearMatchComplete', array( $searchterm, &$title ) );
return $title;
}
/**
+ * Do a near match (see SearchEngine::getNearMatch) and wrap it into a
+ * SearchResultSet.
+ *
+ * @param $searchterm string
+ * @return SearchResultSet
+ */
+ public static function getNearMatchResultSet( $searchterm ) {
+ return new SearchNearMatchResultSet( self::getNearMatch( $searchterm ) );
+ }
+
+ /**
* Really find the title match.
*/
private static function getNearMatchInternal( $searchterm ) {
global $wgContLang;
- $allSearchTerms = array($searchterm);
+ $allSearchTerms = array( $searchterm );
if ( $wgContLang->hasVariants() ) {
- $allSearchTerms = array_merge($allSearchTerms,$wgContLang->convertLinkToAllVariants($searchterm));
+ $allSearchTerms = array_merge( $allSearchTerms, $wgContLang->autoConvertToAllVariants( $searchterm ) );
}
- if( !wfRunHooks( 'SearchGetNearMatchBefore', array( $allSearchTerms, &$titleResult ) ) ) {
+ $titleResult = null;
+ if ( !wfRunHooks( 'SearchGetNearMatchBefore', array( $allSearchTerms, &$titleResult ) ) ) {
return $titleResult;
}
- foreach($allSearchTerms as $term) {
+ foreach ( $allSearchTerms as $term ) {
# Exact match? No need to look further.
$title = Title::newFromText( $term );
- if (is_null($title))
+ if ( is_null( $title ) )
return null;
if ( $title->getNamespace() == NS_SPECIAL || $title->isExternal() || $title->exists() ) {
return $title;
}
-
+
# See if it still otherwise has content is some sane sense
$article = MediaWiki::articleFromTitle( $title );
- if( $article->hasViewableContent() ) {
+ if ( $article->hasViewableContent() ) {
return $title;
}
@@ -136,14 +163,14 @@ class SearchEngine {
}
# Now try Word-Caps-Breaking-At-Word-Breaks, for hyphenated names etc
- $title = Title::newFromText( $wgContLang->ucwordbreaks($term) );
+ $title = Title::newFromText( $wgContLang->ucwordbreaks( $term ) );
if ( $title && $title->exists() ) {
return $title;
}
// Give hooks a chance at better match variants
$title = null;
- if( !wfRunHooks( 'SearchGetNearMatch', array( $term, &$title ) ) ) {
+ if ( !wfRunHooks( 'SearchGetNearMatch', array( $term, &$title ) ) ) {
return $title;
}
}
@@ -151,7 +178,7 @@ class SearchEngine {
$title = Title::newFromText( $searchterm );
# Entering an IP address goes to the contributions page
- if ( ( $title->getNamespace() == NS_USER && User::isIP($title->getText() ) )
+ if ( ( $title->getNamespace() == NS_USER && User::isIP( $title->getText() ) )
|| User::isIP( trim( $searchterm ) ) ) {
return SpecialPage::getTitleFor( 'Contributions', $title->getDBkey() );
}
@@ -165,22 +192,22 @@ class SearchEngine {
# Go to images that exist even if there's no local page.
# There may have been a funny upload, or it may be on a shared
# file repository such as Wikimedia Commons.
- if( $title->getNamespace() == NS_FILE ) {
+ if ( $title->getNamespace() == NS_FILE ) {
$image = wfFindFile( $title );
- if( $image ) {
+ if ( $image ) {
return $title;
}
}
# MediaWiki namespace? Page may be "implied" if not customized.
# Just return it, with caps forced as the message system likes it.
- if( $title->getNamespace() == NS_MEDIAWIKI ) {
+ if ( $title->getNamespace() == NS_MEDIAWIKI ) {
return Title::makeTitle( NS_MEDIAWIKI, $wgContLang->ucfirst( $title->getText() ) );
}
# Quoted term? Try without the quotes...
$matches = array();
- if( preg_match( '/^"([^"]+)"$/', $searchterm, $matches ) ) {
+ if ( preg_match( '/^"([^"]+)"$/', $searchterm, $matches ) ) {
return SearchEngine::getNearMatch( $matches[1] );
}
@@ -219,28 +246,28 @@ class SearchEngine {
*
* @param $query String
*/
- function replacePrefixes( $query ){
+ function replacePrefixes( $query ) {
global $wgContLang;
$parsed = $query;
- if( strpos($query,':') === false ) { // nothing to do
+ if ( strpos( $query, ':' ) === false ) { // nothing to do
wfRunHooks( 'SearchEngineReplacePrefixesComplete', array( $this, $query, &$parsed ) );
return $parsed;
}
-
- $allkeyword = wfMsgForContent('searchall').":";
- if( strncmp($query, $allkeyword, strlen($allkeyword)) == 0 ){
+
+ $allkeyword = wfMsgForContent( 'searchall' ) . ":";
+ if ( strncmp( $query, $allkeyword, strlen( $allkeyword ) ) == 0 ) {
$this->namespaces = null;
- $parsed = substr($query,strlen($allkeyword));
- } else if( strpos($query,':') !== false ) {
- $prefix = substr($query,0,strpos($query,':'));
- $index = $wgContLang->getNsIndex($prefix);
- if($index !== false){
- $this->namespaces = array($index);
- $parsed = substr($query,strlen($prefix)+1);
+ $parsed = substr( $query, strlen( $allkeyword ) );
+ } else if ( strpos( $query, ':' ) !== false ) {
+ $prefix = substr( $query, 0, strpos( $query, ':' ) );
+ $index = $wgContLang->getNsIndex( $prefix );
+ if ( $index !== false ) {
+ $this->namespaces = array( $index );
+ $parsed = substr( $query, strlen( $prefix ) + 1 );
}
}
- if(trim($parsed) == '')
+ if ( trim( $parsed ) == '' )
$parsed = $query; // prefix was the whole query
wfRunHooks( 'SearchEngineReplacePrefixesComplete', array( $this, $query, &$parsed ) );
@@ -255,16 +282,16 @@ class SearchEngine {
public static function searchableNamespaces() {
global $wgContLang;
$arr = array();
- foreach( $wgContLang->getNamespaces() as $ns => $name ) {
- if( $ns >= NS_MAIN ) {
+ foreach ( $wgContLang->getNamespaces() as $ns => $name ) {
+ if ( $ns >= NS_MAIN ) {
$arr[$ns] = $name;
}
}
-
+
wfRunHooks( 'SearchableNamespaces', array( &$arr ) );
return $arr;
}
-
+
/**
* Extract default namespaces to search from the given user's
* settings, returning a list of index numbers.
@@ -274,78 +301,78 @@ class SearchEngine {
*/
public static function userNamespaces( $user ) {
global $wgSearchEverythingOnlyLoggedIn;
-
+
// get search everything preference, that can be set to be read for logged-in users
$searcheverything = false;
- if( ( $wgSearchEverythingOnlyLoggedIn && $user->isLoggedIn() )
+ if ( ( $wgSearchEverythingOnlyLoggedIn && $user->isLoggedIn() )
|| !$wgSearchEverythingOnlyLoggedIn )
- $searcheverything = $user->getOption('searcheverything');
-
- // searcheverything overrides other options
- if( $searcheverything )
- return array_keys(SearchEngine::searchableNamespaces());
-
+ $searcheverything = $user->getOption( 'searcheverything' );
+
+ // searcheverything overrides other options
+ if ( $searcheverything )
+ return array_keys( SearchEngine::searchableNamespaces() );
+
$arr = Preferences::loadOldSearchNs( $user );
$searchableNamespaces = SearchEngine::searchableNamespaces();
-
- $arr = array_intersect( $arr, array_keys($searchableNamespaces) ); // Filter
-
+
+ $arr = array_intersect( $arr, array_keys( $searchableNamespaces ) ); // Filter
+
return $arr;
}
-
+
/**
* Find snippet highlight settings for a given user
*
* @param $user User
- * @return Array contextlines, contextchars
+ * @return Array contextlines, contextchars
*/
- public static function userHighlightPrefs( &$user ){
- //$contextlines = $user->getOption( 'contextlines', 5 );
- //$contextchars = $user->getOption( 'contextchars', 50 );
+ public static function userHighlightPrefs( &$user ) {
+ // $contextlines = $user->getOption( 'contextlines', 5 );
+ // $contextchars = $user->getOption( 'contextchars', 50 );
$contextlines = 2; // Hardcode this. Old defaults sucked. :)
$contextchars = 75; // same as above.... :P
- return array($contextlines, $contextchars);
+ return array( $contextlines, $contextchars );
}
-
+
/**
* An array of namespaces indexes to be searched by default
- *
- * @return Array
+ *
+ * @return Array
*/
- public static function defaultNamespaces(){
+ public static function defaultNamespaces() {
global $wgNamespacesToBeSearchedDefault;
-
- return array_keys($wgNamespacesToBeSearchedDefault, true);
+
+ return array_keys( $wgNamespacesToBeSearchedDefault, true );
}
-
+
/**
* Get a list of namespace names useful for showing in tooltips
* and preferences
*
* @param $namespaces Array
*/
- public static function namespacesAsText( $namespaces ){
+ public static function namespacesAsText( $namespaces ) {
global $wgContLang;
-
- $formatted = array_map( array($wgContLang,'getFormattedNsText'), $namespaces );
- foreach( $formatted as $key => $ns ){
- if ( empty($ns) )
+
+ $formatted = array_map( array( $wgContLang, 'getFormattedNsText' ), $namespaces );
+ foreach ( $formatted as $key => $ns ) {
+ if ( empty( $ns ) )
$formatted[$key] = wfMsg( 'blanknamespace' );
}
return $formatted;
}
-
+
/**
* Return the help namespaces to be shown on Special:Search
- *
- * @return Array
+ *
+ * @return Array
*/
public static function helpNamespaces() {
global $wgNamespacesToBeSearchedHelp;
-
+
return array_keys( $wgNamespacesToBeSearchedHelp, true );
}
-
+
/**
* Return a 'cleaned up' search string
*
@@ -364,14 +391,15 @@ class SearchEngine {
*/
public static function create() {
global $wgSearchType;
- $dbr = wfGetDB( DB_SLAVE );
- if( $wgSearchType ) {
+ $dbr = null;
+ if ( $wgSearchType ) {
$class = $wgSearchType;
} else {
+ $dbr = wfGetDB( DB_SLAVE );
$class = $dbr->getSearchEngine();
}
$search = new $class( $dbr );
- $search->setLimitOffset(0,0);
+ $search->setLimitOffset( 0, 0 );
return $search;
}
@@ -399,34 +427,34 @@ class SearchEngine {
function updateTitle( $id, $title ) {
// no-op
}
-
+
/**
* Get OpenSearch suggestion template
- *
+ *
* @return String
*/
public static function getOpenSearchTemplate() {
- global $wgOpenSearchTemplate, $wgServer, $wgScriptPath;
- if( $wgOpenSearchTemplate ) {
+ global $wgOpenSearchTemplate, $wgServer;
+ if ( $wgOpenSearchTemplate ) {
return $wgOpenSearchTemplate;
- } else {
+ } else {
$ns = implode( '|', SearchEngine::defaultNamespaces() );
- if( !$ns ) $ns = "0";
- return $wgServer . $wgScriptPath . '/api.php?action=opensearch&search={searchTerms}&namespace='.$ns;
+ if ( !$ns ) $ns = "0";
+ return $wgServer . wfScript( 'api' ) . '?action=opensearch&search={searchTerms}&namespace=' . $ns;
}
}
-
+
/**
- * Get internal MediaWiki Suggest template
- *
+ * Get internal MediaWiki Suggest template
+ *
* @return String
*/
public static function getMWSuggestTemplate() {
- global $wgMWSuggestTemplate, $wgServer, $wgScriptPath;
- if($wgMWSuggestTemplate)
+ global $wgMWSuggestTemplate, $wgServer;
+ if ( $wgMWSuggestTemplate )
return $wgMWSuggestTemplate;
- else
- return $wgServer . $wgScriptPath . '/api.php?action=opensearch&search={searchTerms}&namespace={namespaces}&suggest';
+ else
+ return $wgServer . wfScript( 'api' ) . '?action=opensearch&search={searchTerms}&namespace={namespaces}&suggest';
}
}
@@ -486,27 +514,27 @@ class SearchResultSet {
/**
* @return String: suggested query, null if none
*/
- function getSuggestionQuery(){
+ function getSuggestionQuery() {
return null;
}
/**
* @return String: HTML highlighted suggested query, '' if none
*/
- function getSuggestionSnippet(){
+ function getSuggestionSnippet() {
return '';
}
-
+
/**
* Return information about how and from where the results were fetched,
- * should be useful for diagnostics and debugging
+ * should be useful for diagnostics and debugging
*
* @return String
*/
function getInfo() {
return null;
}
-
+
/**
* Return a result set of hits on other (multiple) wikis associated with this one
*
@@ -515,7 +543,7 @@ class SearchResultSet {
function getInterwikiResults() {
return null;
}
-
+
/**
* Check if there are results on other wikis
*
@@ -524,7 +552,6 @@ class SearchResultSet {
function hasInterwikiResults() {
return $this->getInterwikiResults() != null;
}
-
/**
* Fetches next search result, or false.
@@ -558,20 +585,27 @@ class SqlSearchResultSet extends SearchResultSet {
}
function numRows() {
+ if ( $this->mResultSet === false )
+ return false;
+
return $this->mResultSet->numRows();
}
function next() {
- if ($this->mResultSet === false )
+ if ( $this->mResultSet === false )
return false;
$row = $this->mResultSet->fetchObject();
- if ($row === false)
+ if ( $row === false )
return false;
- return new SearchResult($row);
+
+ return SearchResult::newFromRow( $row );
}
function free() {
+ if ( $this->mResultSet === false )
+ return false;
+
$this->mResultSet->free();
}
}
@@ -580,7 +614,7 @@ class SqlSearchResultSet extends SearchResultSet {
* @ingroup Search
*/
class SearchResultTooMany {
- ## Some search engines may bail out if too many matches are found
+ # # Some search engines may bail out if too many matches are found
}
@@ -594,32 +628,78 @@ class SearchResult {
var $mRevision = null;
var $mImage = null;
- function __construct( $row ) {
- $this->mTitle = Title::makeTitle( $row->page_namespace, $row->page_title );
- if( !is_null($this->mTitle) ){
+ /**
+ * Return a new SearchResult and initializes it with a title.
+ *
+ * @param $title Title
+ * @return SearchResult
+ */
+ public static function newFromTitle( $title ) {
+ $result = new self();
+ $result->initFromTitle( $title );
+ return $result;
+ }
+ /**
+ * Return a new SearchResult and initializes it with a row.
+ *
+ * @param $row object
+ * @return SearchResult
+ */
+ public static function newFromRow( $row ) {
+ $result = new self();
+ $result->initFromRow( $row );
+ return $result;
+ }
+
+ public function __construct( $row = null ) {
+ if ( !is_null( $row ) ) {
+ // Backwards compatibility with pre-1.17 callers
+ $this->initFromRow( $row );
+ }
+ }
+
+ /**
+ * Initialize from a database row. Makes a Title and passes that to
+ * initFromTitle.
+ *
+ * @param $row object
+ */
+ protected function initFromRow( $row ) {
+ $this->initFromTitle( Title::makeTitle( $row->page_namespace, $row->page_title ) );
+ }
+
+ /**
+ * Initialize from a Title and if possible initializes a corresponding
+ * Revision and File.
+ *
+ * @param $title Title
+ */
+ protected function initFromTitle( $title ) {
+ $this->mTitle = $title;
+ if ( !is_null( $this->mTitle ) ) {
$this->mRevision = Revision::newFromTitle( $this->mTitle );
- if( $this->mTitle->getNamespace() === NS_FILE )
+ if ( $this->mTitle->getNamespace() === NS_FILE )
$this->mImage = wfFindFile( $this->mTitle );
}
}
-
+
/**
* Check if this is result points to an invalid title
*
* @return Boolean
*/
- function isBrokenTitle(){
- if( is_null($this->mTitle) )
+ function isBrokenTitle() {
+ if ( is_null( $this->mTitle ) )
return true;
return false;
}
-
+
/**
* Check if target page is missing, happens when index is out of date
- *
+ *
* @return Boolean
*/
- function isMissingRevision(){
+ function isMissingRevision() {
return !$this->mRevision && !$this->mImage;
}
@@ -640,36 +720,36 @@ class SearchResult {
/**
* Lazy initialization of article text from DB
*/
- protected function initText(){
- if( !isset($this->mText) ){
- if($this->mRevision != null)
+ protected function initText() {
+ if ( !isset( $this->mText ) ) {
+ if ( $this->mRevision != null )
$this->mText = $this->mRevision->getText();
else // TODO: can we fetch raw wikitext for commons images?
$this->mText = '';
-
+
}
}
-
+
/**
* @param $terms Array: terms to highlight
- * @return String: highlighted text snippet, null (and not '') if not supported
+ * @return String: highlighted text snippet, null (and not '') if not supported
*/
- function getTextSnippet($terms){
+ function getTextSnippet( $terms ) {
global $wgUser, $wgAdvancedSearchHighlighting;
$this->initText();
- list($contextlines,$contextchars) = SearchEngine::userHighlightPrefs($wgUser);
+ list( $contextlines, $contextchars ) = SearchEngine::userHighlightPrefs( $wgUser );
$h = new SearchHighlighter();
- if( $wgAdvancedSearchHighlighting )
+ if ( $wgAdvancedSearchHighlighting )
return $h->highlightText( $this->mText, $terms, $contextlines, $contextchars );
else
return $h->highlightSimple( $this->mText, $terms, $contextlines, $contextchars );
}
-
+
/**
* @param $terms Array: terms to highlight
* @return String: highlighted title, '' if not supported
*/
- function getTitleSnippet($terms){
+ function getTitleSnippet( $terms ) {
return '';
}
@@ -677,46 +757,46 @@ class SearchResult {
* @param $terms Array: terms to highlight
* @return String: highlighted redirect name (redirect to this page), '' if none or not supported
*/
- function getRedirectSnippet($terms){
+ function getRedirectSnippet( $terms ) {
return '';
}
/**
* @return Title object for the redirect to this page, null if none or not supported
*/
- function getRedirectTitle(){
+ function getRedirectTitle() {
return null;
}
/**
* @return string highlighted relevant section name, null if none or not supported
*/
- function getSectionSnippet(){
+ function getSectionSnippet() {
return '';
}
/**
* @return Title object (pagename+fragment) for the section, null if none or not supported
*/
- function getSectionTitle(){
+ function getSectionTitle() {
return null;
}
/**
* @return String: timestamp
*/
- function getTimestamp(){
- if( $this->mRevision )
+ function getTimestamp() {
+ if ( $this->mRevision )
return $this->mRevision->getTimestamp();
- else if( $this->mImage )
+ else if ( $this->mImage )
return $this->mImage->getTimestamp();
- return '';
+ return '';
}
/**
* @return Integer: number of words
*/
- function getWordCount(){
+ function getWordCount() {
$this->initText();
return str_word_count( $this->mText );
}
@@ -724,38 +804,63 @@ class SearchResult {
/**
* @return Integer: size in bytes
*/
- function getByteSize(){
+ function getByteSize() {
$this->initText();
return strlen( $this->mText );
}
-
+
/**
* @return Boolean if hit has related articles
*/
- function hasRelated(){
+ function hasRelated() {
return false;
}
-
+
/**
* @return String: interwiki prefix of the title (return iw even if title is broken)
*/
- function getInterwikiPrefix(){
+ function getInterwikiPrefix() {
return '';
}
}
+/**
+ * A SearchResultSet wrapper for SearchEngine::getNearMatch
+ */
+class SearchNearMatchResultSet extends SearchResultSet {
+ private $fetched = false;
+ /**
+ * @param $match mixed Title if matched, else null
+ */
+ public function __construct( $match ) {
+ $this->result = $match;
+ }
+ public function hasResult() {
+ return (bool)$this->result;
+ }
+ public function numRows() {
+ return $this->hasResults() ? 1 : 0;
+ }
+ public function next() {
+ if ( $this->fetched || !$this->result ) {
+ return false;
+ }
+ $this->fetched = true;
+ return SearchResult::newFromTitle( $this->result );
+ }
+}
/**
* Highlight bits of wikitext
- *
+ *
* @ingroup Search
*/
-class SearchHighlighter {
+class SearchHighlighter {
var $mCleanWikitext = true;
-
- function SearchHighlighter($cleanupWikitext = true){
+
+ function __construct( $cleanupWikitext = true ) {
$this->mCleanWikitext = $cleanupWikitext;
}
-
+
/**
* Default implementation of wikitext highlighting
*
@@ -766,23 +871,23 @@ class SearchHighlighter {
* @return String
*/
public function highlightText( $text, $terms, $contextlines, $contextchars ) {
- global $wgLang, $wgContLang;
+ global $wgContLang;
global $wgSearchHighlightBoundaries;
$fname = __METHOD__;
-
- if($text == '')
+
+ if ( $text == '' )
return '';
-
+
// spli text into text + templates/links/tables
$spat = "/(\\{\\{)|(\\[\\[[^\\]:]+:)|(\n\\{\\|)";
// first capture group is for detecting nested templates/links/tables/references
$endPatterns = array(
1 => '/(\{\{)|(\}\})/', // template
2 => '/(\[\[)|(\]\])/', // image
- 3 => "/(\n\\{\\|)|(\n\\|\\})/"); // table
-
+ 3 => "/(\n\\{\\|)|(\n\\|\\})/" ); // table
+
// FIXME: this should prolly be a hook or something
- if(function_exists('wfCite')){
+ if ( function_exists( 'wfCite' ) ) {
$spat .= '|(<ref>)'; // references via cite extension
$endPatterns[4] = '/(<ref>)|(<\/ref>)/';
}
@@ -791,213 +896,215 @@ class SearchHighlighter {
$otherExt = array(); // other extracts
wfProfileIn( "$fname-split" );
$start = 0;
- $textLen = strlen($text);
+ $textLen = strlen( $text );
$count = 0; // sequence number to maintain ordering
- while( $start < $textLen ){
+ while ( $start < $textLen ) {
// find start of template/image/table
- if( preg_match( $spat, $text, $matches, PREG_OFFSET_CAPTURE, $start ) ){
- $epat = '';
- foreach($matches as $key => $val){
- if($key > 0 && $val[1] != -1){
- if($key == 2){
+ if ( preg_match( $spat, $text, $matches, PREG_OFFSET_CAPTURE, $start ) ) {
+ $epat = '';
+ foreach ( $matches as $key => $val ) {
+ if ( $key > 0 && $val[1] != - 1 ) {
+ if ( $key == 2 ) {
// see if this is an image link
- $ns = substr($val[0],2,-1);
- if( $wgContLang->getNsIndex($ns) != NS_FILE )
+ $ns = substr( $val[0], 2, - 1 );
+ if ( $wgContLang->getNsIndex( $ns ) != NS_FILE )
break;
-
+
}
$epat = $endPatterns[$key];
- $this->splitAndAdd( $textExt, $count, substr( $text, $start, $val[1] - $start ) );
+ $this->splitAndAdd( $textExt, $count, substr( $text, $start, $val[1] - $start ) );
$start = $val[1];
break;
}
}
- if( $epat ){
+ if ( $epat ) {
// find end (and detect any nested elements)
- $level = 0;
+ $level = 0;
$offset = $start + 1;
$found = false;
- while( preg_match( $epat, $text, $endMatches, PREG_OFFSET_CAPTURE, $offset ) ){
- if( array_key_exists(2,$endMatches) ){
+ while ( preg_match( $epat, $text, $endMatches, PREG_OFFSET_CAPTURE, $offset ) ) {
+ if ( array_key_exists( 2, $endMatches ) ) {
// found end
- if($level == 0){
- $len = strlen($endMatches[2][0]);
+ if ( $level == 0 ) {
+ $len = strlen( $endMatches[2][0] );
$off = $endMatches[2][1];
- $this->splitAndAdd( $otherExt, $count,
+ $this->splitAndAdd( $otherExt, $count,
substr( $text, $start, $off + $len - $start ) );
$start = $off + $len;
$found = true;
break;
- } else{
+ } else {
// end of nested element
$level -= 1;
}
- } else{
+ } else {
// nested
$level += 1;
}
- $offset = $endMatches[0][1] + strlen($endMatches[0][0]);
+ $offset = $endMatches[0][1] + strlen( $endMatches[0][0] );
}
- if( ! $found ){
+ if ( ! $found ) {
// couldn't find appropriate closing tag, skip
- $this->splitAndAdd( $textExt, $count, substr( $text, $start, strlen($matches[0][0]) ) );
- $start += strlen($matches[0][0]);
+ $this->splitAndAdd( $textExt, $count, substr( $text, $start, strlen( $matches[0][0] ) ) );
+ $start += strlen( $matches[0][0] );
}
continue;
}
}
// else: add as text extract
- $this->splitAndAdd( $textExt, $count, substr($text,$start) );
+ $this->splitAndAdd( $textExt, $count, substr( $text, $start ) );
break;
}
-
+
$all = $textExt + $otherExt; // these have disjunct key sets
-
+
wfProfileOut( "$fname-split" );
-
+
// prepare regexps
- foreach( $terms as $index => $term ) {
+ foreach ( $terms as $index => $term ) {
// manually do upper/lowercase stuff for utf-8 since PHP won't do it
- if(preg_match('/[\x80-\xff]/', $term) ){
- $terms[$index] = preg_replace_callback('/./us',array($this,'caseCallback'),$terms[$index]);
+ if ( preg_match( '/[\x80-\xff]/', $term ) ) {
+ $terms[$index] = preg_replace_callback( '/./us', array( $this, 'caseCallback' ), $terms[$index] );
} else {
$terms[$index] = $term;
}
}
$anyterm = implode( '|', $terms );
- $phrase = implode("$wgSearchHighlightBoundaries+", $terms );
+ $phrase = implode( "$wgSearchHighlightBoundaries+", $terms );
// FIXME: a hack to scale contextchars, a correct solution
// would be to have contextchars actually be char and not byte
// length, and do proper utf-8 substrings and lengths everywhere,
// but PHP is making that very hard and unclean to implement :(
- $scale = strlen($anyterm) / mb_strlen($anyterm);
+ $scale = strlen( $anyterm ) / mb_strlen( $anyterm );
$contextchars = intval( $contextchars * $scale );
-
+
$patPre = "(^|$wgSearchHighlightBoundaries)";
- $patPost = "($wgSearchHighlightBoundaries|$)";
-
- $pat1 = "/(".$phrase.")/ui";
- $pat2 = "/$patPre(".$anyterm.")$patPost/ui";
-
+ $patPost = "($wgSearchHighlightBoundaries|$)";
+
+ $pat1 = "/(" . $phrase . ")/ui";
+ $pat2 = "/$patPre(" . $anyterm . ")$patPost/ui";
+
wfProfileIn( "$fname-extract" );
-
+
$left = $contextlines;
$snippets = array();
- $offsets = array();
-
+ $offsets = array();
+
// show beginning only if it contains all words
$first = 0;
$firstText = '';
- foreach($textExt as $index => $line){
- if(strlen($line)>0 && $line[0] != ';' && $line[0] != ':'){
+ foreach ( $textExt as $index => $line ) {
+ if ( strlen( $line ) > 0 && $line[0] != ';' && $line[0] != ':' ) {
$firstText = $this->extract( $line, 0, $contextchars * $contextlines );
$first = $index;
break;
}
}
- if( $firstText ){
+ if ( $firstText ) {
$succ = true;
// check if first text contains all terms
- foreach($terms as $term){
- if( ! preg_match("/$patPre".$term."$patPost/ui", $firstText) ){
+ foreach ( $terms as $term ) {
+ if ( ! preg_match( "/$patPre" . $term . "$patPost/ui", $firstText ) ) {
$succ = false;
break;
}
}
- if( $succ ){
+ if ( $succ ) {
$snippets[$first] = $firstText;
- $offsets[$first] = 0;
+ $offsets[$first] = 0;
}
}
- if( ! $snippets ) {
- // match whole query on text
- $this->process($pat1, $textExt, $left, $contextchars, $snippets, $offsets);
+ if ( ! $snippets ) {
+ // match whole query on text
+ $this->process( $pat1, $textExt, $left, $contextchars, $snippets, $offsets );
// match whole query on templates/tables/images
- $this->process($pat1, $otherExt, $left, $contextchars, $snippets, $offsets);
+ $this->process( $pat1, $otherExt, $left, $contextchars, $snippets, $offsets );
// match any words on text
- $this->process($pat2, $textExt, $left, $contextchars, $snippets, $offsets);
+ $this->process( $pat2, $textExt, $left, $contextchars, $snippets, $offsets );
// match any words on templates/tables/images
- $this->process($pat2, $otherExt, $left, $contextchars, $snippets, $offsets);
-
- ksort($snippets);
+ $this->process( $pat2, $otherExt, $left, $contextchars, $snippets, $offsets );
+
+ ksort( $snippets );
}
-
+
// add extra chars to each snippet to make snippets constant size
- $extended = array();
- if( count( $snippets ) == 0){
+ $extended = array();
+ if ( count( $snippets ) == 0 ) {
// couldn't find the target words, just show beginning of article
- $targetchars = $contextchars * $contextlines;
- $snippets[$first] = '';
- $offsets[$first] = 0;
- } else{
- // if begin of the article contains the whole phrase, show only that !!
- if( array_key_exists($first,$snippets) && preg_match($pat1,$snippets[$first])
- && $offsets[$first] < $contextchars * 2 ){
- $snippets = array ($first => $snippets[$first]);
+ if ( array_key_exists( $first, $all ) ) {
+ $targetchars = $contextchars * $contextlines;
+ $snippets[$first] = '';
+ $offsets[$first] = 0;
}
-
+ } else {
+ // if begin of the article contains the whole phrase, show only that !!
+ if ( array_key_exists( $first, $snippets ) && preg_match( $pat1, $snippets[$first] )
+ && $offsets[$first] < $contextchars * 2 ) {
+ $snippets = array ( $first => $snippets[$first] );
+ }
+
// calc by how much to extend existing snippets
- $targetchars = intval( ($contextchars * $contextlines) / count ( $snippets ) );
- }
+ $targetchars = intval( ( $contextchars * $contextlines ) / count ( $snippets ) );
+ }
- foreach($snippets as $index => $line){
+ foreach ( $snippets as $index => $line ) {
$extended[$index] = $line;
- $len = strlen($line);
- if( $len < $targetchars - 20 ){
+ $len = strlen( $line );
+ if ( $len < $targetchars - 20 ) {
// complete this line
- if($len < strlen( $all[$index] )){
- $extended[$index] = $this->extract( $all[$index], $offsets[$index], $offsets[$index]+$targetchars, $offsets[$index]);
+ if ( $len < strlen( $all[$index] ) ) {
+ $extended[$index] = $this->extract( $all[$index], $offsets[$index], $offsets[$index] + $targetchars, $offsets[$index] );
$len = strlen( $extended[$index] );
}
-
+
// add more lines
$add = $index + 1;
- while( $len < $targetchars - 20
- && array_key_exists($add,$all)
- && !array_key_exists($add,$snippets) ){
+ while ( $len < $targetchars - 20
+ && array_key_exists( $add, $all )
+ && !array_key_exists( $add, $snippets ) ) {
$offsets[$add] = 0;
- $tt = "\n".$this->extract( $all[$add], 0, $targetchars - $len, $offsets[$add] );
+ $tt = "\n" . $this->extract( $all[$add], 0, $targetchars - $len, $offsets[$add] );
$extended[$add] = $tt;
$len += strlen( $tt );
- $add++;
+ $add++;
}
- }
+ }
}
-
- //$snippets = array_map('htmlspecialchars', $extended);
+
+ // $snippets = array_map('htmlspecialchars', $extended);
$snippets = $extended;
- $last = -1;
+ $last = - 1;
$extract = '';
- foreach($snippets as $index => $line){
- if($last == -1)
+ foreach ( $snippets as $index => $line ) {
+ if ( $last == - 1 )
$extract .= $line; // first line
- elseif($last+1 == $index && $offsets[$last]+strlen($snippets[$last]) >= strlen($all[$last]))
- $extract .= " ".$line; // continous lines
+ elseif ( $last + 1 == $index && $offsets[$last] + strlen( $snippets[$last] ) >= strlen( $all[$last] ) )
+ $extract .= " " . $line; // continous lines
else
$extract .= '<b> ... </b>' . $line;
$last = $index;
}
- if( $extract )
+ if ( $extract )
$extract .= '<b> ... </b>';
-
+
$processed = array();
- foreach($terms as $term){
- if( ! isset($processed[$term]) ){
- $pat3 = "/$patPre(".$term.")$patPost/ui"; // highlight word
+ foreach ( $terms as $term ) {
+ if ( ! isset( $processed[$term] ) ) {
+ $pat3 = "/$patPre(" . $term . ")$patPost/ui"; // highlight word
$extract = preg_replace( $pat3,
"\\1<span class='searchmatch'>\\2</span>\\3", $extract );
$processed[$term] = true;
}
}
-
+
wfProfileOut( "$fname-extract" );
-
+
return $extract;
}
-
+
/**
* Split text into lines and add it to extracts array
*
@@ -1005,28 +1112,28 @@ class SearchHighlighter {
* @param $count Integer
* @param $text String
*/
- function splitAndAdd(&$extracts, &$count, $text){
- $split = explode( "\n", $this->mCleanWikitext? $this->removeWiki($text) : $text );
- foreach($split as $line){
- $tt = trim($line);
- if( $tt )
+ function splitAndAdd( &$extracts, &$count, $text ) {
+ $split = explode( "\n", $this->mCleanWikitext ? $this->removeWiki( $text ) : $text );
+ foreach ( $split as $line ) {
+ $tt = trim( $line );
+ if ( $tt )
$extracts[$count++] = $tt;
}
}
-
+
/**
* Do manual case conversion for non-ascii chars
*
* @param $matches Array
*/
- function caseCallback($matches){
+ function caseCallback( $matches ) {
global $wgContLang;
- if( strlen($matches[0]) > 1 ){
- return '['.$wgContLang->lc($matches[0]).$wgContLang->uc($matches[0]).']';
+ if ( strlen( $matches[0] ) > 1 ) {
+ return '[' . $wgContLang->lc( $matches[0] ) . $wgContLang->uc( $matches[0] ) . ']';
} else
return $matches[0];
}
-
+
/**
* Extract part of the text from start to end, but by
* not chopping up words
@@ -1035,29 +1142,27 @@ class SearchHighlighter {
* @param $end Integer
* @param $posStart Integer: (out) actual start position
* @param $posEnd Integer: (out) actual end position
- * @return String
+ * @return String
*/
- function extract($text, $start, $end, &$posStart = null, &$posEnd = null ){
- global $wgContLang;
-
- if( $start != 0)
+ function extract( $text, $start, $end, &$posStart = null, &$posEnd = null ) {
+ if ( $start != 0 )
$start = $this->position( $text, $start, 1 );
- if( $end >= strlen($text) )
- $end = strlen($text);
+ if ( $end >= strlen( $text ) )
+ $end = strlen( $text );
else
$end = $this->position( $text, $end );
-
- if(!is_null($posStart))
+
+ if ( !is_null( $posStart ) )
$posStart = $start;
- if(!is_null($posEnd))
+ if ( !is_null( $posEnd ) )
$posEnd = $end;
-
- if($end > $start)
- return substr($text, $start, $end-$start);
+
+ if ( $end > $start )
+ return substr( $text, $start, $end - $start );
else
return '';
- }
-
+ }
+
/**
* Find a nonletter near a point (index) in the text
*
@@ -1066,117 +1171,117 @@ class SearchHighlighter {
* @param $offset Integer: offset to found index
* @return Integer: nearest nonletter index, or beginning of utf8 char if none
*/
- function position($text, $point, $offset=0 ){
+ function position( $text, $point, $offset = 0 ) {
$tolerance = 10;
$s = max( 0, $point - $tolerance );
- $l = min( strlen($text), $point + $tolerance ) - $s;
+ $l = min( strlen( $text ), $point + $tolerance ) - $s;
$m = array();
- if( preg_match('/[ ,.!?~!@#$%^&*\(\)+=\-\\\|\[\]"\'<>]/', substr($text,$s,$l), $m, PREG_OFFSET_CAPTURE ) ){
+ if ( preg_match( '/[ ,.!?~!@#$%^&*\(\)+=\-\\\|\[\]"\'<>]/', substr( $text, $s, $l ), $m, PREG_OFFSET_CAPTURE ) ) {
return $m[0][1] + $s + $offset;
- } else{
+ } else {
// check if point is on a valid first UTF8 char
$char = ord( $text[$point] );
- while( $char >= 0x80 && $char < 0xc0 ) {
+ while ( $char >= 0x80 && $char < 0xc0 ) {
// skip trailing bytes
$point++;
- if($point >= strlen($text))
- return strlen($text);
+ if ( $point >= strlen( $text ) )
+ return strlen( $text );
$char = ord( $text[$point] );
}
return $point;
-
+
}
}
-
+
/**
* Search extracts for a pattern, and return snippets
*
* @param $pattern String: regexp for matching lines
- * @param $extracts Array: extracts to search
+ * @param $extracts Array: extracts to search
* @param $linesleft Integer: number of extracts to make
* @param $contextchars Integer: length of snippet
* @param $out Array: map for highlighted snippets
* @param $offsets Array: map of starting points of snippets
* @protected
*/
- function process( $pattern, $extracts, &$linesleft, &$contextchars, &$out, &$offsets ){
- if($linesleft == 0)
+ function process( $pattern, $extracts, &$linesleft, &$contextchars, &$out, &$offsets ) {
+ if ( $linesleft == 0 )
return; // nothing to do
- foreach($extracts as $index => $line){
- if( array_key_exists($index,$out) )
+ foreach ( $extracts as $index => $line ) {
+ if ( array_key_exists( $index, $out ) )
continue; // this line already highlighted
-
+
$m = array();
if ( !preg_match( $pattern, $line, $m, PREG_OFFSET_CAPTURE ) )
continue;
-
+
$offset = $m[0][1];
- $len = strlen($m[0][0]);
- if($offset + $len < $contextchars)
- $begin = 0;
- elseif( $len > $contextchars)
+ $len = strlen( $m[0][0] );
+ if ( $offset + $len < $contextchars )
+ $begin = 0;
+ elseif ( $len > $contextchars )
$begin = $offset;
else
- $begin = $offset + intval( ($len - $contextchars) / 2 );
-
+ $begin = $offset + intval( ( $len - $contextchars ) / 2 );
+
$end = $begin + $contextchars;
-
+
$posBegin = $begin;
// basic snippet from this line
- $out[$index] = $this->extract($line,$begin,$end,$posBegin);
+ $out[$index] = $this->extract( $line, $begin, $end, $posBegin );
$offsets[$index] = $posBegin;
- $linesleft--;
- if($linesleft == 0)
+ $linesleft--;
+ if ( $linesleft == 0 )
return;
}
}
-
- /**
+
+ /**
* Basic wikitext removal
* @protected
*/
- function removeWiki($text) {
+ function removeWiki( $text ) {
$fname = __METHOD__;
wfProfileIn( $fname );
-
- //$text = preg_replace("/'{2,5}/", "", $text);
- //$text = preg_replace("/\[[a-z]+:\/\/[^ ]+ ([^]]+)\]/", "\\2", $text);
- //$text = preg_replace("/\[\[([^]|]+)\]\]/", "\\1", $text);
- //$text = preg_replace("/\[\[([^]]+\|)?([^|]]+)\]\]/", "\\2", $text);
- //$text = preg_replace("/\\{\\|(.*?)\\|\\}/", "", $text);
- //$text = preg_replace("/\\[\\[[A-Za-z_-]+:([^|]+?)\\]\\]/", "", $text);
- $text = preg_replace("/\\{\\{([^|]+?)\\}\\}/", "", $text);
- $text = preg_replace("/\\{\\{([^|]+\\|)(.*?)\\}\\}/", "\\2", $text);
- $text = preg_replace("/\\[\\[([^|]+?)\\]\\]/", "\\1", $text);
- $text = preg_replace_callback("/\\[\\[([^|]+\\|)(.*?)\\]\\]/", array($this,'linkReplace'), $text);
- //$text = preg_replace("/\\[\\[([^|]+\\|)(.*?)\\]\\]/", "\\2", $text);
- $text = preg_replace("/<\/?[^>]+>/", "", $text);
- $text = preg_replace("/'''''/", "", $text);
- $text = preg_replace("/('''|<\/?[iIuUbB]>)/", "", $text);
- $text = preg_replace("/''/", "", $text);
-
+
+ // $text = preg_replace("/'{2,5}/", "", $text);
+ // $text = preg_replace("/\[[a-z]+:\/\/[^ ]+ ([^]]+)\]/", "\\2", $text);
+ // $text = preg_replace("/\[\[([^]|]+)\]\]/", "\\1", $text);
+ // $text = preg_replace("/\[\[([^]]+\|)?([^|]]+)\]\]/", "\\2", $text);
+ // $text = preg_replace("/\\{\\|(.*?)\\|\\}/", "", $text);
+ // $text = preg_replace("/\\[\\[[A-Za-z_-]+:([^|]+?)\\]\\]/", "", $text);
+ $text = preg_replace( "/\\{\\{([^|]+?)\\}\\}/", "", $text );
+ $text = preg_replace( "/\\{\\{([^|]+\\|)(.*?)\\}\\}/", "\\2", $text );
+ $text = preg_replace( "/\\[\\[([^|]+?)\\]\\]/", "\\1", $text );
+ $text = preg_replace_callback( "/\\[\\[([^|]+\\|)(.*?)\\]\\]/", array( $this, 'linkReplace' ), $text );
+ // $text = preg_replace("/\\[\\[([^|]+\\|)(.*?)\\]\\]/", "\\2", $text);
+ $text = preg_replace( "/<\/?[^>]+>/", "", $text );
+ $text = preg_replace( "/'''''/", "", $text );
+ $text = preg_replace( "/('''|<\/?[iIuUbB]>)/", "", $text );
+ $text = preg_replace( "/''/", "", $text );
+
wfProfileOut( $fname );
return $text;
}
-
+
/**
* callback to replace [[target|caption]] kind of links, if
* the target is category or image, leave it
*
* @param $matches Array
*/
- function linkReplace($matches){
- $colon = strpos( $matches[1], ':' );
- if( $colon === false )
+ function linkReplace( $matches ) {
+ $colon = strpos( $matches[1], ':' );
+ if ( $colon === false )
return $matches[2]; // replace with caption
global $wgContLang;
$ns = substr( $matches[1], 0, $colon );
- $index = $wgContLang->getNsIndex($ns);
- if( $index !== false && ($index == NS_FILE || $index == NS_CATEGORY) )
- return $matches[0]; // return the whole thing
+ $index = $wgContLang->getNsIndex( $ns );
+ if ( $index !== false && ( $index == NS_FILE || $index == NS_CATEGORY ) )
+ return $matches[0]; // return the whole thing
else
return $matches[2];
-
+
}
/**
@@ -1190,11 +1295,11 @@ class SearchHighlighter {
* @return String
*/
public function highlightSimple( $text, $terms, $contextlines, $contextchars ) {
- global $wgLang, $wgContLang;
+ global $wgContLang;
$fname = __METHOD__;
$lines = explode( "\n", $text );
-
+
$terms = implode( '|', $terms );
$max = intval( $contextchars ) + 1;
$pat1 = "/(.*)($terms)(.{0,$max})/i";
@@ -1213,7 +1318,7 @@ class SearchHighlighter {
continue;
}
--$contextlines;
- $pre = $wgContLang->truncate( $m[1], -$contextchars );
+ $pre = $wgContLang->truncate( $m[1], - $contextchars );
if ( count( $m ) < 3 ) {
$post = '';
@@ -1231,10 +1336,10 @@ class SearchHighlighter {
$extract .= "${line}\n";
}
wfProfileOut( "$fname-extract" );
-
+
return $extract;
}
-
+
}
/**
diff --git a/includes/search/SearchIBM_DB2.php b/includes/search/SearchIBM_DB2.php
index d7587186..8cedd6f2 100644
--- a/includes/search/SearchIBM_DB2.php
+++ b/includes/search/SearchIBM_DB2.php
@@ -1,23 +1,25 @@
<?php
-# Copyright (C) 2004 Brion Vibber <brion@pobox.com>
-# http://www.mediawiki.org/
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# http://www.gnu.org/copyleft/gpl.html
-
/**
+ * IBM DB2 search engine
+ *
+ * Copyright © 2004 Brion Vibber <brion@pobox.com>
+ * http://www.mediawiki.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
* @file
* @ingroup Search
*/
@@ -27,8 +29,13 @@
* @ingroup Search
*/
class SearchIBM_DB2 extends SearchEngine {
+
+ /**
+ * Creates an instance of this class
+ * @param $db DatabaseIbm_db2: database object
+ */
function __construct($db) {
- $this->db = $db;
+ parent::__construct( $db );
}
/**
@@ -102,8 +109,8 @@ class SearchIBM_DB2 extends SearchEngine {
/**
* Construct the full SQL query to do the search.
* The guts shoulds be constructed in queryMain()
- * @param string $filteredTerm String
- * @param bool $fulltext Boolean
+ * @param $filteredTerm String
+ * @param $fulltext Boolean
*/
function getQuery( $filteredTerm, $fulltext ) {
return $this->queryLimit($this->queryMain($filteredTerm, $fulltext) . ' ' .
@@ -125,8 +132,8 @@ class SearchIBM_DB2 extends SearchEngine {
/**
* Get the base part of the search query.
*
- * @param string $filteredTerm String
- * @param bool $fulltext Boolean
+ * @param $filteredTerm String
+ * @param $fulltext Boolean
* @return String
*/
function queryMain( $filteredTerm, $fulltext ) {
diff --git a/includes/search/SearchMssql.php b/includes/search/SearchMssql.php
new file mode 100644
index 00000000..8b850fae
--- /dev/null
+++ b/includes/search/SearchMssql.php
@@ -0,0 +1,254 @@
+<?php
+/**
+ * Mssql search engine
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Search
+ */
+
+/**
+ * Search engine hook base class for Mssql (ConText).
+ * @ingroup Search
+ */
+class SearchMssql extends SearchEngine {
+
+ /**
+ * Creates an instance of this class
+ * @param $db DatabaseMssql: database object
+ */
+ function __construct( $db ) {
+ parent::__construct( $db );
+ }
+
+ /**
+ * Perform a full text search query and return a result set.
+ *
+ * @param $term String: raw search term
+ * @return MssqlSearchResultSet
+ * @access public
+ */
+ function searchText( $term ) {
+ $resultSet = $this->db->resultObject( $this->db->query( $this->getQuery( $this->filter( $term ), true ) ) );
+ return new MssqlSearchResultSet( $resultSet, $this->searchTerms );
+ }
+
+ /**
+ * Perform a title-only search query and return a result set.
+ *
+ * @param $term String: raw search term
+ * @return MssqlSearchResultSet
+ * @access public
+ */
+ function searchTitle( $term ) {
+ $resultSet = $this->db->resultObject( $this->db->query( $this->getQuery( $this->filter( $term ), false ) ) );
+ return new MssqlSearchResultSet( $resultSet, $this->searchTerms );
+ }
+
+
+ /**
+ * Return a partial WHERE clause to exclude redirects, if so set
+ *
+ * @return String
+ * @private
+ */
+ function queryRedirect() {
+ if ( $this->showRedirects ) {
+ return '';
+ } else {
+ return 'AND page_is_redirect=0';
+ }
+ }
+
+ /**
+ * Return a partial WHERE clause to limit the search to the given namespaces
+ *
+ * @return String
+ * @private
+ */
+ function queryNamespaces() {
+ $namespaces = implode( ',', $this->namespaces );
+ if ( $namespaces == '' ) {
+ $namespaces = '0';
+ }
+ return 'AND page_namespace IN (' . $namespaces . ')';
+ }
+
+ /**
+ * Return a LIMIT clause to limit results on the query.
+ *
+ * @return String
+ * @private
+ */
+ function queryLimit( $sql ) {
+ return $this->db->limitResult( $sql, $this->limit, $this->offset );
+ }
+
+ /**
+ * Does not do anything for generic search engine
+ * subclasses may define this though
+ *
+ * @return String
+ * @private
+ */
+ function queryRanking( $filteredTerm, $fulltext ) {
+ return ' ORDER BY ftindex.[RANK] DESC'; // return ' ORDER BY score(1)';
+ }
+
+ /**
+ * Construct the full SQL query to do the search.
+ * The guts shoulds be constructed in queryMain()
+ *
+ * @param $filteredTerm String
+ * @param $fulltext Boolean
+ * @private
+ */
+ function getQuery( $filteredTerm, $fulltext ) {
+ return $this->queryLimit( $this->queryMain( $filteredTerm, $fulltext ) . ' ' .
+ $this->queryRedirect() . ' ' .
+ $this->queryNamespaces() . ' ' .
+ $this->queryRanking( $filteredTerm, $fulltext ) . ' ' );
+ }
+
+
+ /**
+ * Picks which field to index on, depending on what type of query.
+ *
+ * @param $fulltext Boolean
+ * @return string
+ */
+ function getIndexField( $fulltext ) {
+ return $fulltext ? 'si_text' : 'si_title';
+ }
+
+ /**
+ * Get the base part of the search query.
+ *
+ * @param $filteredTerm String
+ * @param $fulltext Boolean
+ * @return String
+ * @private
+ */
+ function queryMain( $filteredTerm, $fulltext ) {
+ $match = $this->parseQuery( $filteredTerm, $fulltext );
+ $page = $this->db->tableName( 'page' );
+ $searchindex = $this->db->tableName( 'searchindex' );
+
+ return 'SELECT page_id, page_namespace, page_title, ftindex.[RANK]' .
+ "FROM $page,FREETEXTTABLE($searchindex , $match, LANGUAGE 'English') as ftindex " .
+ 'WHERE page_id=ftindex.[KEY] ';
+ }
+
+ /** @todo document */
+ function parseQuery( $filteredText, $fulltext ) {
+ global $wgContLang;
+ $lc = SearchEngine::legalSearchChars();
+ $this->searchTerms = array();
+
+ # FIXME: This doesn't handle parenthetical expressions.
+ $m = array();
+ $q = array();
+
+ if ( preg_match_all( '/([-+<>~]?)(([' . $lc . ']+)(\*?)|"[^"]*")/',
+ $filteredText, $m, PREG_SET_ORDER ) ) {
+ foreach ( $m as $terms ) {
+ $q[] = $terms[1] . $wgContLang->normalizeForSearch( $terms[2] );
+
+ if ( !empty( $terms[3] ) ) {
+ $regexp = preg_quote( $terms[3], '/' );
+ if ( $terms[4] )
+ $regexp .= "[0-9A-Za-z_]+";
+ } else {
+ $regexp = preg_quote( str_replace( '"', '', $terms[2] ), '/' );
+ }
+ $this->searchTerms[] = $regexp;
+ }
+ }
+
+ $searchon = $this->db->strencode( join( ',', $q ) );
+ $field = $this->getIndexField( $fulltext );
+ return "$field, '$searchon'";
+ }
+
+ /**
+ * Create or update the search index record for the given page.
+ * Title and text should be pre-processed.
+ *
+ * @param $id Integer
+ * @param $title String
+ * @param $text String
+ */
+ function update( $id, $title, $text ) {
+ // We store the column data as UTF-8 byte order marked binary stream
+ // because we are invoking the plain text IFilter on it so that, and we want it
+ // to properly decode the stream as UTF-8. SQL doesn't support UTF8 as a data type
+ // but the indexer will correctly handle it by this method. Since all we are doing
+ // is passing this data to the indexer and never retrieving it via PHP, this will save space
+ $table = $this->db->tableName( 'searchindex' );
+ $utf8bom = '0xEFBBBF';
+ $si_title = $utf8bom . bin2hex( $title );
+ $si_text = $utf8bom . bin2hex( $text );
+ $sql = "DELETE FROM $table WHERE si_page = $id;";
+ $sql .= "INSERT INTO $table (si_page, si_title, si_text) VALUES ($id, $si_title, $si_text)";
+ return $this->db->query( $sql, 'SearchMssql::update' );
+ }
+
+ /**
+ * Update a search index record's title only.
+ * Title should be pre-processed.
+ *
+ * @param $id Integer
+ * @param $title String
+ */
+ function updateTitle( $id, $title ) {
+ $table = $this->db->tableName( 'searchindex' );
+
+ // see update for why we are using the utf8bom
+ $utf8bom = '0xEFBBBF';
+ $si_title = $utf8bom . bin2hex( $title );
+ $sql = "DELETE FROM $table WHERE si_page = $id;";
+ $sql .= "INSERT INTO $table (si_page, si_title, si_text) VALUES ($id, $si_title, 0x00)";
+ return $this->db->query( $sql, 'SearchMssql::updateTitle' );
+ }
+}
+
+/**
+ * @ingroup Search
+ */
+class MssqlSearchResultSet extends SearchResultSet {
+ function __construct( $resultSet, $terms ) {
+ $this->mResultSet = $resultSet;
+ $this->mTerms = $terms;
+ }
+
+ function termMatches() {
+ return $this->mTerms;
+ }
+
+ function numRows() {
+ return $this->mResultSet->numRows();
+ }
+
+ function next() {
+ $row = $this->mResultSet->fetchObject();
+ if ( $row === false )
+ return false;
+ return new SearchResult( $row );
+ }
+}
+
+
diff --git a/includes/search/SearchMySQL.php b/includes/search/SearchMySQL.php
index 0c238be8..b92682ad 100644
--- a/includes/search/SearchMySQL.php
+++ b/includes/search/SearchMySQL.php
@@ -1,23 +1,25 @@
<?php
-# Copyright (C) 2004 Brion Vibber <brion@pobox.com>
-# http://www.mediawiki.org/
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# http://www.gnu.org/copyleft/gpl.html
-
/**
+ * MySQL search engine
+ *
+ * Copyright (C) 2004 Brion Vibber <brion@pobox.com>
+ * http://www.mediawiki.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
* @file
* @ingroup Search
*/
@@ -30,9 +32,12 @@ class SearchMySQL extends SearchEngine {
var $strictMatching = true;
static $mMinSearchLength;
- /** @todo document */
+ /**
+ * Creates an instance of this class
+ * @param $db DatabaseMysql: database object
+ */
function __construct( $db ) {
- $this->db = $db;
+ parent::__construct( $db );
}
/**
@@ -325,8 +330,7 @@ class SearchMySQL extends SearchEngine {
wfProfileIn( __METHOD__ );
- // Some languages such as Chinese require word segmentation
- $out = $wgContLang->wordSegmentation( $string );
+ $out = parent::normalizeText( $string );
// MySQL fulltext index doesn't grok utf-8, so we
// need to fold cases and convert to hex
@@ -401,7 +405,7 @@ class SearchMySQL extends SearchEngine {
* @ingroup Search
*/
class MySQLSearchResultSet extends SqlSearchResultSet {
- function MySQLSearchResultSet( $resultSet, $terms, $totalHits=null ) {
+ function __construct( $resultSet, $terms, $totalHits=null ) {
parent::__construct( $resultSet, $terms );
$this->mTotalHits = $totalHits;
}
@@ -409,4 +413,4 @@ class MySQLSearchResultSet extends SqlSearchResultSet {
function getTotalHits() {
return $this->mTotalHits;
}
-} \ No newline at end of file
+}
diff --git a/includes/search/SearchMySQL4.php b/includes/search/SearchMySQL4.php
deleted file mode 100644
index 3e2bb2d1..00000000
--- a/includes/search/SearchMySQL4.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-# Copyright (C) 2004 Brion Vibber <brion@pobox.com>
-# http://www.mediawiki.org/
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# http://www.gnu.org/copyleft/gpl.html
-
-/**
- * @file
- * @ingroup Search
- */
-
-/**
- * Search engine hook for MySQL 4+
- * This class retained for backwards compatibility...
- * The meat's been moved to SearchMySQL, since the 3.x variety is gone.
- * @ingroup Search
- * @deprecated
- */
-class SearchMySQL4 extends SearchMySQL {
- /* whee */
-}
diff --git a/includes/search/SearchOracle.php b/includes/search/SearchOracle.php
index e4c5deee..15c386ce 100644
--- a/includes/search/SearchOracle.php
+++ b/includes/search/SearchOracle.php
@@ -1,23 +1,25 @@
<?php
-# Copyright (C) 2004 Brion Vibber <brion@pobox.com>
-# http://www.mediawiki.org/
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# http://www.gnu.org/copyleft/gpl.html
-
/**
+ * Oracle search engine
+ *
+ * Copyright © 2004 Brion Vibber <brion@pobox.com>
+ * http://www.mediawiki.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
* @file
* @ingroup Search
*/
@@ -54,9 +56,13 @@ class SearchOracle extends SearchEngine {
'TRSYN' => 1,
'TT' => 1,
'WITHIN' => 1);
-
+
+ /**
+ * Creates an instance of this class
+ * @param $db DatabasePostgres: database object
+ */
function __construct($db) {
- $this->db = $db;
+ parent::__construct( $db );
}
/**
@@ -240,16 +246,24 @@ class SearchOracle extends SearchEngine {
'si_title' => $title,
'si_text' => $text
), 'SearchOracle::update' );
- $dbw->query("CALL ctx_ddl.sync_index('si_text_idx')");
- $dbw->query("CALL ctx_ddl.sync_index('si_title_idx')");
+
+ // Sync the index
+ // We need to specify the DB name (i.e. user/schema) here so that
+ // it can work from the installer, where
+ // ALTER SESSION SET CURRENT_SCHEMA = ...
+ // was used.
+ $dbw->query( "CALL ctx_ddl.sync_index(" .
+ $dbw->addQuotes( $dbw->getDBname() . '.' . trim( $dbw->tableName( 'si_text_idx' ), '"' ) ) . ")" );
+ $dbw->query( "CALL ctx_ddl.sync_index(" .
+ $dbw->addQuotes( $dbw->getDBname() . '.' . trim( $dbw->tableName( 'si_title_idx' ), '"' ) ) . ")" );
}
/**
* Update a search index record's title only.
* Title should be pre-processed.
*
- * @param int $id
- * @param string $title
+ * @param $id Integer
+ * @param $title String
*/
function updateTitle($id, $title) {
$dbw = wfGetDB(DB_MASTER);
diff --git a/includes/search/SearchPostgres.php b/includes/search/SearchPostgres.php
index 0006fa82..9d6d1539 100644
--- a/includes/search/SearchPostgres.php
+++ b/includes/search/SearchPostgres.php
@@ -1,23 +1,25 @@
<?php
-# Copyright (C) 2006-2007 Greg Sabino Mullane <greg@turnstep.com>
-# http://www.mediawiki.org/
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# http://www.gnu.org/copyleft/gpl.html
-
/**
+ * PostgreSQL search engine
+ *
+ * Copyright © 2006-2007 Greg Sabino Mullane <greg@turnstep.com>
+ * http://www.mediawiki.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
* @file
* @ingroup Search
*/
@@ -27,9 +29,12 @@
* @ingroup Search
*/
class SearchPostgres extends SearchEngine {
-
+ /**
+ * Creates an instance of this class
+ * @param $db DatabaseSqlite: database object
+ */
function __construct( $db ) {
- $this->db = $db;
+ parent::__construct( $db );
}
/**
@@ -129,24 +134,21 @@ class SearchPostgres extends SearchEngine {
/**
* Construct the full SQL query to do the search.
- * @param $filteredTerm String
+ * @param $term String
* @param $fulltext String
+ * @param $colname
*/
function searchQuery( $term, $fulltext, $colname ) {
- global $wgDBversion;
+ $postgresVersion = $this->db->getServerVersion();
- if ( !isset( $wgDBversion ) ) {
- $this->db->getServerVersion();
- $wgDBversion = $this->db->numeric_version;
- }
- $prefix = $wgDBversion < 8.3 ? "'default'," : '';
+ $prefix = $postgresVersion < 8.3 ? "'default'," : '';
# Get the SQL fragment for the given term
$searchstring = $this->parseQuery( $term );
## We need a separate query here so gin does not complain about empty searches
$SQL = "SELECT to_tsquery($prefix $searchstring)";
- $res = $this->db->doQuery($SQL);
+ $res = $this->db->query($SQL);
if (!$res) {
## TODO: Better output (example to catch: one 'two)
die ("Sorry, that was not a valid search string. Please go back and try again");
@@ -166,8 +168,8 @@ class SearchPostgres extends SearchEngine {
}
}
- $rankscore = $wgDBversion > 8.2 ? 5 : 1;
- $rank = $wgDBversion < 8.3 ? 'rank' : 'ts_rank';
+ $rankscore = $postgresVersion > 8.2 ? 5 : 1;
+ $rank = $postgresVersion < 8.3 ? 'rank' : 'ts_rank';
$query = "SELECT page_id, page_namespace, page_title, ".
"$rank($fulltext, to_tsquery($prefix $searchstring), $rankscore) AS score ".
"FROM page p, revision r, pagecontent c WHERE p.page_latest = r.rev_id " .
@@ -204,7 +206,7 @@ class SearchPostgres extends SearchEngine {
$SQL = "UPDATE pagecontent SET textvector = NULL WHERE old_id IN ".
"(SELECT rev_text_id FROM revision WHERE rev_page = " . intval( $pageid ) .
" ORDER BY rev_text_id DESC OFFSET 1)";
- $this->db->doQuery($SQL);
+ $this->db->query($SQL);
return true;
}
diff --git a/includes/search/SearchSqlite.php b/includes/search/SearchSqlite.php
index fb55efec..6accc31b 100644
--- a/includes/search/SearchSqlite.php
+++ b/includes/search/SearchSqlite.php
@@ -1,22 +1,22 @@
<?php
-# SQLite search backend, based upon SearchMysql
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# http://www.gnu.org/copyleft/gpl.html
-
/**
+ * SQLite search backend, based upon SearchMysql
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
* @file
* @ingroup Search
*/
@@ -26,15 +26,12 @@
* @ingroup Search
*/
class SearchSqlite extends SearchEngine {
- // Cached because SearchUpdate keeps recreating our class
- private static $fulltextSupported = null;
-
/**
* Creates an instance of this class
* @param $db DatabaseSqlite: database object
*/
function __construct( $db ) {
- $this->db = $db;
+ parent::__construct( $db );
}
/**
@@ -42,18 +39,11 @@ class SearchSqlite extends SearchEngine {
* @return Boolean
*/
function fulltextSearchSupported() {
- if ( self::$fulltextSupported === null ) {
- self::$fulltextSupported = $this->db->selectField(
- 'updatelog',
- 'ul_key',
- array( 'ul_key' => 'fts3' ),
- __METHOD__ ) !== false;
- }
- return self::$fulltextSupported;
+ return $this->db->checkForEnabledSearch();
}
- /**
- * Parse the user's query and transform it into an SQL fragment which will
+ /**
+ * Parse the user's query and transform it into an SQL fragment which will
* become part of a WHERE clause
*/
function parseQuery( $filteredText, $fulltext ) {
@@ -67,7 +57,7 @@ class SearchSqlite extends SearchEngine {
$filteredText, $m, PREG_SET_ORDER ) ) {
foreach( $m as $bits ) {
@list( /* all */, $modifier, $term, $nonQuoted, $wildcard ) = $bits;
-
+
if( $nonQuoted != '' ) {
$term = $nonQuoted;
$quote = '';
@@ -86,7 +76,7 @@ class SearchSqlite extends SearchEngine {
} else {
$variants = array( $term );
}
-
+
// The low-level search index does some processing on input to work
// around problems with minimum lengths and encoding in MySQL's
// fulltext engine.
@@ -94,12 +84,12 @@ class SearchSqlite extends SearchEngine {
$strippedVariants = array_map(
array( $wgContLang, 'normalizeForSearch' ),
$variants );
-
+
// Some languages such as Chinese force all variants to a canonical
// form when stripping to the low-level search index, so to be sure
// let's check our variants list for unique items after stripping.
$strippedVariants = array_unique( $strippedVariants );
-
+
$searchon .= $modifier;
if( count( $strippedVariants) > 1 )
$searchon .= '(';
@@ -114,7 +104,7 @@ class SearchSqlite extends SearchEngine {
}
if( count( $strippedVariants) > 1 )
$searchon .= ')';
-
+
// Match individual terms or quoted phrase in result highlighting...
// Note that variants will be introduced in a later stage for highlighting!
$regexp = $this->regexTerm( $term, $wildcard );
@@ -129,10 +119,10 @@ class SearchSqlite extends SearchEngine {
$field = $this->getIndexField( $fulltext );
return " $field MATCH '$searchon' ";
}
-
+
function regexTerm( $string, $wildcard ) {
global $wgContLang;
-
+
$regex = preg_quote( $string, '/' );
if( $wgContLang->hasWordBreaks() ) {
if( $wildcard ) {
@@ -172,7 +162,7 @@ class SearchSqlite extends SearchEngine {
function searchTitle( $term ) {
return $this->searchInternal( $term, false );
}
-
+
protected function searchInternal( $term, $fulltext ) {
global $wgCountTotalSearchHits, $wgContLang;
@@ -182,7 +172,7 @@ class SearchSqlite extends SearchEngine {
$filteredTerm = $this->filter( $wgContLang->lc( $term ) );
$resultSet = $this->db->query( $this->getQuery( $filteredTerm, $fulltext ) );
-
+
$total = null;
if( $wgCountTotalSearchHits ) {
$totalResult = $this->db->query( $this->getCountQuery( $filteredTerm, $fulltext ) );
@@ -192,7 +182,7 @@ class SearchSqlite extends SearchEngine {
}
$totalResult->free();
}
-
+
return new SqliteSearchResultSet( $resultSet, $this->searchTerms, $total );
}
@@ -226,7 +216,7 @@ class SearchSqlite extends SearchEngine {
/**
* Returns a query with limit for number of results set.
- * @param $sql String:
+ * @param $sql String:
* @return String
*/
function limitResult( $sql ) {
@@ -246,7 +236,7 @@ class SearchSqlite extends SearchEngine {
$this->queryNamespaces()
);
}
-
+
/**
* Picks which field to index on, depending on what type of query.
* @param $fulltext Boolean
@@ -300,7 +290,7 @@ class SearchSqlite extends SearchEngine {
$dbw = wfGetDB( DB_MASTER );
$dbw->delete( 'searchindex', array( 'rowid' => $id ), __METHOD__ );
-
+
$dbw->insert( 'searchindex',
array(
'rowid' => $id,
@@ -333,7 +323,7 @@ class SearchSqlite extends SearchEngine {
* @ingroup Search
*/
class SqliteSearchResultSet extends SqlSearchResultSet {
- function SqliteSearchResultSet( $resultSet, $terms, $totalHits=null ) {
+ function __construct( $resultSet, $terms, $totalHits=null ) {
parent::__construct( $resultSet, $terms );
$this->mTotalHits = $totalHits;
}
@@ -341,4 +331,4 @@ class SqliteSearchResultSet extends SqlSearchResultSet {
function getTotalHits() {
return $this->mTotalHits;
}
-} \ No newline at end of file
+}
diff --git a/includes/search/SearchUpdate.php b/includes/search/SearchUpdate.php
index e30c70e6..5262faa4 100644
--- a/includes/search/SearchUpdate.php
+++ b/includes/search/SearchUpdate.php
@@ -1,6 +1,16 @@
<?php
/**
+ * Search index updater
+ *
* See deferred.txt
+ *
+ * @file
+ * @ingroup Search
+ */
+
+/**
+ * Database independant search index updater
+ *
* @ingroup Search
*/
class SearchUpdate {
@@ -8,7 +18,7 @@ class SearchUpdate {
/* private */ var $mId = 0, $mNamespace, $mTitle, $mText;
/* private */ var $mTitleWords;
- function SearchUpdate( $id, $title, $text = false ) {
+ function __construct( $id, $title, $text = false ) {
$nt = Title::newFromText( $title );
if( $nt ) {
$this->mId = $id;
@@ -29,23 +39,23 @@ class SearchUpdate {
if( $wgDisableSearchUpdate || !$this->mId ) {
return false;
}
- $fname = 'SearchUpdate::doUpdate';
- wfProfileIn( $fname );
+
+ wfProfileIn( __METHOD__ );
$search = SearchEngine::create();
$lc = SearchEngine::legalSearchChars() . '&#;';
if( $this->mText === false ) {
$search->updateTitle($this->mId,
- Title::indexTitle( $this->mNamespace, $this->mTitle ));
- wfProfileOut( $fname );
+ $search->normalizeText( Title::indexTitle( $this->mNamespace, $this->mTitle ) ) );
+ wfProfileOut( __METHOD__ );
return;
}
# Language-specific strip/conversion
$text = $wgContLang->normalizeForSearch( $this->mText );
- wfProfileIn( $fname.'-regexps' );
+ wfProfileIn( __METHOD__ . '-regexps' );
$text = preg_replace( "/<\\/?\\s*[A-Za-z][^>]*?>/",
' ', $wgContLang->lc( " " . $text . " " ) ); # Strip HTML markup
$text = preg_replace( "/(^|\\n)==\\s*([^\\n]+)\\s*==(\\s)/sD",
@@ -92,20 +102,21 @@ class SearchUpdate {
# Strip wiki '' and '''
$text = preg_replace( "/''[']*/", " ", $text );
- wfProfileOut( "$fname-regexps" );
+ wfProfileOut( __METHOD__ . '-regexps' );
wfRunHooks( 'SearchUpdate', array( $this->mId, $this->mNamespace, $this->mTitle, &$text ) );
# Perform the actual update
- $search->update($this->mId, Title::indexTitle( $this->mNamespace, $this->mTitle ),
- $text);
+ $search->update($this->mId, $search->normalizeText( Title::indexTitle( $this->mNamespace, $this->mTitle ) ),
+ $search->normalizeText( $text ) );
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
}
}
/**
* Placeholder class
+ *
* @ingroup Search
*/
class SearchUpdateMyISAM extends SearchUpdate {