Skip to content

Commit 523e46f

Browse files
martenbf3l1x
authored andcommitted
feat: add conjunction search if text filter
1 parent b910672 commit 523e46f

11 files changed

+55
-12
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
@@ -184,11 +184,21 @@ protected function applyFilter(mixed $row, Filter $filter): mixed
184184

185185
$row_value = strtolower(Strings::toAscii((string) $row[$column]));
186186

187+
$found = [];
188+
187189
foreach ($words as $word) {
188190
if (str_contains($row_value, strtolower(Strings::toAscii($word)))) {
189-
return $row;
191+
if ($filter instanceof FilterText && !$filter->hasConjunctionSearch()) {
192+
return $row;
193+
} else {
194+
$found[] = true;
195+
}
190196
}
191197
}
198+
199+
if (count($found) === count($words)) {
200+
return $row;
201+
}
192202
}
193203
}
194204

src/DataSource/DibiFluentDataSource.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ protected function applyFilterText(FilterText $filter): void
182182
}
183183

184184
if (count($or) > 1) {
185-
$this->dataSource->where('(%or)', $or);
185+
$this->dataSource->where($filter->hasConjunctionSearch() ? '(%and)' : '(%or)', $or);
186186
} else {
187187
$this->dataSource->where($or);
188188
}

src/DataSource/DibiFluentMssqlDataSource.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ protected function applyFilterText(FilterText $filter): void
119119
}
120120

121121
if (count($or) > 1) {
122-
$this->dataSource->where('(%or)', $or);
122+
$this->dataSource->where($filter->hasConjunctionSearch() ? '(%and)' : '(%or)', $or);
123123
} else {
124124
$this->dataSource->where($or);
125125
}

src/DataSource/DibiFluentPostgreDataSource.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ protected function applyFilterText(FilterText $filter): void
3131
}
3232

3333
if (count($or) > 1) {
34-
$this->dataSource->where('(%or)', $or);
34+
$this->dataSource->where($filter->hasConjunctionSearch() ? '(%and)' : '(%or)', $or);
3535
} else {
3636
$this->dataSource->where($or);
3737
}

src/DataSource/DoctrineCollectionDataSource.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ protected function applyFilterText(FilterText $filter): void
196196
}
197197
}
198198

199-
$expr = call_user_func_array([Criteria::expr(), 'orX'], $exprs);
199+
$expr = call_user_func_array([Criteria::expr(), $filter->hasConjunctionSearch() ? 'andX' : 'orX'], $exprs);
200200
$this->criteria->andWhere($expr);
201201
}
202202

src/DataSource/DoctrineDataSource.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ protected function applyFilterText(FilterText $filter): void
278278
}
279279
}
280280

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

283283
$this->dataSource->andWhere($or);
284284
}

src/DataSource/NetteDatabaseTableDataSource.php

+7-5
Original file line numberDiff line numberDiff line change
@@ -194,31 +194,33 @@ protected function applyFilterText(FilterText $filter): void
194194
$bigOrArgs = [];
195195
$condition = $filter->getCondition();
196196

197+
$operator = $filter->hasConjunctionSearch() ? 'AND' : 'OR';
198+
197199
foreach ($condition as $column => $value) {
198200
$like = '(';
199201
$args = [];
200202

201203
if ($filter->isExactSearch()) {
202-
$like .= sprintf('%s = ? OR ', $column);
204+
$like .= sprintf('%s = ? %s ', $column, $operator);
203205
$args[] = sprintf('%s', $value);
204206
} else {
205207
$words = $filter->hasSplitWordsSearch() === false ? [$value] : explode(' ', $value);
206208

207209
foreach ($words as $word) {
208-
$like .= sprintf('%s LIKE ? OR ', $column);
210+
$like .= sprintf('%s LIKE ? %s ', $column, $operator);
209211
$args[] = sprintf('%%%s%%', $word);
210212
}
211213
}
212214

213-
$like = substr($like, 0, strlen($like) - 4) . ')';
215+
$like = substr($like, 0, strlen($like) - (strlen($operator) + 2)) . ')';
214216

215217
$or[] = $like;
216-
$bigOr .= sprintf('%s OR ', $like);
218+
$bigOr .= sprintf('%s %s ', $like, $operator);
217219
$bigOrArgs = [...$bigOrArgs, ...$args];
218220
}
219221

220222
if (count($or) > 1) {
221-
$bigOr = substr($bigOr, 0, strlen($bigOr) - 4) . ')';
223+
$bigOr = substr($bigOr, 0, strlen($bigOr) - (strlen($operator) + 2)) . ')';
222224

223225
$query = [...[$bigOr], ...$bigOrArgs];
224226

src/DataSource/NextrasDataSource.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ protected function applyFilterRange(FilterRange $filter): void
190190
protected function applyFilterText(FilterText $filter): void
191191
{
192192
$conditions = [
193-
ICollection::OR,
193+
$filter->hasConjunctionSearch() ? ICollection::AND : ICollection::OR,
194194
];
195195

196196
foreach ($filter->getCondition() as $column => $value) {

src/Filter/FilterText.php

+12
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ class FilterText extends Filter
1616

1717
protected bool $splitWordsSearch = true;
1818

19+
protected bool $conjunctionSearch = false;
20+
1921
/**
2022
* @param array|string[] $columns
2123
*/
@@ -84,4 +86,14 @@ public function hasSplitWordsSearch(): bool
8486
return $this->splitWordsSearch;
8587
}
8688

89+
public function setConjunctionSearch(bool $conjunctionSearch = true): void
90+
{
91+
$this->conjunctionSearch = $conjunctionSearch;
92+
}
93+
94+
public function hasConjunctionSearch(): bool
95+
{
96+
return $this->conjunctionSearch;
97+
}
98+
8799
}

tests/Cases/DataSources/BaseDataSourceTest.phpt

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

4343
$this->ds->filter([$filter]);
4444
Assert::same(2, $this->ds->getCount());
45+
46+
$filter->setConjunctionSearch();
47+
48+
$this->ds->filter([$filter]);
49+
Assert::same(1, $this->ds->getCount());
4550
}
4651

4752
public function testGetData(): void
@@ -59,6 +64,13 @@ abstract class BaseDataSourceTest extends TestCase
5964
$this->data[0],
6065
$this->data[5],
6166
], $this->getActualResultAsArray());
67+
68+
$filter->setConjunctionSearch();
69+
70+
$this->ds->filter([$filter]);
71+
Assert::equal([
72+
$this->data[5],
73+
], $this->getActualResultAsArray());
6274
}
6375

6476
public function testFilterMultipleColumns(): void

0 commit comments

Comments
 (0)