3 * FusionForge search engine
5 * Copyright 1999-2001, VA Linux Systems, Inc
6 * Copyright 2004, Guillaume Smet/Open Wide
7 * Copyright 2009, Roland Mas
8 * Copyright 2010-2011, Franck Villaume - Capgemini
9 * Copyright (C) 2012 Alain Peyrat - Alcatel-Lucent
11 * This file is part of FusionForge. FusionForge is free software;
12 * you can redistribute it and/or modify it under the terms of the
13 * GNU General Public License as published by the Free Software
14 * Foundation; either version 2 of the Licence, or (at your option)
17 * FusionForge is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 class SearchQuery extends Error {
29 * the operator between each part of the query. Can be AND or OR.
31 * @var string $operator
35 * Number of rows per page
37 * @var int $rowsPerPage
41 * Number of rows we will display on the page
47 * Number of rows returned by the query
49 * @var int $rowsTotalCount
51 var $rowsTotalCount = 0;
61 * @var resource $result
65 * if we want to search for all the words or if only one is sufficient
67 * @var boolean $isExact
71 * sections to search in
73 * @var array $sections
75 var $sections = SEARCH__ALL_SECTIONS;
79 var $phrases = array();
81 // Something that's hopefully not going to end up in real data
82 var $field_separator = ' ioM0Thu6_fieldseparator_kaeph9Ee ';
87 * @param string $words words we are searching for
88 * @param int $offset offset
89 * @param boolean $isExact if we want to search for all the words or if only one is sufficient
90 * @param int $rowsPerPage number of rows per page
92 function __construct($words, $offset, $isExact, $rowsPerPage = SEARCH__DEFAULT_ROWS_PER_PAGE) {
93 $this->cleanSearchWords($words);
94 //We manual escap because every Query in Search escap parameters
95 $words = addslashes($words);
96 if (is_array ($this->words)){
97 $this->words = array_map ('addslashes',$this->words);
99 $this->words = array();
101 if (is_array ($this->phrases)){
102 $this->phrases = array_map ('addslashes',$this->phrases);
104 $this->phrases = array();
106 $this->rowsPerPage = $rowsPerPage;
107 $this->offset = $offset;
108 $this->isExact = $isExact;
109 $this->operator = $this->getOperator();
113 * cleanSearchWords - clean the words we are searching for
115 * @param string $words words we are searching for
117 function cleanSearchWords($words) {
118 $words = trim($words);
120 $this->setError(_('Error') . _(': ') . _('Please enter a term to search for'));
124 $words = preg_replace("/[ \t]+/", ' ', $words);
125 if(strlen($words) < 3) {
126 $this->setError(_('Error: search query too short'));
129 $words = htmlspecialchars($words);
130 $words = strtr($words, array('%' => '\%', '_' => '\_'));
133 foreach(explode(' ', quotemeta($words)) as $word) {
135 if(substr($word, -1) == "'") {
136 $word = substr($word, 0, -1);
138 $phrase .= ' '.$word;
139 $this->phrases[] = $phrase;
141 $phrase .= ' '.$word;
144 if(substr($word, 0, 1) == "'") {
145 $word = substr($word, 1);
147 if(substr($word, -1) == "'") {
148 // This is a special case where the phrase is just one word
149 $word = substr($word, 0, -1);
151 $this->words[] = $word;
156 $this->words[] = $word;
163 * executeQuery - execute the SQL query to get the results
165 function executeQuery() {
167 $this->result = db_query_qpa (
169 $this->rowsPerPage + 1,
173 $this->rowsTotalCount = db_numrows($this->result);
174 $this->rowsCount = min($this->rowsPerPage, $this->rowsTotalCount);
178 * getQuery - returns the query built to get the search results
179 * This is an abstract method. It _MUST_ be implemented in children classes.
181 * @return array query+params array
183 function getQuery() {
187 function addMatchCondition($qpa, $fieldName) {
189 if(!count($this->phrases)) {
190 $qpa = db_construct_qpa ($qpa, 'TRUE') ;
195 foreach ($this->phrases as $p) {
196 $regexs[] = strtolower (preg_replace ("/\s+/", "\s+", $p));
199 for ($i = 0; $i < count ($regexs); $i++) {
201 $qpa = db_construct_qpa ($qpa,
204 $qpa = db_construct_qpa ($qpa,
206 array ($regexs[$i])) ;
211 function addIlikeCondition($qpa, $fieldName) {
212 $wordArgs = array_map ('strtolower',
213 array_merge($this->words, $this->phrases));
215 for ($i = 0; $i < count ($wordArgs); $i++) {
217 $qpa = db_construct_qpa ($qpa,
220 $qpa = db_construct_qpa ($qpa,
221 'lower ('.$fieldName.') LIKE $1',
222 array ('%'.$wordArgs[$i].'%')) ;
228 * getOperator - get the operator we have to use in ILIKE condition
230 * @return string AND if it is an exact search, OR otherwise
232 function getOperator() {
241 * getResult - returns the result set
243 * @return resource result set
245 function & getResult() {
246 return $this->result;
250 * getRowsCount - returns number of rows for the current page
252 * @return int rows count for the current page
254 function getRowsCount() {
255 return $this->rowsCount;
259 * getRowsTotalCount - returns total number of rows
261 * @return int rows count
263 function getRowsTotalCount() {
264 return $this->rowsTotalCount;
268 * getOffset - returns the offset
272 function getOffset() {
273 return $this->offset;
277 * getRowsPerPage - returns number of rows per page
279 * @return int number of rows per page
281 function getRowsPerPage() {
282 return $this->rowsPerPage;
286 * getWords - returns the array containing words we are searching for
288 * @return array words we are searching for
290 function getWords() {
295 * getPhrases - returns the array containing phrases we are searching for
297 * @return array phrases we are searching for
299 function getPhrases() {
300 return $this->phrases;
304 * setSections - set the sections list
306 * @param $sections mixed array of sections or SEARCH__ALL_SECTIONS
308 function setSections($sections) {
309 if(is_array($sections)) {
310 $this->sections = array_values($sections) ;
312 $this->sections = $sections;
317 * getFTIwords - get words formatted in order to be used in the FTI stored procedures
319 * @return string words we are searching for, separated by
321 function getFTIwords() {
322 $bits = $this->words;
323 foreach ($this->phrases as $p) {
324 $bits[] = '('.implode ('&', explode (' ', $p)).')';
326 if ($this->isExact) {
327 $query = implode('&', $bits);
329 $query = implode('|', $bits);
337 // c-file-style: "bsd"