This commit is contained in:
d-buchmann 2025-12-02 16:08:22 +01:00 committed by GitHub
commit 716f4c2a23
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -66,11 +66,16 @@ class PartSearchFilter implements FilterInterface
/** @var bool Use Internal Part number for searching */
protected bool $ipn = true;
/** @var int Helper variable for hacky array_map variable injection */
protected int $it = 0;
public function __construct(
/** @var string The string to query for */
protected string $keyword
)
{
// Transform keyword and trim excess spaces
$keyword = trim(str_replace('+', ' ', $keyword));
}
protected function getFieldsToSearch(): array
@ -126,27 +131,53 @@ class PartSearchFilter implements FilterInterface
return;
}
//Convert the fields to search to a list of expressions
$expressions = array_map(function (string $field): string {
if ($this->regex) {
if($this->regex) {
//Convert the fields to search to a list of expressions
$expressions = array_map(function (string $field): string {
return sprintf("REGEXP(%s, :search_query) = TRUE", $field);
}
}, $fields_to_search);
return sprintf("ILIKE(%s, :search_query) = TRUE", $field);
}, $fields_to_search);
//Add Or concatenation of the expressions to our query
$queryBuilder->andWhere(
$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) {
//For regex, we pass the query as is, save html special chars
$queryBuilder->setParameter('search_query', $this->keyword);
return;
} else {
//Escape % and _ characters in the keyword
$this->keyword = str_replace(['%', '_'], ['\%', '\_'], $this->keyword);
$queryBuilder->setParameter('search_query', '%' . $this->keyword . '%');
//Split keyword on spaces, but limit token count
$tokens = explode(' ', $this->keyword, 5);
$params = new \Doctrine\Common\Collections\ArrayCollection();
//Perform search of every single token in every selected field
//AND-combine the results (all tokens must be present in any result, but the order does not matter)
for ($i = 0; $i < sizeof($tokens); $i++) {
$this->it = $i;
$tokens[$i] = trim($tokens[$i]);
//Skip empty words (e.g. because of multiple spaces)
if ($tokens[$i] === '') {
continue;
}
//Convert the fields to search to a list of expressions
$expressions = array_map(function (string $field): string {
return sprintf("ILIKE(%s, :search_query%u) = TRUE", $field, $this->it);
}, $fields_to_search);
//Aggregate the parameters for consolidated commission
$params[] = new \Doctrine\ORM\Query\Parameter('search_query' . $i, '%' . $tokens[$i] . '%');
//Add Or concatenation of the expressions to our query
$queryBuilder->andWhere(
$queryBuilder->expr()->orX(...$expressions)
);
}
$queryBuilder->setParameters($params);
}
}
@ -304,5 +335,4 @@ class PartSearchFilter implements FilterInterface
return $this;
}
}