Update message initialiser to use Revision functions for backend-independence. No...
[lhc/web/wiklou.git] / includes / SearchEngine.php
1 <?php
2 /**
3 * Contain a class for special pages
4 * @package MediaWiki
5 */
6
7 /**
8 * @package MediaWiki
9 */
10 class SearchEngine {
11 var $limit = 10;
12 var $offset = 0;
13 var $searchTerms = array();
14 var $namespaces = array( 0 );
15 var $showRedirects = false;
16
17 /**
18 * Perform a full text search query and return a result set.
19 *
20 * @param string $term - Raw search term
21 * @param array $namespaces - List of namespaces to search
22 * @return ResultWrapper
23 * @access public
24 */
25 function searchText( $term ) {
26 return $this->db->resultObject( $this->db->query( $this->getQuery( $this->filter( $term ), true ) ) );
27 }
28
29 /**
30 * Perform a title-only search query and return a result set.
31 *
32 * @param string $term - Raw search term
33 * @param array $namespaces - List of namespaces to search
34 * @return ResultWrapper
35 * @access public
36 */
37 function searchTitle( $term ) {
38 return $this->db->resultObject( $this->db->query( $this->getQuery( $this->filter( $term ), false ) ) );
39 }
40
41 /**
42 * If an exact title match can be find, or a very slightly close match,
43 * return the title. If no match, returns NULL.
44 *
45 * @param string $term
46 * @return Title
47 * @access private
48 */
49 function getNearMatch( $term ) {
50 # Exact match? No need to look further.
51 $title = Title::newFromText( $term );
52 if ( $title->getNamespace() == NS_SPECIAL || 0 != $title->getArticleID() ) {
53 return $title;
54 }
55
56 # Now try all lower case (i.e. first letter capitalized)
57 #
58 $title = Title::newFromText( strtolower( $term ) );
59 if ( 0 != $title->getArticleID() ) {
60 return $title;
61 }
62
63 # Now try capitalized string
64 #
65 $title = Title::newFromText( ucwords( strtolower( $term ) ) );
66 if ( 0 != $title->getArticleID() ) {
67 return $title;
68 }
69
70 # Now try all upper case
71 #
72 $title = Title::newFromText( strtoupper( $term ) );
73 if ( 0 != $title->getArticleID() ) {
74 return $title;
75 }
76
77 # Entering an IP address goes to the contributions page
78 if ( preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $term ) ) {
79 $title = Title::makeTitle( NS_SPECIAL, "Contributions/" . $term );
80 return $title;
81 }
82
83 return NULL;
84 }
85
86 function legalSearchChars() {
87 return "A-Za-z_'0-9\\x80-\\xFF\\-";
88 }
89
90 /**
91 * Set the maximum number of results to return
92 * and how many to skip before returning the first.
93 *
94 * @param int $limit
95 * @param int $offset
96 * @access public
97 */
98 function setLimitOffset( $limit, $offset = 0 ) {
99 $this->limit = IntVal( $limit );
100 $this->offset = IntVal( $offset );
101 }
102
103 /**
104 * Set which namespaces the search should include.
105 * Give an array of namespace index numbers.
106 *
107 * @param array $namespaces
108 * @access public
109 */
110 function setNamespaces( $namespaces ) {
111 $this->namespaces = $namespaces;
112 }
113
114 /**
115 * Make a list of searchable namespaces and their canonical names.
116 * @return array
117 * @access public
118 */
119 function searchableNamespaces() {
120 global $wgContLang;
121 $arr = array();
122 foreach( $wgContLang->getNamespaces() as $ns => $name ) {
123 if( $ns >= NS_MAIN ) {
124 $arr[$ns] = $name;
125 }
126 }
127 return $arr;
128 }
129
130 /**
131 * Fetch an array of regular expression fragments for matching
132 * the search terms as parsed by this engine in a text extract.
133 *
134 * @return array
135 * @access public
136 */
137 function termMatches() {
138 return $this->searchTerms;
139 }
140
141 /**
142 * Return a 'cleaned up' search string
143 *
144 * @return string
145 * @access public
146 */
147 function filter( $text ) {
148 $lc = $this->legalSearchChars();
149 return trim( preg_replace( "/[^{$lc}]/", " ", $text ) );
150 }
151
152 /**
153 * Return a partial WHERE clause to exclude redirects, if so set
154 * @return string
155 * @access private
156 */
157 function queryRedirect() {
158 if( $this->showRedirects ) {
159 return 'AND cur_is_redirect=0';
160 } else {
161 return '';
162 }
163 }
164
165 /**
166 * Return a partial WHERE clause to limit the search to the given namespaces
167 * @return string
168 * @access private
169 */
170 function queryNamespaces() {
171 $namespaces = implode( ',', $this->namespaces );
172 if ($namespaces == '') {
173 $namespaces = '0';
174 }
175 return 'AND page_namespace IN (' . $namespaces . ')';
176 }
177
178 /**
179 * Return a LIMIT clause to limit results on the query.
180 * @return string
181 * @access private
182 */
183 function queryLimit() {
184 return $this->db->limitResult( $this->limit, $this->offset );
185 }
186
187 /**
188 * Does not do anything for generic search engine
189 * subclasses may define this though
190 * @return string
191 * @access private
192 */
193 function queryRanking($filteredTerm,$fulltext) {
194 return "";
195 }
196
197 /**
198 * Construct the full SQL query to do the search.
199 * The guts shoulds be constructed in queryMain()
200 * @param string $filteredTerm
201 * @param bool $fulltext
202 * @access private
203 */
204 function getQuery( $filteredTerm, $fulltext ) {
205 return $this->queryMain( $filteredTerm, $fulltext ) . ' ' .
206 $this->queryRedirect() . ' ' .
207 $this->queryNamespaces() . ' ' .
208 $this->queryRanking($filteredTerm, $fulltext) . ' ' .
209 $this->queryLimit();
210 }
211
212 /**
213 * Load up the appropriate search engine class for the currently
214 * active database backend, and return a configured instance.
215 *
216 * @return SearchEngine
217 * @access private
218 */
219 function create() {
220 global $wgDBtype, $wgDBmysql4, $wgSearchType;
221 if( $wgDBtype == 'mysql' ) {
222 if( $wgDBmysql4 ) {
223 $class = 'SearchMySQL4';
224 require_once( 'SearchMySQL4.php' );
225 } else {
226 $class = 'SearchMysql3';
227 require_once( 'SearchMySQL3.php' );
228 }
229 } else if ( $wgDBtype == 'PostgreSQL' ) {
230 $class = 'SearchTsearch2';
231 require_once( 'SearchTsearch2.php' );
232 } else {
233 $class = 'SearchEngineDummy';
234 }
235 $search = new $class( wfGetDB( DB_SLAVE ) );
236 $search->setLimitOffset(0,0);
237 return $search;
238 }
239
240
241 }
242
243 /**
244 * @package MediaWiki
245 */
246 class SearchEngineDummy {
247 function search( $term ) {
248 return null;
249 }
250 }
251