diff --git a/src/Controller/PartListsController.php b/src/Controller/PartListsController.php index ce2eb2e9..87d48a4a 100644 --- a/src/Controller/PartListsController.php +++ b/src/Controller/PartListsController.php @@ -37,7 +37,6 @@ use App\Form\Filters\PartFilterType; use App\Services\Parts\PartsTableActionHandler; use App\Services\Trees\NodesListBuilder; use App\Settings\BehaviorSettings\SidebarSettings; -use App\Settings\BehaviorSettings\SearchSettings; use App\Settings\BehaviorSettings\TableSettings; use Doctrine\DBAL\Exception\DriverException; use Doctrine\ORM\EntityManagerInterface; @@ -60,7 +59,6 @@ class PartListsController extends AbstractController private readonly TranslatorInterface $translator, private readonly TableSettings $tableSettings, private readonly SidebarSettings $sidebarSettings, - private readonly SearchSettings $searchSettings, ) { } @@ -317,7 +315,7 @@ class PartListsController extends AbstractController private function searchRequestToFilter(Request $request): PartSearchFilter { - $filter = new PartSearchFilter($request->query->get('keyword', ''), $this->searchSettings); + $filter = new PartSearchFilter($request->query->get('keyword', '')); //As an unchecked checkbox is not set in the query, the default value for all bools have to be false (which is the default argument value)! $filter->setName($request->query->getBoolean('name')); @@ -336,6 +334,8 @@ class PartListsController extends AbstractController $filter->setRegex($request->query->getBoolean('regex')); + $filter->setExtensive($request->query->getBoolean('extensive')); + $filter->setWildcard($request->query->getBoolean('wildcard')); return $filter; } diff --git a/src/DataTables/Filters/PartSearchFilter.php b/src/DataTables/Filters/PartSearchFilter.php index 9d8ee394..777f9c8e 100644 --- a/src/DataTables/Filters/PartSearchFilter.php +++ b/src/DataTables/Filters/PartSearchFilter.php @@ -26,13 +26,18 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\Query\Parameter; use Doctrine\DBAL\ParameterType; -use App\Settings\BehaviorSettings\SearchSettings; class PartSearchFilter implements FilterInterface { /** @var boolean Whether to use regex for searching */ protected bool $regex = false; + + /** @var boolean Whether to use extensive matching for searching */ + protected bool $extensive = false; + + /** @var boolean Whether to use wildcards for searching */ + protected bool $wildcard = false; /** @var bool Use name field for searching */ protected bool $name = true; @@ -78,9 +83,7 @@ class PartSearchFilter implements FilterInterface public function __construct( /** @var string The string to query for */ - protected string $keyword, - /** @var SearchSettings The settings that control how the search operates */ - private readonly SearchSettings $searchSettings, + protected string $keyword ) { } @@ -138,11 +141,11 @@ class PartSearchFilter implements FilterInterface $search_dbId = $is_numeric && (bool)$this->dbId; $tokens = []; - if ($this->searchSettings->enableAdvancedSearch) { + if ($this->extensive) { //Transform keyword and trim excess spaces $this->keyword = trim(str_replace('+', ' ', $this->keyword)); - //Split keyword on spaces, but limit token count (default is 3) - $tokens = explode(' ', $this->keyword, $this->searchSettings->searchTokenLimit); + //Split keyword on spaces, but limit token count to 5 + $tokens = explode(' ', $this->keyword, 5); //Throw away array elements which are null or have zero length $tokens = array_filter($tokens, fn($x) => (strlen($x) > 0)); } @@ -176,7 +179,7 @@ class PartSearchFilter implements FilterInterface //Add a new expression and parameter set to the query for each token foreach ($tokens as $i => $token) { //Conditionally escape % and _ characters - if ($this->searchSettings->escapeSQLWildcards) + if (!$this->wildcard) $token = str_replace(['%', '_'], ['\%', '\_'], $token); //Convert the fields to search to a list of expressions @@ -240,6 +243,30 @@ class PartSearchFilter implements FilterInterface return $this; } + public function isExtensive(): bool + { + return $this->extensive; + } + + public function setExtensive(bool $extensive): PartSearchFilter + { + $this->extensive = $extensive; + return $this; + } + + + public function isWildcard(): bool + { + return $this->wildcard; + } + + public function setWildcard(bool $wildcard): PartSearchFilter + { + $this->wildcard = $wildcard; + return $this; + } + + public function isName(): bool { return $this->name; diff --git a/src/Settings/BehaviorSettings/BehaviorSettings.php b/src/Settings/BehaviorSettings/BehaviorSettings.php index 2740466f..ec849db3 100644 --- a/src/Settings/BehaviorSettings/BehaviorSettings.php +++ b/src/Settings/BehaviorSettings/BehaviorSettings.php @@ -44,7 +44,4 @@ class BehaviorSettings #[EmbeddedSettings] public ?KeybindingsSettings $keybindings = null; - - #[EmbeddedSettings] - public ?SearchSettings $search = null; } diff --git a/src/Settings/BehaviorSettings/SearchSettings.php b/src/Settings/BehaviorSettings/SearchSettings.php deleted file mode 100644 index dd67d51c..00000000 --- a/src/Settings/BehaviorSettings/SearchSettings.php +++ /dev/null @@ -1,74 +0,0 @@ -. - */ - -declare(strict_types=1); - - -namespace App\Settings\BehaviorSettings; - -use App\Settings\SettingsIcon; -use Jbtronics\SettingsBundle\Metadata\EnvVarMode; -use Jbtronics\SettingsBundle\Settings\Settings; -use Jbtronics\SettingsBundle\Settings\SettingsParameter; -use Symfony\Component\Translation\TranslatableMessage as TM; -use Symfony\Component\Validator\Constraints as Assert; - -#[Settings(name: "search", label: new TM("settings.behavior.search"))] -#[SettingsIcon('fa-magnifying-glass')] -class SearchSettings -{ - /** - * Whether to enable advanced search - * @var bool - */ - #[SettingsParameter( - label: new TM("settings.behavior.search.enable_advanced_search"), - description: new TM("settings.behavior.search.enable_advanced_search.help"), - envVar: "bool:ENABLE_ADVANCED_SEARCH", - envVarMode: EnvVarMode::OVERWRITE - )] - public bool $enableAdvancedSearch = false; - - /** - * Defines the maximum number of tokens the keyword can be split into - * @var int - */ - #[SettingsParameter( - label: new TM("settings.behavior.search.token_limit"), - description: new TM("settings.behavior.search.token_limit.help"), - envVar: "int:SEARCH_TOKEN_LIMIT", - envVarMode: EnvVarMode::OVERWRITE, - formOptions: ['attr' => ['min' => 2, 'max' => 5]], - )] - #[Assert\Range(min: 2, max: 5)] - public int $searchTokenLimit = 3; - - /** - * Whether to escape sql wildcards - * @var bool - */ - #[SettingsParameter( - label: new TM("settings.behavior.search.escape_sql_wildcards"), - description: new TM("settings.behavior.search.escape_sql_wildcards.help"), - envVar: "bool:ESCAPE_SQL_WILDCARDS", - envVarMode: EnvVarMode::OVERWRITE - )] - public bool $escapeSQLWildcards = true; -} diff --git a/templates/components/search.macro.html.twig b/templates/components/search.macro.html.twig index 90c01876..f826e1a4 100644 --- a/templates/components/search.macro.html.twig +++ b/templates/components/search.macro.html.twig @@ -1,4 +1,4 @@ -{% macro settings_drodown(show_label_instead_icon = true) %} +{% macro settings_dropdown(show_label_instead_icon = true) %} +
+ + +
+
+ + +
@@ -85,7 +93,7 @@ {# Show the options left in navbar #} {% if is_navbar %} - {{ _self.settings_drodown(is_navbar) }} + {{ _self.settings_dropdown(is_navbar) }} {% endif %}
{% endmacro %} diff --git a/templates/parts/lists/search_list.html.twig b/templates/parts/lists/search_list.html.twig index 49093c4c..56cf71cd 100644 --- a/templates/parts/lists/search_list.html.twig +++ b/templates/parts/lists/search_list.html.twig @@ -69,6 +69,14 @@
+
+ + +
+
+ + +
diff --git a/tests/DataTables/Filters/PartSearchFilterTest.php b/tests/DataTables/Filters/PartSearchFilterTest.php index 91d04c74..1a2738a2 100644 --- a/tests/DataTables/Filters/PartSearchFilterTest.php +++ b/tests/DataTables/Filters/PartSearchFilterTest.php @@ -22,7 +22,6 @@ namespace App\Tests\DataTables\Filters; use App\DataTables\Filters\PartSearchFilter; -use App\Settings\BehaviorSettings\SearchSettings; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\DBAL\ParameterType; use Doctrine\ORM\Query\Expr; @@ -34,22 +33,10 @@ use PHPUnit\Framework\TestCase; final class PartSearchFilterTest extends TestCase { - private function makeSearchSettings( - bool $enableAdvancedSearch = false, - int $searchTokenLimit = 3, - bool $escapeSQLWildcards = true, - ): SearchSettings { - $settings = $this->createMock(SearchSettings::class); - $settings->enableAdvancedSearch = $enableAdvancedSearch; - $settings->searchTokenLimit = $searchTokenLimit; - $settings->escapeSQLWildcards = $escapeSQLWildcards; - - return $settings; - } public function testApplyEnforcesNoResultsWhenKeywordEmpty(): void { - $filter = new PartSearchFilter('', $this->makeSearchSettings()); + $filter = new PartSearchFilter(''); $qb = $this->createMock(QueryBuilder::class); $qb->expects($this->once()) @@ -63,7 +50,7 @@ final class PartSearchFilterTest extends TestCase public function testApplyEnforcesNoResultsWhenNothingToSearchForAndNoExactIdSearch(): void { - $filter = (new PartSearchFilter('foo', $this->makeSearchSettings())) + $filter = (new PartSearchFilter('foo')) ->setName(false) ->setCategory(false) ->setDescription(false) @@ -90,7 +77,7 @@ final class PartSearchFilterTest extends TestCase public function testApplyUsesRegexExpressionAndRawParameterWhenRegexEnabled(): void { - $filter = (new PartSearchFilter('foo.*bar', $this->makeSearchSettings())) + $filter = (new PartSearchFilter('foo.*bar')) ->setRegex(true); $expr = $this->createStub(Expr::class); @@ -123,9 +110,7 @@ final class PartSearchFilterTest extends TestCase public function testApplyEscapesSqlWildcardsAndWrapsLikeParameterWhenRegexDisabled(): void { - $filter = (new PartSearchFilter('10%_off', $this->makeSearchSettings(escapeSQLWildcards: true))) - ->setRegex(false); - + $filter = (new PartSearchFilter('10%_off')); $expr = $this->createMock(Expr::class); $expr->method('orX')->willReturn(new Orx()); @@ -157,7 +142,7 @@ final class PartSearchFilterTest extends TestCase public function testApplyAddsExactIdExpressionWhenDbIdSearchEnabledAndKeywordNumeric(): void { - $filter = (new PartSearchFilter('123', $this->makeSearchSettings())) + $filter = (new PartSearchFilter('123')) ->setDbId(true); $expr = $this->createMock(Expr::class); @@ -209,7 +194,7 @@ final class PartSearchFilterTest extends TestCase public function testApplyDoesNotAddExactIdExpressionWhenKeywordNotNumeric(): void { - $filter = (new PartSearchFilter('123abc', $this->makeSearchSettings())) + $filter = (new PartSearchFilter('123abc')) ->setDbId(true); $expr = $this->createMock(Expr::class);