Added ID to search options. Fixed seach option by using equal to instead of like for the ID.

This commit is contained in:
kernchen-brc 2026-01-09 11:37:30 +01:00
parent 2157916e9b
commit 64efca4786
3 changed files with 56 additions and 18 deletions

View file

@ -319,6 +319,7 @@ class PartListsController extends AbstractController
//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)! //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')); $filter->setName($request->query->getBoolean('name'));
$filter->setDbId($request->query->getBoolean('dbid'));
$filter->setCategory($request->query->getBoolean('category')); $filter->setCategory($request->query->getBoolean('category'));
$filter->setDescription($request->query->getBoolean('description')); $filter->setDescription($request->query->getBoolean('description'));
$filter->setMpn($request->query->getBoolean('mpn')); $filter->setMpn($request->query->getBoolean('mpn'));

View file

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace App\DataTables\Filters; namespace App\DataTables\Filters;
use App\DataTables\Filters\Constraints\AbstractConstraint; use App\DataTables\Filters\Constraints\AbstractConstraint;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Doctrine\DBAL\ParameterType;
class PartSearchFilter implements FilterInterface class PartSearchFilter implements FilterInterface
{ {
@ -33,6 +34,9 @@ class PartSearchFilter implements FilterInterface
/** @var bool Use name field for searching */ /** @var bool Use name field for searching */
protected bool $name = true; protected bool $name = true;
/** @var bool Use id field for searching */
protected bool $dbId = false;
/** @var bool Use category name for searching */ /** @var bool Use category name for searching */
protected bool $category = true; protected bool $category = true;
@ -120,33 +124,51 @@ class PartSearchFilter implements FilterInterface
public function apply(QueryBuilder $queryBuilder): void public function apply(QueryBuilder $queryBuilder): void
{ {
$fields_to_search = $this->getFieldsToSearch(); $fields_to_search = $this->getFieldsToSearch();
$is_numeric = preg_match('/^\d+$/', $this->keyword) === 1;
// Add exact ID match only when the keyword is numeric
$search_dbId = $is_numeric && (bool)$this->dbId;
//If we have nothing to search for, do nothing //If we have nothing to search for, do nothing
if ($fields_to_search === [] || $this->keyword === '') { if (($fields_to_search === [] && !$search_dbId) || $this->keyword === '') {
return; return;
} }
//Convert the fields to search to a list of expressions $expressions = [];
$expressions = array_map(function (string $field): string {
if($fields_to_search !== []) {
//Convert the fields to search to a list of expressions
$expressions = array_map(function (string $field): string {
if ($this->regex) {
return sprintf("REGEXP(%s, :search_query) = TRUE", $field);
}
return sprintf("ILIKE(%s, :search_query) = TRUE", $field);
}, $fields_to_search);
//For regex, we pass the query as is, for like we add % to the start and end as wildcards
if ($this->regex) { if ($this->regex) {
return sprintf("REGEXP(%s, :search_query) = TRUE", $field); $queryBuilder->setParameter('search_query', $this->keyword);
} else {
//Escape % and _ characters in the keyword
$this->keyword = str_replace(['%', '_'], ['\%', '\_'], $this->keyword);
$queryBuilder->setParameter('search_query', '%' . $this->keyword . '%');
} }
}
return sprintf("ILIKE(%s, :search_query) = TRUE", $field); //Use equal expression to just search for exact numeric matches
}, $fields_to_search); if ($search_dbId) {
$expressions[] = $queryBuilder->expr()->eq('part.id', ':id_exact');
$queryBuilder->setParameter('id_exact', (int) $this->keyword,
\Doctrine\DBAL\ParameterType::INTEGER);
}
//Add Or concatenation of the expressions to our query //Guard condition
$queryBuilder->andWhere( if (!empty($expressions)) {
$queryBuilder->expr()->orX(...$expressions) //Add Or concatenation of the expressions to our query
); $queryBuilder->andWhere(
$queryBuilder->expr()->orX(...$expressions)
//For regex, we pass the query as is, for like we add % to the start and end as wildcards );
if ($this->regex) {
$queryBuilder->setParameter('search_query', $this->keyword);
} else {
//Escape % and _ characters in the keyword
$this->keyword = str_replace(['%', '_'], ['\%', '\_'], $this->keyword);
$queryBuilder->setParameter('search_query', '%' . $this->keyword . '%');
} }
} }
@ -183,6 +205,17 @@ class PartSearchFilter implements FilterInterface
return $this; return $this;
} }
public function isDbId(): bool
{
return $this->dbId;
}
public function setDbId(bool $dbId): PartSearchFilter
{
$this->dbId = $dbId;
return $this;
}
public function isCategory(): bool public function isCategory(): bool
{ {
return $this->category; return $this->category;

View file

@ -11,6 +11,10 @@
<input type="checkbox" class="form-check-input" id="search_name" name="name" value="1" checked {{ stimulus_controller('elements/localStorage_checkbox') }}> <input type="checkbox" class="form-check-input" id="search_name" name="name" value="1" checked {{ stimulus_controller('elements/localStorage_checkbox') }}>
<label for="search_name" class="form-check-label justify-content-start">{% trans %}name.label{% endtrans %}</label> <label for="search_name" class="form-check-label justify-content-start">{% trans %}name.label{% endtrans %}</label>
</div> </div>
<div class="form-check">
<input type="checkbox" class="form-check-input" id="search_dbid" name="dbid" value="1" checked {{ stimulus_controller('elements/localStorage_checkbox') }}>
<label for="search_dbid" class="form-check-label justify-content-start">{% trans %}id.label{% endtrans %}</label>
</div>
<div class="form-check"> <div class="form-check">
<input type="checkbox" class="form-check-input" id="search_category" name="category" value="1" checked {{ stimulus_controller('elements/localStorage_checkbox') }}> <input type="checkbox" class="form-check-input" id="search_category" name="category" value="1" checked {{ stimulus_controller('elements/localStorage_checkbox') }}>
<label for="search_category" class="form-check-label justify-content-start">{% trans %}category.label{% endtrans %}</label> <label for="search_category" class="form-check-label justify-content-start">{% trans %}category.label{% endtrans %}</label>