3 * FusionForge search engine
5 * Copyright 1999-2001, VA Linux Systems, Inc
6 * Copyright 2004, Guillaume Smet/Open Wide
8 * This file is part of FusionForge.
10 * FusionForge is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published
12 * by the Free Software Foundation; either version 2 of the License,
13 * or (at your option) any later version.
15 * FusionForge is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with FusionForge; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 class SearchQuery extends Error {
28 * the operator between each part of the query. Can be AND or OR.
30 * @var string $operator
34 * Number of rows per page
36 * @var int $rowsPerPage
40 * Number of rows we will display on the page
46 * Number of rows returned by the query
48 * @var int $rowsTotalCount
50 var $rowsTotalCount = 0;
60 * @var resource $result
64 * When search by id is enabled, the id to search for
68 var $searchId = false;
70 * if we want to search for all the words or if only one is sufficient
72 * @var boolean $isExact
76 * sections to search in
78 * @var array $sections
80 var $sections = SEARCH__ALL_SECTIONS;
89 * @param string $words words we are searching for
90 * @param int $offset offset
91 * @param boolean $isExact if we want to search for all the words or if only one is sufficient
92 * @param int $rowsPerPage number of rows per page
94 function SearchQuery($words, $offset, $isExact, $rowsPerPage = SEARCH__DEFAULT_ROWS_PER_PAGE) {
95 $this->cleanSearchWords($words);
97 $this->rowsPerPage = $rowsPerPage;
98 $this->offset = $offset;
99 $this->isExact = $isExact;
100 $this->operator = $this->getOperator();
104 * cleanSearchWords - clean the words we are searching for
106 * @param string $words words we are searching for
108 function cleanSearchWords($words) {
109 $words = trim($words);
111 $this->setError(_('Error: criteria not specified'));
114 if(is_numeric($words) && $this->implementsSearchById()) {
115 $this->searchId = (int) $words;
117 $words = htmlspecialchars($words);
118 $words = strtr($words, array('%' => '', '_' => ''));
119 $words = preg_replace("/[ \t]+/", ' ', $words);
120 if(strlen($words) < 3) {
121 $this->setError(_('Error: search query too short'));
124 $this->words = array();
125 $this->phrases = array();
128 foreach(explode(' ', quotemeta($words)) as $word) {
130 if(substr($word, -3) == "\\\\'") {
131 $word = substr($word, 0, -3);
133 $phrase .= ' '.$word;
134 $this->phrases[] = $phrase;
136 $phrase .= ' '.$word;
139 if(substr($word, 0, 3) == "\\\\'") {
140 $word = substr($word, 3);
142 if(substr($word, -3) == "\\\\'") {
143 // This is a special case where the phrase is just one word
144 $word = substr($word, 0, -3);
146 $this->phrases[] = $word;
151 $this->words[] = $word;
160 * executeQuery - execute the SQL query to get the results
162 function executeQuery() {
164 if($this->searchId) {
165 $query = $this->getSearchByIdQuery();
167 $query = $this->getQuery();
171 db_query("select set_curcfg('default')");
173 $this->result = db_query(
175 $this->rowsPerPage + 1,
180 $this->rowsTotalCount = db_numrows($this->result);
181 $this->rowsCount = min($this->rowsPerPage, $this->rowsTotalCount);
185 * getQuery - returns the sql query built to get the search results
186 * This is an abstract method. It _MUST_ be implemented in children classes.
188 * @return string sql query to execute
190 function getQuery() {
195 * getIlikeCondition - build the ILIKE condition of the SQL query for a given field name
197 * @param string $fieldName name of the field in the ILIKE condition
198 * @return string the condition
200 function getIlikeCondition($fieldName) {
201 global $sys_database_type;
203 $wordArgs = array_merge($this->words, str_replace(' ', "\\\s+",$this->phrases));
204 if ( $sys_database_type == "mysql" ) {
205 return $fieldName." LIKE '%" . implode("%' ".$this->operator." ".$fieldName." ILIKE '%", $wordArgs) ."%'";
207 return $fieldName." ILIKE '%" . implode("%' ".$this->operator." ".$fieldName." ILIKE '%", $wordArgs) ."%'";
211 function getMatchCond($fieldName, $arr) {
215 $regexs = str_replace(' ', "\\\s+",$arr);
216 $result = $fieldName." ~* '" . implode("' ".$this->operator." ".$fieldName." ~* '", $regexs) ."'";
222 * getOperator - get the operator we have to use in ILIKE condition
224 * @return string AND if it is an exact search, OR otherwise
226 function getOperator() {
235 * implementsSearchById - check if the current object implements the search by id feature by having a getSearchByIdQuery method
237 * @return boolean true if our object implements search by id, false otherwise.
239 function implementsSearchById() {
240 return method_exists($this, 'getSearchByIdQuery');
244 * getResult - returns the result set
246 * @return resource result set
248 function & getResult() {
249 return $this->result;
253 * getRowsCount - returns number of rows for the current page
255 * @return int rows count for the current page
257 function getRowsCount() {
258 return $this->rowsCount;
262 * getRowsTotalCount - returns total number of rows
264 * @return int rows count
266 function getRowsTotalCount() {
267 return $this->rowsTotalCount;
271 * getOffset - returns the offset
275 function getOffset() {
276 return $this->offset;
280 * getRowsPerPage - returns number of rows per page
282 * @return int number of rows per page
284 function getRowsPerPage() {
285 return $this->rowsPerPage;
289 * getWords - returns the array containing words we are searching for
291 * @return array words we are searching for
293 function getWords() {
298 * setSections - set the sections list
300 * @param $sections mixed array of sections or SEARCH__ALL_SECTIONS
302 function setSections($sections) {
303 if(is_array($sections)) {
304 //make a comma separated string from the sections array
305 foreach($sections as $key => $section)
306 $sections[$key] = '\''.$section.'\'';
307 $this->sections = implode(', ', $sections);
309 $this->sections = $sections;
314 * getFormattedWords - get words formatted in order to be used in the FTI stored procedures
316 * @return string words we are searching for, separated by a pipe
318 function getFormattedWords() {
319 if ($this->isExact) {
320 $words = implode('&', $this->words);
322 $words = implode('|', $this->words);
329 // c-file-style: "bsd"