From 26cc003a1b6b8ea044d45ed3261da7a64163dfd1 Mon Sep 17 00:00:00 2001 From: Andrew Parnham Date: Mon, 5 Oct 2020 14:51:35 +0100 Subject: [PATCH 1/8] Initial pass at adding a full text search --- src/Filters/FullTextSearch.php | 98 +++++++++++++++++++ .../MySql/Filters/MySqlFullTextSearch.php | 62 ++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 src/Filters/FullTextSearch.php create mode 100644 src/Repositories/MySql/Filters/MySqlFullTextSearch.php diff --git a/src/Filters/FullTextSearch.php b/src/Filters/FullTextSearch.php new file mode 100644 index 0000000..8abeb15 --- /dev/null +++ b/src/Filters/FullTextSearch.php @@ -0,0 +1,98 @@ +indexColumns = $indexColumns; + $this->searchPhrase = $searchPhrase; + $this->mode = $mode; + } + + /** + * @inheritDoc + */ + public function doGetUniqueIdentifiersToFilter(Collection $list) + { + $ids = []; + + //We need to make sure our search value does not contain any diacritics + $searchValueCleaned = preg_replace('/&([a-z]{1,2})(acute|cedil|circ|grave|lig|orn|ring|slash|th|tilde|uml|caron);/i','$1', htmlentities($this->searchPhrase)); + foreach ($list as $item) { + $columnsToSearch = $this->indexColumns; + + foreach ($columnsToSearch as $column) { + if (preg_match("/$searchValueCleaned/i", $item[$column])) { + $ids[] = $item->UniqueIdentifier; + break; + } + } + } + + return $ids; + } + + /** + * @inheritDoc + */ + public function getSettingsArray() + { + $settings = parent::getSettingsArray(); + $settings["indexColumns"] = $this->indexColumns; + $settings["searchPhrase"] = $this->searchPhrase; + $settings["mode"] = $this->mode; + + return $settings; + } + + /** + * Builds a new instance of the FullTextSearch from the settings array + * + * @param $settings + * + * @return FullTextSearch + * + * @throws ImplementationException + */ + public static function fromSettingsArray($settings) + { + return new self($settings["indexColumns"], $settings["searchPhrase"], $settings["mode"]); + } +} diff --git a/src/Repositories/MySql/Filters/MySqlFullTextSearch.php b/src/Repositories/MySql/Filters/MySqlFullTextSearch.php new file mode 100644 index 0000000..8c0de09 --- /dev/null +++ b/src/Repositories/MySql/Filters/MySqlFullTextSearch.php @@ -0,0 +1,62 @@ +getSettingsArray(); + if (!isset($settings["indexColumns"]) || !isset($settings["searchPhrase"]) || !isset($settings["mode"])) { + throw new ImplementationException("Filter passed to doFilterWithRepository was \"" . get_class($originalFilter) . "\" expected " . \Unislim\WebApp\Shared\Filters\MySqlFullTextSearch::class); + } + + $implodedColumns = StringTools::implodeIgnoringBlanks(",", $settings["indexColumns"]); + if (self::canFilter($repository, $implodedColumns, $propertiesToAutoHydrate)) { + $searchPhrase = $settings["searchPhrase"]; + $paramName = uniqid() . str_replace(".", "", $implodedColumns); + $params[$paramName] = $searchPhrase; + + $originalFilter->filteredByRepository = true; + + return "MATCH (`{$implodedColumns}`) AGAINST (`{$searchPhrase}` IN `{$settings["mode"]}` MODE)"; + } + + parent::doFilterWithRepository($repository, $originalFilter, $params, $propertiesToAutoHydrate); + } + + /** + * @inheritDoc + */ + protected static function canFilter(Repository $repository, $columnName, &$propertiesToAutoHydrate) + { + $schema = $repository->getRepositorySchema(); + $columns = $schema->getColumns(); + + //We need to explode the column name as we will have passed an imploded list of columns that + //comprise the index + $providedColumns = preg_split('@/@', $columnName, NULL, PREG_SPLIT_NO_EMPTY); + foreach ($providedColumns as $column) { + if (!isset($column, $columns)) { + if (!self::canFilterTrait($repository, $column, $propertiesToAutoHydrate)) { + return false; + } + } + } + + return true; + } +} From afe91a7fa9b592a3b9309bb051e71dc8222ab71a Mon Sep 17 00:00:00 2001 From: Andrew Parnham Date: Mon, 5 Oct 2020 15:10:21 +0100 Subject: [PATCH 2/8] Change query --- src/Repositories/MySql/Filters/MySqlFullTextSearch.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Repositories/MySql/Filters/MySqlFullTextSearch.php b/src/Repositories/MySql/Filters/MySqlFullTextSearch.php index 8c0de09..f766e14 100644 --- a/src/Repositories/MySql/Filters/MySqlFullTextSearch.php +++ b/src/Repositories/MySql/Filters/MySqlFullTextSearch.php @@ -32,7 +32,7 @@ protected static function doFilterWithRepository(Repository $repository, Filter $originalFilter->filteredByRepository = true; - return "MATCH (`{$implodedColumns}`) AGAINST (`{$searchPhrase}` IN `{$settings["mode"]}` MODE)"; + return "MATCH ({$implodedColumns}) AGAINST ('{$searchPhrase}' IN {$settings["mode"]} MODE)"; } parent::doFilterWithRepository($repository, $originalFilter, $params, $propertiesToAutoHydrate); From 47659e3e605395c0f08626623b7bcc99e30b8c41 Mon Sep 17 00:00:00 2001 From: Andrew Cutbhert Date: Tue, 6 Oct 2020 12:37:13 +0100 Subject: [PATCH 3/8] Partial word fix --- src/Repositories/MySql/Filters/MySqlFullTextSearch.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Repositories/MySql/Filters/MySqlFullTextSearch.php b/src/Repositories/MySql/Filters/MySqlFullTextSearch.php index f766e14..9faf5cc 100644 --- a/src/Repositories/MySql/Filters/MySqlFullTextSearch.php +++ b/src/Repositories/MySql/Filters/MySqlFullTextSearch.php @@ -32,6 +32,14 @@ protected static function doFilterWithRepository(Repository $repository, Filter $originalFilter->filteredByRepository = true; + $words = preg_split("/\s+/", $searchPhrase); + $newWords = []; + foreach($words as $word){ + $newWords[] = $word."*"; + } + + $searchPhrase = implode(" ", $newWords); + return "MATCH ({$implodedColumns}) AGAINST ('{$searchPhrase}' IN {$settings["mode"]} MODE)"; } From 1c11ffc8d9f00bd262b2dbf9e4d3a133ef2329ab Mon Sep 17 00:00:00 2001 From: Andrew Cutbhert Date: Tue, 6 Oct 2020 12:56:22 +0100 Subject: [PATCH 4/8] Fix for hyphenation --- src/Repositories/MySql/Filters/MySqlFullTextSearch.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Repositories/MySql/Filters/MySqlFullTextSearch.php b/src/Repositories/MySql/Filters/MySqlFullTextSearch.php index 9faf5cc..c9f2708 100644 --- a/src/Repositories/MySql/Filters/MySqlFullTextSearch.php +++ b/src/Repositories/MySql/Filters/MySqlFullTextSearch.php @@ -32,7 +32,7 @@ protected static function doFilterWithRepository(Repository $repository, Filter $originalFilter->filteredByRepository = true; - $words = preg_split("/\s+/", $searchPhrase); + $words = preg_split("/\W+/", $searchPhrase); $newWords = []; foreach($words as $word){ $newWords[] = $word."*"; From 95de2757b1bccbd65643590908025003b002f29e Mon Sep 17 00:00:00 2001 From: Andrew Parnham Date: Tue, 6 Oct 2020 14:34:01 +0100 Subject: [PATCH 5/8] Use named params --- src/Repositories/MySql/Filters/MySqlFullTextSearch.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Repositories/MySql/Filters/MySqlFullTextSearch.php b/src/Repositories/MySql/Filters/MySqlFullTextSearch.php index c9f2708..e477f7d 100644 --- a/src/Repositories/MySql/Filters/MySqlFullTextSearch.php +++ b/src/Repositories/MySql/Filters/MySqlFullTextSearch.php @@ -28,7 +28,6 @@ protected static function doFilterWithRepository(Repository $repository, Filter if (self::canFilter($repository, $implodedColumns, $propertiesToAutoHydrate)) { $searchPhrase = $settings["searchPhrase"]; $paramName = uniqid() . str_replace(".", "", $implodedColumns); - $params[$paramName] = $searchPhrase; $originalFilter->filteredByRepository = true; @@ -40,7 +39,9 @@ protected static function doFilterWithRepository(Repository $repository, Filter $searchPhrase = implode(" ", $newWords); - return "MATCH ({$implodedColumns}) AGAINST ('{$searchPhrase}' IN {$settings["mode"]} MODE)"; + $params[$paramName] = $searchPhrase; + + return "MATCH ({$implodedColumns}) AGAINST ('{$paramName}' IN {$settings["mode"]} MODE)"; } parent::doFilterWithRepository($repository, $originalFilter, $params, $propertiesToAutoHydrate); From b0f820796af576a9bd3f2cfbe4af46349663c76c Mon Sep 17 00:00:00 2001 From: Andrew Parnham Date: Tue, 6 Oct 2020 14:36:56 +0100 Subject: [PATCH 6/8] Adding colon --- src/Repositories/MySql/Filters/MySqlFullTextSearch.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Repositories/MySql/Filters/MySqlFullTextSearch.php b/src/Repositories/MySql/Filters/MySqlFullTextSearch.php index e477f7d..47a574f 100644 --- a/src/Repositories/MySql/Filters/MySqlFullTextSearch.php +++ b/src/Repositories/MySql/Filters/MySqlFullTextSearch.php @@ -41,7 +41,7 @@ protected static function doFilterWithRepository(Repository $repository, Filter $params[$paramName] = $searchPhrase; - return "MATCH ({$implodedColumns}) AGAINST ('{$paramName}' IN {$settings["mode"]} MODE)"; + return "MATCH ({$implodedColumns}) AGAINST (':{$paramName}' IN {$settings["mode"]} MODE)"; } parent::doFilterWithRepository($repository, $originalFilter, $params, $propertiesToAutoHydrate); From 270a0c4cab0e7c99a7ca764543b254627c0d06e8 Mon Sep 17 00:00:00 2001 From: Andrew Parnham Date: Tue, 6 Oct 2020 14:57:30 +0100 Subject: [PATCH 7/8] Tweak to parameter --- src/Repositories/MySql/Filters/MySqlFullTextSearch.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Repositories/MySql/Filters/MySqlFullTextSearch.php b/src/Repositories/MySql/Filters/MySqlFullTextSearch.php index 47a574f..5993a91 100644 --- a/src/Repositories/MySql/Filters/MySqlFullTextSearch.php +++ b/src/Repositories/MySql/Filters/MySqlFullTextSearch.php @@ -41,7 +41,9 @@ protected static function doFilterWithRepository(Repository $repository, Filter $params[$paramName] = $searchPhrase; - return "MATCH ({$implodedColumns}) AGAINST (':{$paramName}' IN {$settings["mode"]} MODE)"; + $parameter = ":" . $paramName; + + return "MATCH ({$implodedColumns}) AGAINST ({$parameter} IN {$settings["mode"]} MODE)"; } parent::doFilterWithRepository($repository, $originalFilter, $params, $propertiesToAutoHydrate); From a65d8bb8c128cf8cba7ec62bb6d675fe9fff5290 Mon Sep 17 00:00:00 2001 From: Andrew Cutbhert Date: Tue, 6 Oct 2020 17:07:34 +0100 Subject: [PATCH 8/8] Fix for punctuation --- src/Repositories/MySql/Filters/MySqlFullTextSearch.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Repositories/MySql/Filters/MySqlFullTextSearch.php b/src/Repositories/MySql/Filters/MySqlFullTextSearch.php index 5993a91..e324700 100644 --- a/src/Repositories/MySql/Filters/MySqlFullTextSearch.php +++ b/src/Repositories/MySql/Filters/MySqlFullTextSearch.php @@ -34,7 +34,9 @@ protected static function doFilterWithRepository(Repository $repository, Filter $words = preg_split("/\W+/", $searchPhrase); $newWords = []; foreach($words as $word){ - $newWords[] = $word."*"; + if ($word) { + $newWords[] = $word."*"; + } } $searchPhrase = implode(" ", $newWords); @@ -44,7 +46,7 @@ protected static function doFilterWithRepository(Repository $repository, Filter $parameter = ":" . $paramName; return "MATCH ({$implodedColumns}) AGAINST ({$parameter} IN {$settings["mode"]} MODE)"; - } + } parent::doFilterWithRepository($repository, $originalFilter, $params, $propertiesToAutoHydrate); }