[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/includes/search/ -> SearchOracle.php (source)

   1  <?php
   2  /**
   3   * Oracle search engine
   4   *
   5   * Copyright © 2004 Brion Vibber <[email protected]>
   6   * https://www.mediawiki.org/
   7   *
   8   * This program is free software; you can redistribute it and/or modify
   9   * it under the terms of the GNU General Public License as published by
  10   * the Free Software Foundation; either version 2 of the License, or
  11   * (at your option) any later version.
  12   *
  13   * This program is distributed in the hope that it will be useful,
  14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16   * GNU General Public License for more details.
  17   *
  18   * You should have received a copy of the GNU General Public License along
  19   * with this program; if not, write to the Free Software Foundation, Inc.,
  20   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  21   * http://www.gnu.org/copyleft/gpl.html
  22   *
  23   * @file
  24   * @ingroup Search
  25   */
  26  
  27  /**
  28   * Search engine hook base class for Oracle (ConText).
  29   * @ingroup Search
  30   */
  31  class SearchOracle extends SearchDatabase {
  32      private $reservedWords = array(
  33          'ABOUT' => 1,
  34          'ACCUM' => 1,
  35          'AND' => 1,
  36          'BT' => 1,
  37          'BTG' => 1,
  38          'BTI' => 1,
  39          'BTP' => 1,
  40          'FUZZY' => 1,
  41          'HASPATH' => 1,
  42          'INPATH' => 1,
  43          'MINUS' => 1,
  44          'NEAR' => 1,
  45          'NOT' => 1,
  46          'NT' => 1,
  47          'NTG' => 1,
  48          'NTI' => 1,
  49          'NTP' => 1,
  50          'OR' => 1,
  51          'PT' => 1,
  52          'RT' => 1,
  53          'SQE' => 1,
  54          'SYN' => 1,
  55          'TR' => 1,
  56          'TRSYN' => 1,
  57          'TT' => 1,
  58          'WITHIN' => 1,
  59      );
  60  
  61      /**
  62       * Perform a full text search query and return a result set.
  63       *
  64       * @param string $term Raw search term
  65       * @return SqlSearchResultSet
  66       */
  67  	function searchText( $term ) {
  68          if ( $term == '' ) {
  69              return new SqlSearchResultSet( false, '' );
  70          }
  71  
  72          $resultSet = $this->db->query( $this->getQuery( $this->filter( $term ), true ) );
  73          return new SqlSearchResultSet( $resultSet, $this->searchTerms );
  74      }
  75  
  76      /**
  77       * Perform a title-only search query and return a result set.
  78       *
  79       * @param string $term Raw search term
  80       * @return SqlSearchResultSet
  81       */
  82  	function searchTitle( $term ) {
  83          if ( $term == '' ) {
  84              return new SqlSearchResultSet( false, '' );
  85          }
  86  
  87          $resultSet = $this->db->query( $this->getQuery( $this->filter( $term ), false ) );
  88          return new SqlSearchResultSet( $resultSet, $this->searchTerms );
  89      }
  90  
  91      /**
  92       * Return a partial WHERE clause to limit the search to the given namespaces
  93       * @return string
  94       */
  95  	function queryNamespaces() {
  96          if ( is_null( $this->namespaces ) ) {
  97              return '';
  98          }
  99          if ( !count( $this->namespaces ) ) {
 100              $namespaces = '0';
 101          } else {
 102              $namespaces = $this->db->makeList( $this->namespaces );
 103          }
 104          return 'AND page_namespace IN (' . $namespaces . ')';
 105      }
 106  
 107      /**
 108       * Return a LIMIT clause to limit results on the query.
 109       *
 110       * @param string $sql
 111       *
 112       * @return string
 113       */
 114  	function queryLimit( $sql ) {
 115          return $this->db->limitResult( $sql, $this->limit, $this->offset );
 116      }
 117  
 118      /**
 119       * Does not do anything for generic search engine
 120       * subclasses may define this though
 121       *
 122       * @param string $filteredTerm
 123       * @param bool $fulltext
 124       * @return string
 125       */
 126  	function queryRanking( $filteredTerm, $fulltext ) {
 127          return ' ORDER BY score(1)';
 128      }
 129  
 130      /**
 131       * Construct the full SQL query to do the search.
 132       * The guts shoulds be constructed in queryMain()
 133       * @param string $filteredTerm
 134       * @param bool $fulltext
 135       * @return string
 136       */
 137  	function getQuery( $filteredTerm, $fulltext ) {
 138          return $this->queryLimit( $this->queryMain( $filteredTerm, $fulltext ) . ' ' .
 139              $this->queryNamespaces() . ' ' .
 140              $this->queryRanking( $filteredTerm, $fulltext ) . ' ' );
 141      }
 142  
 143      /**
 144       * Picks which field to index on, depending on what type of query.
 145       * @param bool $fulltext
 146       * @return string
 147       */
 148  	function getIndexField( $fulltext ) {
 149          return $fulltext ? 'si_text' : 'si_title';
 150      }
 151  
 152      /**
 153       * Get the base part of the search query.
 154       *
 155       * @param string $filteredTerm
 156       * @param bool $fulltext
 157       * @return string
 158       */
 159  	function queryMain( $filteredTerm, $fulltext ) {
 160          $match = $this->parseQuery( $filteredTerm, $fulltext );
 161          $page = $this->db->tableName( 'page' );
 162          $searchindex = $this->db->tableName( 'searchindex' );
 163          return 'SELECT page_id, page_namespace, page_title ' .
 164              "FROM $page,$searchindex " .
 165              'WHERE page_id=si_page AND ' . $match;
 166      }
 167  
 168      /**
 169       * Parse a user input search string, and return an SQL fragment to be used
 170       * as part of a WHERE clause
 171       * @param string $filteredText
 172       * @param bool $fulltext
 173       * @return string
 174       */
 175  	function parseQuery( $filteredText, $fulltext ) {
 176          global $wgContLang;
 177          $lc = $this->legalSearchChars();
 178          $this->searchTerms = array();
 179  
 180          # @todo FIXME: This doesn't handle parenthetical expressions.
 181          $m = array();
 182          $searchon = '';
 183          if ( preg_match_all( '/([-+<>~]?)(([' . $lc . ']+)(\*?)|"[^"]*")/',
 184                  $filteredText, $m, PREG_SET_ORDER ) ) {
 185              foreach ( $m as $terms ) {
 186                  // Search terms in all variant forms, only
 187                  // apply on wiki with LanguageConverter
 188                  $temp_terms = $wgContLang->autoConvertToAllVariants( $terms[2] );
 189                  if ( is_array( $temp_terms ) ) {
 190                      $temp_terms = array_unique( array_values( $temp_terms ) );
 191                      foreach ( $temp_terms as $t ) {
 192                          $searchon .= ( $terms[1] == '-' ? ' ~' : ' & ' ) . $this->escapeTerm( $t );
 193                      }
 194                  }
 195                  else {
 196                      $searchon .= ( $terms[1] == '-' ? ' ~' : ' & ' ) . $this->escapeTerm( $terms[2] );
 197                  }
 198                  if ( !empty( $terms[3] ) ) {
 199                      $regexp = preg_quote( $terms[3], '/' );
 200                      if ( $terms[4] ) {
 201                          $regexp .= "[0-9A-Za-z_]+";
 202                      }
 203                  } else {
 204                      $regexp = preg_quote( str_replace( '"', '', $terms[2] ), '/' );
 205                  }
 206                  $this->searchTerms[] = $regexp;
 207              }
 208          }
 209  
 210          $searchon = $this->db->addQuotes( ltrim( $searchon, ' &' ) );
 211          $field = $this->getIndexField( $fulltext );
 212          return " CONTAINS($field, $searchon, 1) > 0 ";
 213      }
 214  
 215  	private function escapeTerm( $t ) {
 216          global $wgContLang;
 217          $t = $wgContLang->normalizeForSearch( $t );
 218          $t = isset( $this->reservedWords[strtoupper( $t )] ) ? '{' . $t . '}' : $t;
 219          $t = preg_replace( '/^"(.*)"$/', '($1)', $t );
 220          $t = preg_replace( '/([-&|])/', '\\\\$1', $t );
 221          return $t;
 222      }
 223  
 224      /**
 225       * Create or update the search index record for the given page.
 226       * Title and text should be pre-processed.
 227       *
 228       * @param int $id
 229       * @param string $title
 230       * @param string $text
 231       */
 232  	function update( $id, $title, $text ) {
 233          $dbw = wfGetDB( DB_MASTER );
 234          $dbw->replace( 'searchindex',
 235              array( 'si_page' ),
 236              array(
 237                  'si_page' => $id,
 238                  'si_title' => $title,
 239                  'si_text' => $text
 240              ), 'SearchOracle::update' );
 241  
 242          // Sync the index
 243          // We need to specify the DB name (i.e. user/schema) here so that
 244          // it can work from the installer, where
 245          //     ALTER SESSION SET CURRENT_SCHEMA = ...
 246          // was used.
 247          $dbw->query( "CALL ctx_ddl.sync_index(" .
 248              $dbw->addQuotes( $dbw->getDBname() . '.' . $dbw->tableName( 'si_text_idx', 'raw' ) ) . ")" );
 249          $dbw->query( "CALL ctx_ddl.sync_index(" .
 250              $dbw->addQuotes( $dbw->getDBname() . '.' . $dbw->tableName( 'si_title_idx', 'raw' ) ) . ")" );
 251      }
 252  
 253      /**
 254       * Update a search index record's title only.
 255       * Title should be pre-processed.
 256       *
 257       * @param int $id
 258       * @param string $title
 259       */
 260  	function updateTitle( $id, $title ) {
 261          $dbw = wfGetDB( DB_MASTER );
 262  
 263          $dbw->update( 'searchindex',
 264              array( 'si_title' => $title ),
 265              array( 'si_page' => $id ),
 266              'SearchOracle::updateTitle',
 267              array() );
 268      }
 269  
 270  	public static function legalSearchChars() {
 271          return "\"" . parent::legalSearchChars();
 272      }
 273  }


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1