Skip to content

Commit 6b4ff26

Browse files
committed
More generous search
Split the keyword into tokens (at spaces). Search for every token individually, then combine results with AND.
1 parent b8d5b83 commit 6b4ff26

1 file changed

Lines changed: 44 additions & 16 deletions

File tree

src/DataTables/Filters/PartSearchFilter.php

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,16 @@ class PartSearchFilter implements FilterInterface
6565
/** @var bool Use Internal Part number for searching */
6666
protected bool $ipn = true;
6767

68+
/** @var int Helper variable for hacky array_map variable injection */
69+
protected int $it = 0;
70+
6871
public function __construct(
6972
/** @var string The string to query for */
7073
protected string $keyword
7174
)
7275
{
76+
// Transform keyword and trim excess spaces
77+
$keyword = trim(str_replace('+', ' ', $keyword));
7378
}
7479

7580
protected function getFieldsToSearch(): array
@@ -125,26 +130,50 @@ public function apply(QueryBuilder $queryBuilder): void
125130
return;
126131
}
127132

128-
//Convert the fields to search to a list of expressions
129-
$expressions = array_map(function (string $field): string {
130-
if ($this->regex) {
133+
if($this->regex) {
134+
//Convert the fields to search to a list of expressions
135+
$expressions = array_map(function (string $field): string {
131136
return sprintf("REGEXP(%s, :search_query) = TRUE", $field);
132-
}
133-
134-
return sprintf("ILIKE(%s, :search_query) = TRUE", $field);
135-
}, $fields_to_search);
137+
}, $fields_to_search);
136138

137-
//Add Or concatenation of the expressions to our query
138-
$queryBuilder->andWhere(
139-
$queryBuilder->expr()->orX(...$expressions)
140-
);
139+
//Add Or concatenation of the expressions to our query
140+
$queryBuilder->andWhere(
141+
$queryBuilder->expr()->orX(...$expressions)
142+
);
141143

142-
//For regex, we pass the query as is, for like we add % to the start and end as wildcards
143-
if ($this->regex) {
144+
//For regex, we pass the query as is, save html special chars
144145
$queryBuilder->setParameter('search_query', $this->keyword);
145-
} else {
146-
$queryBuilder->setParameter('search_query', '%' . $this->keyword . '%');
146+
return;
147147
}
148+
149+
//Split keyword on spaces, but limit token count to not blow up the DB
150+
$tokens = explode(' ', $this->keyword, 5);
151+
152+
$params = new \Doctrine\Common\Collections\ArrayCollection();
153+
154+
//Perform search of every single token in every selected field, AND the where clauses
155+
for ($i = 0; $i < sizeof($tokens); $i++) {
156+
$this->it = $i;
157+
$tokens[$i] = trim($tokens[$i]);
158+
159+
//Skip empty words (e.g. because of multiple spaces)
160+
if ($tokens[$i] === '') continue;
161+
162+
//Convert the fields to search to a list of expressions
163+
$expressions = array_map(function (string $field): string {
164+
return sprintf("ILIKE(%s, :search_query%u) = TRUE", $field, $this->it);
165+
}, $fields_to_search);
166+
167+
//Aggregate the parameters for consolidated commission
168+
$params[] = new \Doctrine\ORM\Query\Parameter('search_query' . $i, '%' . $tokens[$i] . '%');
169+
170+
//Add Or concatenation of the expressions to our query
171+
$queryBuilder->andWhere(
172+
$queryBuilder->expr()->orX(...$expressions)
173+
);
174+
}
175+
$queryBuilder->setParameters($params);
176+
148177
}
149178

150179
public function getKeyword(): string
@@ -301,5 +330,4 @@ public function setComment(bool $comment): PartSearchFilter
301330
return $this;
302331
}
303332

304-
305333
}

0 commit comments

Comments
 (0)