Skip to content

Commit 60cf8a8

Browse files
committed
feat: add conjunction search if text filter
1 parent 1a63088 commit 60cf8a8

11 files changed

+64
-15
lines changed

.docs/filters.md

+7
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,13 @@ $grid->addFilterText('name', 'Name')
158158
->setSplitWordsSearch(false);
159159
```
160160

161+
If you need to find rows, that contains "foo" and "bar" (not just one of them), you can use `setConjunctionSearch()`.
162+
163+
```php
164+
$grid->addFilterText('name', 'Name')
165+
->setConjunctionSearch();
166+
```
167+
161168
## FilterSelect
162169

163170
`FilterSelect` has one more parameter - options:

src/DataSource/ArrayDataSource.php

+11-1
Original file line numberDiff line numberDiff line change
@@ -209,11 +209,21 @@ protected function applyFilter($row, Filter $filter)
209209

210210
$row_value = strtolower(Strings::toAscii((string) $row[$column]));
211211

212+
$found = [];
213+
212214
foreach ($words as $word) {
213215
if (strpos($row_value, strtolower(Strings::toAscii($word))) !== false) {
214-
return $row;
216+
if ($filter instanceof FilterText && !$filter->hasConjunctionSearch()) {
217+
return $row;
218+
} else {
219+
$found[] = true;
220+
}
215221
}
216222
}
223+
224+
if (count($found) === count($words)) {
225+
return $row;
226+
}
217227
}
218228
}
219229

src/DataSource/DibiFluentDataSource.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ protected function applyFilterText(FilterText $filter): void
215215
}
216216

217217
if (sizeof($or) > 1) {
218-
$this->dataSource->where('(%or)', $or);
218+
$this->dataSource->where($filter->hasConjunctionSearch() ? '(%and)' : '(%or)', $or);
219219
} else {
220220
$this->dataSource->where($or);
221221
}

src/DataSource/DibiFluentMssqlDataSource.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ protected function applyFilterText(FilterText $filter): void
136136
}
137137

138138
if (sizeof($or) > 1) {
139-
$this->dataSource->where('(%or)', $or);
139+
$this->dataSource->where($filter->hasConjunctionSearch() ? '(%and)' : '(%or)', $or);
140140
} else {
141141
$this->dataSource->where($or);
142142
}

src/DataSource/DibiFluentPostgreDataSource.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ protected function applyFilterText(FilterText $filter): void
3333
}
3434

3535
if (sizeof($or) > 1) {
36-
$this->dataSource->where('(%or)', $or);
36+
$this->dataSource->where($filter->hasConjunctionSearch() ? '(%and)' : '(%or)', $or);
3737
} else {
3838
$this->dataSource->where($or);
3939
}

src/DataSource/DoctrineCollectionDataSource.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ protected function applyFilterText(FilterText $filter): void
226226
}
227227
}
228228

229-
$expr = call_user_func_array([Criteria::expr(), 'orX'], $exprs);
229+
$expr = call_user_func_array([Criteria::expr(), $filter->hasConjunctionSearch() ? 'andX' : 'orX'], $exprs);
230230
$this->criteria->andWhere($expr);
231231
}
232232

src/DataSource/DoctrineDataSource.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ protected function applyFilterText(FilterText $filter): void
319319
}
320320
}
321321

322-
$or = call_user_func_array([$this->dataSource->expr(), 'orX'], $exprs);
322+
$or = call_user_func_array([$this->dataSource->expr(), $filter->hasConjunctionSearch() ? 'andX' : 'orX'], $exprs);
323323

324324
$this->dataSource->andWhere($or);
325325
}

src/DataSource/NetteDatabaseTableDataSource.php

+7-5
Original file line numberDiff line numberDiff line change
@@ -224,31 +224,33 @@ protected function applyFilterText(FilterText $filter): void
224224
$bigOrArgs = [];
225225
$condition = $filter->getCondition();
226226

227+
$operator = $filter->hasConjunctionSearch() ? 'AND' : 'OR';
228+
227229
foreach ($condition as $column => $value) {
228230
$like = '(';
229231
$args = [];
230232

231233
if ($filter->isExactSearch()) {
232-
$like .= "$column = ? OR ";
234+
$like .= "$column = ? $operator ";
233235
$args[] = "$value";
234236
} else {
235237
$words = $filter->hasSplitWordsSearch() === false ? [$value] : explode(' ', $value);
236238

237239
foreach ($words as $word) {
238-
$like .= "$column LIKE ? OR ";
240+
$like .= "$column LIKE ? $operator ";
239241
$args[] = "%$word%";
240242
}
241243
}
242244

243-
$like = substr($like, 0, strlen($like) - 4) . ')';
245+
$like = substr($like, 0, strlen($like) - (strlen($operator) + 2)) . ')';
244246

245247
$or[] = $like;
246-
$bigOr .= "$like OR ";
248+
$bigOr .= "$like $operator ";
247249
$bigOrArgs = array_merge($bigOrArgs, $args);
248250
}
249251

250252
if (sizeof($or) > 1) {
251-
$bigOr = substr($bigOr, 0, strlen($bigOr) - 4) . ')';
253+
$bigOr = substr($bigOr, 0, strlen($bigOr) - (strlen($operator) + 2)) . ')';
252254

253255
$query = array_merge([$bigOr], $bigOrArgs);
254256

src/DataSource/NextrasDataSource.php

+5-4
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ protected function applyFilterText(FilterText $filter): void
243243
// native handling with LikeFunction in v4
244244
if (class_exists(LikeExpression::class)) {
245245
$conditions = [
246-
ICollection::OR,
246+
$filter->hasConjunctionSearch() ? ICollection::AND : ICollection::OR,
247247
];
248248

249249
foreach ($filter->getCondition() as $column => $value) {
@@ -272,10 +272,11 @@ protected function applyFilterText(FilterText $filter): void
272272
$condition = $filter->getCondition();
273273
$expr = '(';
274274
$params = [];
275+
$operator = $filter->hasConjunctionSearch() ? 'AND' : 'OR';
275276

276277
foreach ($condition as $column => $value) {
277278
if ($filter->isExactSearch()) {
278-
$expr .= '%column = %s OR ';
279+
$expr .= "%column = %s $operator ";
279280
$params[] = $column;
280281
$params[] = "$value";
281282

@@ -285,13 +286,13 @@ protected function applyFilterText(FilterText $filter): void
285286
$words = $filter->hasSplitWordsSearch() === false ? [$value] : explode(' ', $value);
286287

287288
foreach ($words as $word) {
288-
$expr .= '%column LIKE %s OR ';
289+
$expr .= "%column LIKE %s $operator ";
289290
$params[] = $column;
290291
$params[] = "%$word%";
291292
}
292293
}
293294

294-
$expr = preg_replace('/ OR $/', ')', $expr);
295+
$expr = preg_replace("/ $operator $/", ')', $expr);
295296

296297
array_unshift($params, $expr);
297298

src/Filter/FilterText.php

+17
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ class FilterText extends Filter
3030
*/
3131
protected $splitWordsSearch = true;
3232

33+
/**
34+
* @var bool
35+
*/
36+
protected $conjunctionSearch = false;
37+
3338
/**
3439
* @var array|string[]
3540
*/
@@ -110,4 +115,16 @@ public function hasSplitWordsSearch(): bool
110115
{
111116
return $this->splitWordsSearch;
112117
}
118+
119+
120+
public function setConjunctionSearch(bool $conjunctionSearch = true): void
121+
{
122+
$this->conjunctionSearch = $conjunctionSearch;
123+
}
124+
125+
126+
public function hasConjunctionSearch(): bool
127+
{
128+
return $this->conjunctionSearch;
129+
}
113130
}

tests/Cases/DataSources/BaseDataSourceTest.phpt

+12
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ abstract class BaseDataSourceTest extends TestCase
4747

4848
$this->ds->filter([$filter]);
4949
Assert::same(2, $this->ds->getCount());
50+
51+
$filter->setConjunctionSearch();
52+
53+
$this->ds->filter([$filter]);
54+
Assert::same(1, $this->ds->getCount());
5055
}
5156

5257
public function testGetData(): void
@@ -65,6 +70,13 @@ abstract class BaseDataSourceTest extends TestCase
6570
$this->data[0],
6671
$this->data[5],
6772
], $this->getActualResultAsArray());
73+
74+
$filter->setConjunctionSearch();
75+
76+
$this->ds->filter([$filter]);
77+
Assert::equal([
78+
$this->data[5],
79+
], $this->getActualResultAsArray());
6880
}
6981

7082
public function testFilterMultipleColumns(): void

0 commit comments

Comments
 (0)