Updated fulltext search with custom escaped query
Changed pdo quoted query to use custom escaping and added like searches when quoted terms are used.
Showing
3 changed files
with
28 additions
and
9 deletions
| ... | @@ -87,8 +87,8 @@ abstract class Entity extends Model | ... | @@ -87,8 +87,8 @@ abstract class Entity extends Model |
| 87 | */ | 87 | */ |
| 88 | public function getShortName($length = 25) | 88 | public function getShortName($length = 25) |
| 89 | { | 89 | { |
| 90 | - if(strlen($this->name) <= $length) return $this->name; | 90 | + if (strlen($this->name) <= $length) return $this->name; |
| 91 | - return substr($this->name, 0, $length-3) . '...'; | 91 | + return substr($this->name, 0, $length - 3) . '...'; |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | /** | 94 | /** |
| ... | @@ -100,19 +100,34 @@ abstract class Entity extends Model | ... | @@ -100,19 +100,34 @@ abstract class Entity extends Model |
| 100 | */ | 100 | */ |
| 101 | public static function fullTextSearchQuery($fieldsToSearch, $terms, $wheres = []) | 101 | public static function fullTextSearchQuery($fieldsToSearch, $terms, $wheres = []) |
| 102 | { | 102 | { |
| 103 | + $exactTerms = []; | ||
| 103 | foreach ($terms as $key => $term) { | 104 | foreach ($terms as $key => $term) { |
| 104 | - $term = htmlentities($term); | 105 | + $term = htmlentities($term, ENT_QUOTES); |
| 106 | + $term = preg_replace('/[+\-><\(\)~*\"@]+/', ' ', $term); | ||
| 105 | if (preg_match('/\s/', $term)) { | 107 | if (preg_match('/\s/', $term)) { |
| 108 | + $exactTerms[] = '%' . $term . '%'; | ||
| 106 | $term = '"' . $term . '"'; | 109 | $term = '"' . $term . '"'; |
| 110 | + } else { | ||
| 111 | + $term = '' . $term . '*'; | ||
| 107 | } | 112 | } |
| 108 | - $terms[$key] = $term . '*'; | 113 | + if ($term !== '*') $terms[$key] = $term; |
| 109 | } | 114 | } |
| 110 | - $termString = "'" . implode(' ', $terms) . "'"; | 115 | + $termString = implode(' ', $terms); |
| 111 | $fields = implode(',', $fieldsToSearch); | 116 | $fields = implode(',', $fieldsToSearch); |
| 112 | - $termStringEscaped = \DB::connection()->getPdo()->quote($termString); | 117 | + $search = static::selectRaw('*, MATCH(name) AGAINST(? IN BOOLEAN MODE) AS title_relevance', [$termString]); |
| 113 | - $search = static::addSelect(\DB::raw('*, MATCH(name) AGAINST('.$termStringEscaped.' IN BOOLEAN MODE) AS title_relevance')); | ||
| 114 | $search = $search->whereRaw('MATCH(' . $fields . ') AGAINST(? IN BOOLEAN MODE)', [$termString]); | 118 | $search = $search->whereRaw('MATCH(' . $fields . ') AGAINST(? IN BOOLEAN MODE)', [$termString]); |
| 115 | 119 | ||
| 120 | + // Ensure at least one exact term matches if in search | ||
| 121 | + if (count($exactTerms) > 0) { | ||
| 122 | + $search = $search->where(function($query) use ($exactTerms, $fieldsToSearch) { | ||
| 123 | + foreach ($exactTerms as $exactTerm) { | ||
| 124 | + foreach ($fieldsToSearch as $field) { | ||
| 125 | + $query->orWhere($field, 'like', $exactTerm); | ||
| 126 | + } | ||
| 127 | + } | ||
| 128 | + }); | ||
| 129 | + } | ||
| 130 | + | ||
| 116 | // Add additional where terms | 131 | // Add additional where terms |
| 117 | foreach ($wheres as $whereTerm) { | 132 | foreach ($wheres as $whereTerm) { |
| 118 | $search->where($whereTerm[0], $whereTerm[1], $whereTerm[2]); | 133 | $search->where($whereTerm[0], $whereTerm[1], $whereTerm[2]); | ... | ... |
| ... | @@ -233,7 +233,9 @@ class BookRepo | ... | @@ -233,7 +233,9 @@ class BookRepo |
| 233 | } else { | 233 | } else { |
| 234 | $terms = []; | 234 | $terms = []; |
| 235 | } | 235 | } |
| 236 | - $terms = array_merge($terms, explode(' ', $term)); | 236 | + if (!empty($term)) { |
| 237 | + $terms = array_merge($terms, explode(' ', $term)); | ||
| 238 | + } | ||
| 237 | $books = $this->book->fullTextSearchQuery(['name', 'description'], $terms) | 239 | $books = $this->book->fullTextSearchQuery(['name', 'description'], $terms) |
| 238 | ->paginate($count)->appends($paginationAppends); | 240 | ->paginate($count)->appends($paginationAppends); |
| 239 | $words = join('|', explode(' ', preg_quote(trim($term), '/'))); | 241 | $words = join('|', explode(' ', preg_quote(trim($term), '/'))); | ... | ... |
| ... | @@ -138,7 +138,9 @@ class ChapterRepo | ... | @@ -138,7 +138,9 @@ class ChapterRepo |
| 138 | } else { | 138 | } else { |
| 139 | $terms = []; | 139 | $terms = []; |
| 140 | } | 140 | } |
| 141 | - $terms = array_merge($terms, explode(' ', $term)); | 141 | + if (!empty($term)) { |
| 142 | + $terms = array_merge($terms, explode(' ', $term)); | ||
| 143 | + } | ||
| 142 | $chapters = $this->chapter->fullTextSearchQuery(['name', 'description'], $terms, $whereTerms) | 144 | $chapters = $this->chapter->fullTextSearchQuery(['name', 'description'], $terms, $whereTerms) |
| 143 | ->paginate($count)->appends($paginationAppends); | 145 | ->paginate($count)->appends($paginationAppends); |
| 144 | $words = join('|', explode(' ', preg_quote(trim($term), '/'))); | 146 | $words = join('|', explode(' ', preg_quote(trim($term), '/'))); | ... | ... |
-
Please register or sign in to post a comment