Dan Brown

Improved numeric term search capabilities

Prevented a quoted term also being added to fuzzy searches
and also added check to see if the term is numeric to check if
an exact match is required.

Closes #200
...@@ -160,44 +160,49 @@ class Entity extends Ownable ...@@ -160,44 +160,49 @@ class Entity extends Ownable
160 public function fullTextSearchQuery($fieldsToSearch, $terms, $wheres = []) 160 public function fullTextSearchQuery($fieldsToSearch, $terms, $wheres = [])
161 { 161 {
162 $exactTerms = []; 162 $exactTerms = [];
163 - if (count($terms) === 0) { 163 + $fuzzyTerms = [];
164 - $search = $this; 164 + $search = static::newQuery();
165 - $orderBy = 'updated_at'; 165 +
166 - } else { 166 + foreach ($terms as $key => $term) {
167 - foreach ($terms as $key => $term) { 167 + $term = htmlentities($term, ENT_QUOTES);
168 - $term = htmlentities($term, ENT_QUOTES); 168 + $term = preg_replace('/[+\-><\(\)~*\"@]+/', ' ', $term);
169 - $term = preg_replace('/[+\-><\(\)~*\"@]+/', ' ', $term); 169 + if (preg_match('/&quot;.*?&quot;/', $term) || is_numeric($term)) {
170 - if (preg_match('/&quot;.*?&quot;/', $term)) { 170 + $term = str_replace('&quot;', '', $term);
171 - $term = str_replace('&quot;', '', $term); 171 + $exactTerms[] = '%' . $term . '%';
172 - $exactTerms[] = '%' . $term . '%'; 172 + } else {
173 - $term = '"' . $term . '"'; 173 + $term = '' . $term . '*';
174 - } else { 174 + if ($term !== '*') $fuzzyTerms[] = $term;
175 - $term = '' . $term . '*';
176 - }
177 - if ($term !== '*') $terms[$key] = $term;
178 } 175 }
179 - $termString = implode(' ', $terms); 176 + }
177 +
178 + $isFuzzy = count($exactTerms) === 0 || count($fuzzyTerms) > 0;
179 +
180 + // Perform fulltext search if relevant terms exist.
181 + if ($isFuzzy) {
182 + $termString = implode(' ', $fuzzyTerms);
180 $fields = implode(',', $fieldsToSearch); 183 $fields = implode(',', $fieldsToSearch);
181 - $search = static::selectRaw('*, MATCH(name) AGAINST(? IN BOOLEAN MODE) AS title_relevance', [$termString]); 184 + $search = $search->selectRaw('*, MATCH(name) AGAINST(? IN BOOLEAN MODE) AS title_relevance', [$termString]);
182 $search = $search->whereRaw('MATCH(' . $fields . ') AGAINST(? IN BOOLEAN MODE)', [$termString]); 185 $search = $search->whereRaw('MATCH(' . $fields . ') AGAINST(? IN BOOLEAN MODE)', [$termString]);
186 + }
183 187
184 - // Ensure at least one exact term matches if in search 188 + // Ensure at least one exact term matches if in search
185 - if (count($exactTerms) > 0) { 189 + if (count($exactTerms) > 0) {
186 - $search = $search->where(function ($query) use ($exactTerms, $fieldsToSearch) { 190 + $search = $search->where(function ($query) use ($exactTerms, $fieldsToSearch) {
187 - foreach ($exactTerms as $exactTerm) { 191 + foreach ($exactTerms as $exactTerm) {
188 - foreach ($fieldsToSearch as $field) { 192 + foreach ($fieldsToSearch as $field) {
189 - $query->orWhere($field, 'like', $exactTerm); 193 + $query->orWhere($field, 'like', $exactTerm);
190 - }
191 } 194 }
192 - }); 195 + }
193 - } 196 + });
194 - $orderBy = 'title_relevance'; 197 + }
195 - }; 198 +
199 + $orderBy = $isFuzzy ? 'title_relevance' : 'updated_at';
196 200
197 // Add additional where terms 201 // Add additional where terms
198 foreach ($wheres as $whereTerm) { 202 foreach ($wheres as $whereTerm) {
199 $search->where($whereTerm[0], $whereTerm[1], $whereTerm[2]); 203 $search->where($whereTerm[0], $whereTerm[1], $whereTerm[2]);
200 } 204 }
205 +
201 // Load in relations 206 // Load in relations
202 if ($this->isA('page')) { 207 if ($this->isA('page')) {
203 $search = $search->with('book', 'chapter', 'createdBy', 'updatedBy'); 208 $search = $search->with('book', 'chapter', 'createdBy', 'updatedBy');
......