From e03dc3b738287c4ed6fd9f5abf6ad317034b5f9b Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Wed, 13 Apr 2022 13:18:32 +0300 Subject: [PATCH] refactoring --- .../Select/Applier/Appliers/TextFilter.php | 6 +- .../Text/FullTextSearchDataComposer.php | 148 +++++++----------- .../Text/FullTextSearchDataComposerParams.php | 23 +-- application/Espo/Services/GlobalSearch.php | 2 +- .../Appliers/TextFilterApplierTest.php | 6 +- .../FullTextSearchDataComposerParamsTest.php | 26 +-- .../Text/FullTextSearchDataComposerTest.php | 12 +- 7 files changed, 81 insertions(+), 142 deletions(-) diff --git a/application/Espo/Core/Select/Applier/Appliers/TextFilter.php b/application/Espo/Core/Select/Applier/Appliers/TextFilter.php index 7d9b0979c6..737b975ce5 100644 --- a/application/Espo/Core/Select/Applier/Appliers/TextFilter.php +++ b/application/Espo/Core/Select/Applier/Appliers/TextFilter.php @@ -171,9 +171,9 @@ class TextFilter { $composer = $this->fullTextSearchDataComposerFactory->create($this->entityType); - $params = FullTextSearchDataComposerParams::fromArray([ - 'isAuxiliaryUse' => $isAuxiliaryUse, - ]); + $params = FullTextSearchDataComposerParams + ::create() + ->withIsAuxiliaryUse($isAuxiliaryUse); return $composer->compose($filter, $params); } diff --git a/application/Espo/Core/Select/Text/FullTextSearchDataComposer.php b/application/Espo/Core/Select/Text/FullTextSearchDataComposer.php index b84c60b6f9..3a2e983e0a 100644 --- a/application/Espo/Core/Select/Text/FullTextSearchDataComposer.php +++ b/application/Espo/Core/Select/Text/FullTextSearchDataComposer.php @@ -36,8 +36,6 @@ use Espo\ORM\Query\Part\Expression; class FullTextSearchDataComposer { - private const MIN_LENGTH = 4; - private string $entityType; private Config $config; @@ -60,44 +58,15 @@ class FullTextSearchDataComposer return null; } - $isAuxiliaryUse = $params->isAuxiliaryUse(); + $columnList = $this->metadataProvider->getFullTextSearchColumnList($this->entityType) ?? []; - $fieldList = $this->getTextFilterFieldList(); - - if ($isAuxiliaryUse) { - $filter = str_replace('%', '', $filter); - } - - $fullTextSearchColumnList = $this->metadataProvider->getFullTextSearchColumnList($this->entityType); - - $useFullTextSearch = false; - - if ( - $this->metadataProvider->hasFullTextSearch($this->entityType) && - !empty($fullTextSearchColumnList) - ) { - $fullTextSearchMinLength = $this->config->get('fullTextSearchMinLength') ?? self::MIN_LENGTH; - - if (!$fullTextSearchMinLength) { - $fullTextSearchMinLength = 0; - } - - /*$filterWoWildcards = str_replace('*', '', $filter); - - if (mb_strlen($filterWoWildcards) >= $fullTextSearchMinLength) { - $useFullTextSearch = true; - }*/ - - $useFullTextSearch = true; - } - - $fullTextSearchFieldList = []; - - if (!$useFullTextSearch) { + if (!count($columnList)) { return null; } - foreach ($fieldList as $field) { + $fieldList = []; + + foreach ($this->getTextFilterFieldList() as $field) { if (strpos($field, '.') !== false) { continue; } @@ -110,85 +79,88 @@ class FullTextSearchDataComposer continue; } - $fullTextSearchFieldList[] = $field; + $fieldList[] = $field; } - if (!count($fullTextSearchFieldList)) { - $useFullTextSearch = false; - } - - if (substr_count($filter, '\'') % 2 != 0) { - $useFullTextSearch = false; - } - - if (substr_count($filter, '"') % 2 != 0) { - $useFullTextSearch = false; - } - - if (empty($fullTextSearchColumnList)) { - $useFullTextSearch = false; - } - - if ($isAuxiliaryUse) { - if (mb_strpos($filter, '@') !== false) { - $useFullTextSearch = false; - } - } - - if (!$useFullTextSearch) { + if (!count($fieldList)) { return null; } - $filter = str_replace(['(', ')'], '', $filter); + if ( + substr_count($filter, '\'') % 2 !== 0 || + substr_count($filter, '"') % 2 !== 0 + ) { + return null; + } + + if ($params->isAuxiliaryUse() && mb_strpos($filter, '@') !== false) { + return null; + } + + $preparedFilter = $this->prepareFilter($filter); + + if ($params->isAuxiliaryUse()) { + $preparedFilter = str_replace('%', '', $preparedFilter); + } + + $function = 'MATCH_BOOLEAN'; if ( - $isAuxiliaryUse && mb_strpos($filter, '*') === false + $params->isAuxiliaryUse() && mb_strpos($preparedFilter, '*') === false || - mb_strpos($filter, ' ') === false && - mb_strpos($filter, '+') === false && - mb_strpos($filter, '-') === false && - mb_strpos($filter, '*') === false + mb_strpos($preparedFilter, ' ') === false && + mb_strpos($preparedFilter, '+') === false && + mb_strpos($preparedFilter, '-') === false && + mb_strpos($preparedFilter, '*') === false ) { $function = 'MATCH_NATURAL_LANGUAGE'; } - else { - $function = 'MATCH_BOOLEAN'; - } - - $filter = str_replace('"*', '"', $filter); - $filter = str_replace('*"', '"', $filter); - - while (strpos($filter, '**')) { - $filter = str_replace('**', '*', $filter); - - $filter = trim($filter); - } - - while (mb_substr($filter, -2) === ' *') { - $filter = mb_substr($filter, 0, mb_strlen($filter) - 2); - - $filter = trim($filter); - } $argumentList = array_merge( array_map( function ($item) { return Expression::column($item); }, - $fullTextSearchColumnList ?? [] + $columnList ), - [$filter] + [$preparedFilter] ); $expression = ExpressionUtil::composeFunction($function, ...$argumentList); - return new FullTextSearchData($expression, $fullTextSearchFieldList, $fullTextSearchColumnList ?? []); + return new FullTextSearchData( + $expression, + $fieldList, + $columnList + ); + } + + private function prepareFilter(string $filter): string + { + $filter = str_replace(['(', ')'], '', $filter); + + $filter = str_replace('"*', '"', $filter); + $filter = str_replace('*"', '"', $filter); + + while (strpos($filter, '**')) { + $filter = trim( + str_replace('**', '*', $filter) + ); + } + + while (mb_substr($filter, -2) === ' *') { + $filter = trim( + mb_substr($filter, 0, mb_strlen($filter) - 2) + ); + } + + return $filter; } /** * @return string[] */ - protected function getTextFilterFieldList(): array + private function getTextFilterFieldList(): array { return $this->metadataProvider->getTextFilterAttributeList($this->entityType) ?? ['name']; } diff --git a/application/Espo/Core/Select/Text/FullTextSearchDataComposerParams.php b/application/Espo/Core/Select/Text/FullTextSearchDataComposerParams.php index c3e0e52db9..c40fb5b4df 100644 --- a/application/Espo/Core/Select/Text/FullTextSearchDataComposerParams.php +++ b/application/Espo/Core/Select/Text/FullTextSearchDataComposerParams.php @@ -29,8 +29,6 @@ namespace Espo\Core\Select\Text; -use InvalidArgumentException; - class FullTextSearchDataComposerParams { private bool $isAuxiliaryUse = false; @@ -39,22 +37,17 @@ class FullTextSearchDataComposerParams { } - /** - * @param array $params - */ - public static function fromArray(array $params): self + public static function create(): self { - $object = new self(); + return new self(); + } - $object->isAuxiliaryUse = $params['isAuxiliaryUse'] ?? false; + public function withIsAuxiliaryUse(bool $isAuxiliaryUse = true): self + { + $obj = clone $this; + $obj->isAuxiliaryUse = $isAuxiliaryUse; - foreach ($params as $key => $value) { - if (!property_exists($object, $key)) { - throw new InvalidArgumentException("Unknown parameter '{$key}'."); - } - } - - return $object; + return $obj; } public function isAuxiliaryUse(): bool diff --git a/application/Espo/Services/GlobalSearch.php b/application/Espo/Services/GlobalSearch.php index fa3dea1e86..04dd43aba1 100644 --- a/application/Espo/Services/GlobalSearch.php +++ b/application/Espo/Services/GlobalSearch.php @@ -181,7 +181,7 @@ class GlobalSearch implements $fullTextSearchData = $fullTextSearchDataComposer->compose( $filter, - FullTextSearchDataComposerParams::fromArray([]) + FullTextSearchDataComposerParams::create() ); $isPerson = $this->metadata->get([ diff --git a/tests/unit/Espo/Core/Select/Applier/Appliers/TextFilterApplierTest.php b/tests/unit/Espo/Core/Select/Applier/Appliers/TextFilterApplierTest.php index 41f54efc8c..75cb431225 100644 --- a/tests/unit/Espo/Core/Select/Applier/Appliers/TextFilterApplierTest.php +++ b/tests/unit/Espo/Core/Select/Applier/Appliers/TextFilterApplierTest.php @@ -233,9 +233,9 @@ class TextFilterApplierTest extends \PHPUnit\Framework\TestCase $fullTextSearchDataComposer = $this->createMock(FullTextSearchDataComposer::class); - $fullTextSearchDataComposerParams = FullTextSearchDataComposerParams::fromArray([ - 'isAuxiliaryUse' => $isAuxiliaryUse, - ]); + $fullTextSearchDataComposerParams = FullTextSearchDataComposerParams + ::create() + ->withIsAuxiliaryUse($isAuxiliaryUse); $this->fullTextSearchDataComposerFactory ->expects($this->once()) diff --git a/tests/unit/Espo/Core/Select/Text/FullTextSearchDataComposerParamsTest.php b/tests/unit/Espo/Core/Select/Text/FullTextSearchDataComposerParamsTest.php index ad78e6b24b..c2748853f0 100644 --- a/tests/unit/Espo/Core/Select/Text/FullTextSearchDataComposerParamsTest.php +++ b/tests/unit/Espo/Core/Select/Text/FullTextSearchDataComposerParamsTest.php @@ -33,40 +33,20 @@ use Espo\Core\{ Select\Text\FullTextSearchDataComposerParams, }; -use InvalidArgumentException; - class FullTextSearchDataComposerParamsTest extends \PHPUnit\Framework\TestCase { - protected function setUp() : void - { - } - public function testFromArray() { - $item = FullTextSearchDataComposerParams::fromArray([ - 'isAuxiliaryUse' => true, - ]); + $item = FullTextSearchDataComposerParams::create()->withIsAuxiliaryUse(true); $this->assertTrue($item->isAuxiliaryUse()); - $item = FullTextSearchDataComposerParams::fromArray([ - 'isAuxiliaryUse' => false, - ]); + $item = FullTextSearchDataComposerParams::create()->withIsAuxiliaryUse(false); $this->assertFalse($item->isAuxiliaryUse()); - $item = FullTextSearchDataComposerParams::fromArray([ - ]); + $item = FullTextSearchDataComposerParams::create(); $this->assertFalse($item->isAuxiliaryUse()); } - - public function testNonExistingParam() - { - $this->expectException(InvalidArgumentException::class); - - $params = FullTextSearchDataComposerParams::fromArray([ - 'bad' => 'd', - ]); - } } diff --git a/tests/unit/Espo/Core/Select/Text/FullTextSearchDataComposerTest.php b/tests/unit/Espo/Core/Select/Text/FullTextSearchDataComposerTest.php index bf778a7ba5..dbe3b77aed 100644 --- a/tests/unit/Espo/Core/Select/Text/FullTextSearchDataComposerTest.php +++ b/tests/unit/Espo/Core/Select/Text/FullTextSearchDataComposerTest.php @@ -114,9 +114,7 @@ class FullTextSearchDataComposerTest extends \PHPUnit\Framework\TestCase ['field1', 'field2', 'field3'] ); - $params = FullTextSearchDataComposerParams::fromArray([ - 'isAuxiliaryUse' => false, - ]); + $params = FullTextSearchDataComposerParams::create()->withIsAuxiliaryUse(false); $data = $this->fullTextSearchDataComposer->compose($filter, $params); @@ -147,9 +145,7 @@ class FullTextSearchDataComposerTest extends \PHPUnit\Framework\TestCase ) ); - $params = FullTextSearchDataComposerParams::fromArray([ - 'isAuxiliaryUse' => false, - ]); + $params = FullTextSearchDataComposerParams::create()->withIsAuxiliaryUse(false); $data = $this->fullTextSearchDataComposer->compose($filter, $params); @@ -172,9 +168,7 @@ class FullTextSearchDataComposerTest extends \PHPUnit\Framework\TestCase ) ); - $params = FullTextSearchDataComposerParams::fromArray([ - 'isAuxiliaryUse' => false, - ]); + $params = FullTextSearchDataComposerParams::create()->withIsAuxiliaryUse(false); $data = $this->fullTextSearchDataComposer->compose($filter, $params);