Dan Brown

Updated fulltext search with custom escaped query

Changed pdo quoted query to use custom escaping and added like searches when quoted terms are used.
...@@ -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), '/')));
......