diff --git a/application/Espo/Core/Select/Text/Applier.php b/application/Espo/Core/Select/Text/Applier.php index fc58f3a062..25994dc706 100644 --- a/application/Espo/Core/Select/Text/Applier.php +++ b/application/Espo/Core/Select/Text/Applier.php @@ -60,7 +60,8 @@ class Applier private User $user, private MetadataProvider $metadataProvider, private FullTextSearchDataComposerFactory $fullTextSearchDataComposerFactory, - private FilterFactory $filterFactory + private FilterFactory $filterFactory, + private ConfigProvider $config ) {} /** @noinspection PhpUnusedParameterInspection */ @@ -90,6 +91,14 @@ class Applier } ); + if ( + $fullTextWhere && + !$forceFullTextSearch && + $this->toSkipFullText($filter) + ) { + $fullTextWhere = Expr::value(false); + } + $skipWildcards = false; if (mb_strpos($filter, '*') !== false) { @@ -167,4 +176,19 @@ class Applier return Expr::notEqual($expression, 0); } + + private function toSkipFullText(string $filter): bool + { + $min = $this->config->getFullTextSearchMinLength(); + + if ($min === null || strlen($filter) >= $min) { + return false; + } + + return + !str_contains($filter, '*') && + !str_contains($filter, '"') && + !str_contains($filter, '+') && + !str_contains($filter, '-'); + } } diff --git a/application/Espo/Core/Select/Text/ConfigProvider.php b/application/Espo/Core/Select/Text/ConfigProvider.php index e1df91bae3..9926e8e70f 100644 --- a/application/Espo/Core/Select/Text/ConfigProvider.php +++ b/application/Espo/Core/Select/Text/ConfigProvider.php @@ -38,6 +38,17 @@ class ConfigProvider public function __construct(private Config $config) {} + /** + * Full-text search min indexed word length. + * + * @internal Do not use. + * @since 8.3.0 + */ + public function getFullTextSearchMinLength(): ?int + { + return $this->config->get('fullTextSearchMinLength'); + } + public function getMinLengthForContentSearch(): int { return $this->config->get('textFilterContainsMinLength') ?? diff --git a/tests/unit/Espo/Core/Select/Applier/Appliers/TextFilterApplierTest.php b/tests/unit/Espo/Core/Select/Applier/Appliers/TextFilterApplierTest.php index 2ed8ac9ac2..1cac074780 100644 --- a/tests/unit/Espo/Core/Select/Applier/Appliers/TextFilterApplierTest.php +++ b/tests/unit/Espo/Core/Select/Applier/Appliers/TextFilterApplierTest.php @@ -29,30 +29,29 @@ namespace tests\unit\Espo\Core\Select\Applier\Appliers; -use Espo\Core\{ - Select\Text\Applier as TextFilterApplier, - Utils\Config, - Select\Text\MetadataProvider, - Select\Text\FilterParams, - Select\Text\FullTextSearch\Data as FullTextSearchData, - Select\Text\FullTextSearch\DefaultDataComposer as FullTextSearchDataComposer, - Select\Text\FullTextSearch\DataComposerFactory as FullTextSearchDataComposerFactory, - Select\Text\FullTextSearch\DataComposer\Params as FullTextSearchDataComposerParams, - Select\Text\FilterFactory, - Select\Text\DefaultFilter, - Select\Text\ConfigProvider, -}; +use Espo\Core\Select\Text\Applier as TextFilterApplier; +use Espo\Core\Select\Text\ConfigProvider; +use Espo\Core\Select\Text\DefaultFilter; +use Espo\Core\Select\Text\FilterFactory; +use Espo\Core\Select\Text\FilterParams; +use Espo\Core\Select\Text\FullTextSearch\Data as FullTextSearchData; +use Espo\Core\Select\Text\FullTextSearch\DataComposer\Params as FullTextSearchDataComposerParams; +use Espo\Core\Select\Text\FullTextSearch\DataComposerFactory as FullTextSearchDataComposerFactory; +use Espo\Core\Select\Text\FullTextSearch\DefaultDataComposer as FullTextSearchDataComposer; +use Espo\Core\Select\Text\MetadataProvider; +use Espo\Core\Utils\Config; -use Espo\{ - ORM\Query\SelectBuilder as QueryBuilder, - ORM\Query\Part\Where\OrGroup, - ORM\Query\Part\Expression as Expr, - ORM\Entity, - Entities\User, -}; +use Espo\Entities\User; +use Espo\ORM\Entity; +use Espo\ORM\Query\Part\Expression as Expr; +use Espo\ORM\Query\Part\Where\OrGroup; +use Espo\ORM\Query\SelectBuilder as QueryBuilder; +use PHPUnit\Framework\TestCase; -class TextFilterApplierTest extends \PHPUnit\Framework\TestCase +class TextFilterApplierTest extends TestCase { + private ?ConfigProvider $configProvider = null; + protected function setUp(): void { $this->user = $this->createMock(User::class); @@ -63,6 +62,8 @@ class TextFilterApplierTest extends \PHPUnit\Framework\TestCase $this->fullTextSearchDataComposerFactory = $this->createMock(FullTextSearchDataComposerFactory::class); $this->filterFactory = $this->createMock(FilterFactory::class); + $this->configProvider = $this->createMock(ConfigProvider::class); + $this->entityType = 'Test'; $this->applier = new TextFilterApplier( @@ -70,7 +71,8 @@ class TextFilterApplierTest extends \PHPUnit\Framework\TestCase $this->user, $this->metadataProvider, $this->fullTextSearchDataComposerFactory, - $this->filterFactory + $this->filterFactory, + $this->configProvider ); }