-
Notifications
You must be signed in to change notification settings - Fork 61
/
Copy pathAbstractAPI.php
268 lines (224 loc) · 6.54 KB
/
AbstractAPI.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
<?php
/**
* Abstract class that defines the methods search APIs shall implement
*
* @package ElkArte Forum
* @copyright ElkArte Forum contributors
* @license BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
*
* @version 2.0 dev
*/
namespace ElkArte\Search\API;
use ElkArte\Database\AbstractSearch;
use ElkArte\Database\QueryInterface;
use ElkArte\Helper\HttpReq;
use ElkArte\Helper\Util;
use ElkArte\Helper\ValuesContainer;
use ElkArte\Search\SearchArray;
use ElkArte\Search\SearchParams;
use ElkArte\Search\WeightFactors;
/**
* Abstract class that defines the methods any search API shall implement
* to properly work with ElkArte
*
* @package Search
*/
abstract class AbstractAPI
{
/** @var string This is the last version of ElkArte that this was tested on, to protect against API changes. */
public $version_compatible;
/** @var string This won't work with versions of ElkArte less than this. */
public $min_elk_version;
/** @var bool Standard search is supported by default. */
public $is_supported;
/** @var array Any word excluded from the search? */
protected $_excludedWords = [];
/** @var int Number of hits */
protected $_num_results = 0;
/** @var array What words are banned? */
protected $bannedWords = [];
/** @var int What is the minimum word length? */
protected $min_word_length;
/** @var array The weights to associate to various areas for relevancy */
protected $_weight_factors = [];
/** @var array Weighing factor each area, ie frequency, age, sticky, etc */
protected $_weight = [];
/** @var int The sum of the _weight_factors, normally but not always 100 */
protected $_weight_total = 0;
/** @var bool If we are creating a tmp db table */
protected $_createTemporary = true;
/** @var array Builds the array of words for use in the db query */
protected $_searchWords = [];
/** @var array Phrases not to be found in the search results (-"some phrase") */
protected $_excludedPhrases = [];
/** @var QueryInterface Database instance */
protected $_db;
/** @var HttpReq HttpReq instance */
protected $_req;
/** @var AbstractSearch Search db instance */
protected $_db_search;
/** @var array Words excluded from indexes */
protected $_excludedIndexWords = [];
/** @var array Words not to be found in the subject (-word) */
protected $_excludedSubjectWords = [];
/** @var SearchArray Holds the words and phrases to be searched on */
protected $_searchArray;
/** @var array What databases do we support? (In general.) */
protected $supported_databases = ['MySQL', 'PostgreSQL'];
/**
* __construct()
* @param ValuesContainer $config All the search configurations
* @param null|SearchParams $_searchParams Parameters of the search
*/
public function __construct(protected $config, protected $_searchParams)
{
$this->bannedWords = $this->config->banned_words;
$this->min_word_length = $this->_getMinWordLength();
$this->_db = database();
$this->_db_search = db_search();
$this->_req = HttpReq::instance();
}
/**
* What is a sensible minimum word length?
*
* @return int
*/
protected function _getMinWordLength()
{
return 3;
}
/**
* If the settings don't exist we can't continue.
*
* @return bool
*/
public function isValid()
{
// Always fall back to the standard search method.
return in_array($this->_db->title(), $this->supported_databases, true);
}
/**
* Adds the excluded words list
*
* @param string[] $words An array of words to exclude
*/
public function setExcludedWords($words)
{
$this->_excludedWords = $words;
}
/**
* Adds the excluded phrases list
*
* @param string[] $phrases An array of phrases to exclude
*/
public function setExcludedPhrases($phrases)
{
$this->_excludedPhrases = $phrases;
}
/**
* Sets the SearchArray... heck if I know what it is.
*
* @param SearchArray $searchArray
*/
public function setSearchArray(SearchArray $searchArray)
{
$this->_searchArray = $searchArray;
}
/**
* If we use a temporary table or not
*
* @param bool $use
*/
public function useTemporary($use = false)
{
$this->_createTemporary = $use;
}
/**
* Adds the weight factors
*
* @param WeightFactors $weights
*/
public function setWeightFactors(WeightFactors $weights)
{
$this->_weight_factors = $weights->getFactors();
$this->_weight = $weights->getWeight();
$this->_weight_total = $weights->getTotal();
}
/**
* Number of results?
*
* @return int
*/
public function getNumResults()
{
return $this->_num_results;
}
/**
* Callback function for usort used to sort the results.
*
* - The order of sorting is: large words, small words, large words that
* are excluded from the search, small words that are excluded.
*
* @param string $a Word A
* @param string $b Word B
* @return int An integer indicating how the words should be sorted (-1, 0 1)
*/
public function searchSort($a, $b)
{
$x = Util::strlen($a) - (in_array($a, $this->_excludedWords, true) ? 1000 : 0);
$y = Util::strlen($b) - (in_array($b, $this->_excludedWords, true) ? 1000 : 0);
return $y < $x ? 1 : ($y > $x ? -1 : 0);
}
/**
* Prepares the indexes
*
* @param string $word
* @param array $wordsSearch
* @param array $wordsExclude
* @param boolean $isExcluded
* @param string $excludedSubjectWords
*/
public function prepareIndexes($word, &$wordsSearch, &$wordsExclude, $isExcluded, $excludedSubjectWords)
{
// API specific implementations
}
/**
* Returns if the API uses the extended query syntax (aka sphinx etc)
*
* @return bool
*/
public function supportsExtended()
{
return false;
}
/**
* If the current API can use a word index.
*
* @return bool
*/
abstract public function useWordIndex();
/**
* Search for indexed words.
*
* @param array $words An array of words
* @param array $search_data An array of search data
*
* @return resource
*/
abstract public function indexedWordQuery($words, $search_data);
/**
* Escape words passed by the client
*
* @param string $phrase - The string to escape
* @param bool $no_regexp - If true or $modSettings['search_match_words']
* is empty, uses % at the beginning and end of the string,
* otherwise returns a regular expression
*
* @return string
*/
public function prepareWord($phrase, $no_regexp)
{
global $modSettings;
return empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($phrase, ['_' => '\\_', '%' => '\\%']) . '%' : '[[:<:]]' . addcslashes(preg_replace(['/([\[\]$.+*?|{}()])/'], ['[$1]'], $phrase), '\\\'') . '[[:>:]]';
}
}