Skip to content

Commit

Permalink
feat: add conjunction search if text filter
Browse files Browse the repository at this point in the history
  • Loading branch information
martenb committed Oct 14, 2024
1 parent 1a63088 commit 688f57f
Show file tree
Hide file tree
Showing 12 changed files with 65 additions and 34 deletions.
7 changes: 7 additions & 0 deletions .docs/filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,13 @@ $grid->addFilterText('name', 'Name')
->setSplitWordsSearch(false);
```

If you need to find rows, that contains "foo" and "bar" (not just one of them), you can use `setConjunctionSearch()`.

```php
$grid->addFilterText('name', 'Name')
->setConjunctionSearch();
```

## FilterSelect

`FilterSelect` has one more parameter - options:
Expand Down
12 changes: 11 additions & 1 deletion src/DataSource/ArrayDataSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,21 @@ protected function applyFilter($row, Filter $filter)

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

$found = [];

foreach ($words as $word) {
if (strpos($row_value, strtolower(Strings::toAscii($word))) !== false) {
return $row;
if ($filter instanceof FilterText && !$filter->hasConjunctionSearch()) {
return $row;
} else {
$found[] = true;
}
}
}

if (count($found) === count($words)) {
return $row;
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/DataSource/DibiFluentDataSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ protected function applyFilterText(FilterText $filter): void
}

if (sizeof($or) > 1) {
$this->dataSource->where('(%or)', $or);
$this->dataSource->where($filter->hasConjunctionSearch() ? '(%and)' : '(%or)', $or);
} else {
$this->dataSource->where($or);
}
Expand Down
2 changes: 1 addition & 1 deletion src/DataSource/DibiFluentMssqlDataSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ protected function applyFilterText(FilterText $filter): void
}

if (sizeof($or) > 1) {
$this->dataSource->where('(%or)', $or);
$this->dataSource->where($filter->hasConjunctionSearch() ? '(%and)' : '(%or)', $or);
} else {
$this->dataSource->where($or);
}
Expand Down
2 changes: 1 addition & 1 deletion src/DataSource/DibiFluentPostgreDataSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ protected function applyFilterText(FilterText $filter): void
}

if (sizeof($or) > 1) {
$this->dataSource->where('(%or)', $or);
$this->dataSource->where($filter->hasConjunctionSearch() ? '(%and)' : '(%or)', $or);
} else {
$this->dataSource->where($or);
}
Expand Down
2 changes: 1 addition & 1 deletion src/DataSource/DoctrineCollectionDataSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ protected function applyFilterText(FilterText $filter): void
}
}

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

Expand Down
2 changes: 1 addition & 1 deletion src/DataSource/DoctrineDataSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ protected function applyFilterText(FilterText $filter): void
}
}

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

$this->dataSource->andWhere($or);
}
Expand Down
12 changes: 7 additions & 5 deletions src/DataSource/NetteDatabaseTableDataSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -224,31 +224,33 @@ protected function applyFilterText(FilterText $filter): void
$bigOrArgs = [];
$condition = $filter->getCondition();

$operator = $filter->hasConjunctionSearch() ? 'AND' : 'OR';

foreach ($condition as $column => $value) {
$like = '(';
$args = [];

if ($filter->isExactSearch()) {
$like .= "$column = ? OR ";
$like .= "$column = ? $operator ";
$args[] = "$value";
} else {
$words = $filter->hasSplitWordsSearch() === false ? [$value] : explode(' ', $value);

foreach ($words as $word) {
$like .= "$column LIKE ? OR ";
$like .= "$column LIKE ? $operator ";
$args[] = "%$word%";
}
}

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

$or[] = $like;
$bigOr .= "$like OR ";
$bigOr .= "$like $operator ";
$bigOrArgs = array_merge($bigOrArgs, $args);
}

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

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

Expand Down
9 changes: 5 additions & 4 deletions src/DataSource/NextrasDataSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ protected function applyFilterText(FilterText $filter): void
// native handling with LikeFunction in v4
if (class_exists(LikeExpression::class)) {
$conditions = [
ICollection::OR,
$filter->hasConjunctionSearch() ? ICollection::AND : ICollection::OR,
];

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

foreach ($condition as $column => $value) {
if ($filter->isExactSearch()) {
$expr .= '%column = %s OR ';
$expr .= "%column = %s $operator ";
$params[] = $column;
$params[] = "$value";

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

foreach ($words as $word) {
$expr .= '%column LIKE %s OR ';
$expr .= "%column LIKE %s $operator ";
$params[] = $column;
$params[] = "%$word%";
}
}

$expr = preg_replace('/ OR $/', ')', $expr);
$expr = preg_replace("/ $operator $/", ')', $expr);

array_unshift($params, $expr);

Expand Down
18 changes: 18 additions & 0 deletions src/Filter/FilterText.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ class FilterText extends Filter
*/
protected $splitWordsSearch = true;

/**
* @var bool
*/
protected $conjunctionSearch = false;

/**
* @var array|string[]
*/
Expand Down Expand Up @@ -110,4 +115,17 @@ public function hasSplitWordsSearch(): bool
{
return $this->splitWordsSearch;
}


public function setConjunctionSearch(bool $conjunctionSearch = true): void
{
$this->conjunctionSearch = $conjunctionSearch;
}


public function hasConjunctionSearch(): bool
{
return $this->conjunctionSearch;
}

}
12 changes: 12 additions & 0 deletions tests/Cases/DataSources/BaseDataSourceTest.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ abstract class BaseDataSourceTest extends TestCase

$this->ds->filter([$filter]);
Assert::same(2, $this->ds->getCount());

$filter->setConjunctionSearch();

$this->ds->filter([$filter]);
Assert::same(1, $this->ds->getCount());
}

public function testGetData(): void
Expand All @@ -65,6 +70,13 @@ abstract class BaseDataSourceTest extends TestCase
$this->data[0],
$this->data[5],
], $this->getActualResultAsArray());

$filter->setConjunctionSearch();

$this->ds->filter([$filter]);
Assert::equal([
$this->data[5],
], $this->getActualResultAsArray());
}

public function testFilterMultipleColumns(): void
Expand Down
19 changes: 0 additions & 19 deletions tests/Cases/DataSources/NextrasDataSourceTest.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,14 @@ use Nette\Caching\Cache;
use Nette\Caching\Storages\DevNullStorage;
use Nette\Utils\Arrays;
use Nextras\Dbal\Connection;
use Nextras\Orm\Collection\Expression\LikeExpression;
use Nextras\Orm\Entity\Entity;
use Nextras\Orm\Mapper\Dbal\DbalMapperCoordinator;
use Nextras\Orm\Mapper\Mapper;
use Nextras\Orm\Model\Model;
use Nextras\Orm\Model\SimpleModelFactory;
use Nextras\Orm\Repository\Repository;
use Tester\Assert;
use Tester\Environment;
use Ublaboo\DataGrid\DataSource\NextrasDataSource;
use Ublaboo\DataGrid\Filter\FilterText;
use Ublaboo\DataGrid\Tests\Files\TestingDataGridFactory;

require __DIR__ . '/BaseDataSourceTest.phpt';
Expand All @@ -38,22 +35,6 @@ final class NextrasDataSourceTest extends BaseDataSourceTest
*/
private $model;

public function testFilterOnJoinedTable(): void
{
// skip this test for v3.1
if (!class_exists(LikeExpression::class)) {
return;
}

$this->ds = new NextrasDataSource($this->model->books->findAll(), 'id');

$filter = new FilterText($this->grid, 'a', 'b', ['author.name']);
$filter->setValue('John Red');

$this->ds->filter([$filter]);
Assert::same(2, $this->ds->getCount());
}

protected function setUp(): void
{
$this->setUpDatabase();
Expand Down

0 comments on commit 688f57f

Please sign in to comment.