From 514ba1e202822f1ae8e11b3c2892db5ddf914b10 Mon Sep 17 00:00:00 2001 From: Alexey Rogachev Date: Mon, 1 Apr 2024 13:27:10 +0500 Subject: [PATCH 1/7] Add `ILike` filter, fix `Like` filter --- src/Reader/Filter/ILike.php | 33 +++++++++++++++++++ src/Reader/Filter/Like.php | 2 +- .../Iterable/FilterHandler/ILikeHandler.php | 33 +++++++++++++++++++ .../Iterable/FilterHandler/LikeHandler.php | 4 +-- src/Reader/Iterable/IterableDataReader.php | 2 ++ tests/Reader/IterableDataReaderTest.php | 19 +++++++++-- tests/Reader/IterableHandler/ILikeTest.php | 31 +++++++++++++++++ tests/Reader/IterableHandler/LikeTest.php | 16 ++++----- 8 files changed, 124 insertions(+), 16 deletions(-) create mode 100644 src/Reader/Filter/ILike.php create mode 100644 src/Reader/Iterable/FilterHandler/ILikeHandler.php create mode 100644 tests/Reader/IterableHandler/ILikeTest.php diff --git a/src/Reader/Filter/ILike.php b/src/Reader/Filter/ILike.php new file mode 100644 index 00000000..3cabf898 --- /dev/null +++ b/src/Reader/Filter/ILike.php @@ -0,0 +1,33 @@ +field; + } + + public function getValue(): string + { + return $this->value; + } +} diff --git a/src/Reader/Filter/Like.php b/src/Reader/Filter/Like.php index fc6781f1..ffd79801 100644 --- a/src/Reader/Filter/Like.php +++ b/src/Reader/Filter/Like.php @@ -7,7 +7,7 @@ use Yiisoft\Data\Reader\FilterInterface; /** - * `Like` filter defines a criteria for ensuring field value is like-match to a given value. + * `Like` filter defines a criteria for ensuring field value is like-match to a given value (case-sensitive). */ final class Like implements FilterInterface { diff --git a/src/Reader/Iterable/FilterHandler/ILikeHandler.php b/src/Reader/Iterable/FilterHandler/ILikeHandler.php new file mode 100644 index 00000000..e5400fd2 --- /dev/null +++ b/src/Reader/Iterable/FilterHandler/ILikeHandler.php @@ -0,0 +1,33 @@ +getField()); + + return is_string($itemValue) && mb_stripos($itemValue, $filter->getValue()) !== false; + } +} diff --git a/src/Reader/Iterable/FilterHandler/LikeHandler.php b/src/Reader/Iterable/FilterHandler/LikeHandler.php index 5dac7d36..0c9ef2d7 100644 --- a/src/Reader/Iterable/FilterHandler/LikeHandler.php +++ b/src/Reader/Iterable/FilterHandler/LikeHandler.php @@ -13,7 +13,7 @@ use function stripos; /** - * `Like` iterable filter handler ensures that the field value is like-match to a given value. + * `Like` iterable filter handler ensures that the field value is like-match to a given value (case-sensitive). */ final class LikeHandler implements IterableFilterHandlerInterface { @@ -28,6 +28,6 @@ public function match(object|array $item, FilterInterface $filter, array $iterab $itemValue = ArrayHelper::getValue($item, $filter->getField()); - return is_string($itemValue) && stripos($itemValue, $filter->getValue()) !== false; + return is_string($itemValue) && strpos($itemValue, $filter->getValue()) !== false; } } diff --git a/src/Reader/Iterable/IterableDataReader.php b/src/Reader/Iterable/IterableDataReader.php index 81cb90e1..211d5c6e 100644 --- a/src/Reader/Iterable/IterableDataReader.php +++ b/src/Reader/Iterable/IterableDataReader.php @@ -20,6 +20,7 @@ use Yiisoft\Data\Reader\Iterable\FilterHandler\EqualsNullHandler; use Yiisoft\Data\Reader\Iterable\FilterHandler\GreaterThanHandler; use Yiisoft\Data\Reader\Iterable\FilterHandler\GreaterThanOrEqualHandler; +use Yiisoft\Data\Reader\Iterable\FilterHandler\ILikeHandler; use Yiisoft\Data\Reader\Iterable\FilterHandler\InHandler; use Yiisoft\Data\Reader\Iterable\FilterHandler\LessThanHandler; use Yiisoft\Data\Reader\Iterable\FilterHandler\LessThanOrEqualHandler; @@ -73,6 +74,7 @@ public function __construct(private iterable $data) new EqualsNullHandler(), new GreaterThanHandler(), new GreaterThanOrEqualHandler(), + new ILikeHandler(), new InHandler(), new LessThanHandler(), new LessThanOrEqualHandler(), diff --git a/tests/Reader/IterableDataReaderTest.php b/tests/Reader/IterableDataReaderTest.php index 74069b37..112527de 100644 --- a/tests/Reader/IterableDataReaderTest.php +++ b/tests/Reader/IterableDataReaderTest.php @@ -14,6 +14,7 @@ use Yiisoft\Data\Reader\Filter\Equals; use Yiisoft\Data\Reader\Filter\GreaterThan; use Yiisoft\Data\Reader\Filter\GreaterThanOrEqual; +use Yiisoft\Data\Reader\Filter\ILike; use Yiisoft\Data\Reader\Filter\In; use Yiisoft\Data\Reader\Filter\LessThan; use Yiisoft\Data\Reader\Filter\LessThanOrEqual; @@ -264,7 +265,19 @@ public function testInFiltering(): void public function testLikeFiltering(): void { - $filter = new Like('name', 'agent'); + $filter = new Like('name', 'Agent'); + $reader = (new IterableDataReader(self::DEFAULT_DATASET)) + ->withFilter($filter); + + $this->assertSame([ + 2 => self::ITEM_3, + 3 => self::ITEM_4, + ], $reader->read()); + } + + public function testILikeFiltering(): void + { + $filter = new ILike('name', 'agent'); $reader = (new IterableDataReader(self::DEFAULT_DATASET)) ->withFilter($filter); @@ -307,7 +320,7 @@ public function testAllFiltering(): void { $filter = new All( new GreaterThan('id', 3), - new Like('name', 'agent') + new Like('name', 'Agent') ); $reader = (new IterableDataReader(self::DEFAULT_DATASET)) ->withFilter($filter); @@ -343,7 +356,7 @@ public function testFilteredCount(): void $this->assertSame(5, $total, 'Wrong count of elements'); - $reader = $reader->withFilter(new Like('name', 'agent')); + $reader = $reader->withFilter(new Like('name', 'Agent')); $totalAgents = count($reader); $this->assertSame(2, $totalAgents, 'Wrong count of filtered elements'); } diff --git a/tests/Reader/IterableHandler/ILikeTest.php b/tests/Reader/IterableHandler/ILikeTest.php new file mode 100644 index 00000000..5429032a --- /dev/null +++ b/tests/Reader/IterableHandler/ILikeTest.php @@ -0,0 +1,31 @@ + 1, 'value' => 'Great Cat Fighter'], 'value', 'Great Cat Fighter'], + [true, ['id' => 1, 'value' => 'Great Cat Fighter'], 'value', 'Cat'], + [true, ['id' => 1, 'value' => 'Great Cat Fighter'], 'value', 'cat'], + [false, ['id' => 1, 'value' => 'Great Cat Fighter'], 'id', '1'], + [true, ['id' => 1, 'value' => 'πŸ™πŸ™‚πŸ™'], 'value', 'πŸ™‚'], + ]; + } + + #[DataProvider('matchDataProvider')] + public function testMatch(bool $expected, array $item, string $field, string $value): void + { + $processor = new ILikeHandler(); + $this->assertSame($expected, $processor->match($item, new ILike($field, $value), [])); + } +} diff --git a/tests/Reader/IterableHandler/LikeTest.php b/tests/Reader/IterableHandler/LikeTest.php index f5a943f6..0502dc95 100644 --- a/tests/Reader/IterableHandler/LikeTest.php +++ b/tests/Reader/IterableHandler/LikeTest.php @@ -14,22 +14,18 @@ final class LikeTest extends TestCase public static function matchDataProvider(): array { return [ - [true, 'value', 'Great Cat Fighter'], - [true, 'value', 'Cat'], - [false, 'id', '1'], + [true, ['id' => 1, 'value' => 'Great Cat Fighter'], 'value', 'Great Cat Fighter'], + [true, ['id' => 1, 'value' => 'Great Cat Fighter'], 'value', 'Cat'], + [false, ['id' => 1, 'value' => 'Great Cat Fighter'], 'value', 'cat'], + [false, ['id' => 1, 'value' => 'Great Cat Fighter'], 'id', '1'], + [true, ['id' => 1, 'value' => 'πŸ™πŸ™‚πŸ™'], 'value', 'πŸ™‚'], ]; } #[DataProvider('matchDataProvider')] - public function testMatch(bool $expected, string $field, string $value): void + public function testMatch(bool $expected, array $item, string $field, string $value): void { $processor = new LikeHandler(); - - $item = [ - 'id' => 1, - 'value' => 'Great Cat Fighter', - ]; - $this->assertSame($expected, $processor->match($item, new Like($field, $value), [])); } } From a196c44448e5894d2ed0604ab1ec79e28cf60edb Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Mon, 1 Apr 2024 08:27:25 +0000 Subject: [PATCH 2/7] Apply fixes from StyleCI --- src/Reader/Iterable/FilterHandler/ILikeHandler.php | 1 - src/Reader/Iterable/FilterHandler/LikeHandler.php | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Reader/Iterable/FilterHandler/ILikeHandler.php b/src/Reader/Iterable/FilterHandler/ILikeHandler.php index e5400fd2..a6c6b6b3 100644 --- a/src/Reader/Iterable/FilterHandler/ILikeHandler.php +++ b/src/Reader/Iterable/FilterHandler/ILikeHandler.php @@ -10,7 +10,6 @@ use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; use function is_string; -use function stripos; /** * `ILike` iterable filter handler ensures that the field value is like-match to a given value (case-insensitive). diff --git a/src/Reader/Iterable/FilterHandler/LikeHandler.php b/src/Reader/Iterable/FilterHandler/LikeHandler.php index 0c9ef2d7..6d047cc9 100644 --- a/src/Reader/Iterable/FilterHandler/LikeHandler.php +++ b/src/Reader/Iterable/FilterHandler/LikeHandler.php @@ -10,7 +10,6 @@ use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; use function is_string; -use function stripos; /** * `Like` iterable filter handler ensures that the field value is like-match to a given value (case-sensitive). From e866fcc2fac5c2d48f092746d171628c7ba4af7a Mon Sep 17 00:00:00 2001 From: arogachev Date: Mon, 1 Apr 2024 08:29:00 +0000 Subject: [PATCH 3/7] Apply Rector changes (CI) --- src/Reader/Iterable/FilterHandler/LikeHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Reader/Iterable/FilterHandler/LikeHandler.php b/src/Reader/Iterable/FilterHandler/LikeHandler.php index 6d047cc9..7dac3e0c 100644 --- a/src/Reader/Iterable/FilterHandler/LikeHandler.php +++ b/src/Reader/Iterable/FilterHandler/LikeHandler.php @@ -27,6 +27,6 @@ public function match(object|array $item, FilterInterface $filter, array $iterab $itemValue = ArrayHelper::getValue($item, $filter->getField()); - return is_string($itemValue) && strpos($itemValue, $filter->getValue()) !== false; + return is_string($itemValue) && str_contains($itemValue, $filter->getValue()); } } From 1dbb70aac67beec914b97dab8047707013ae3468 Mon Sep 17 00:00:00 2001 From: Alexey Rogachev Date: Tue, 2 Apr 2024 12:18:17 +0500 Subject: [PATCH 4/7] Use stripos instead of mb_stripos in ILikeHandler --- src/Reader/Iterable/FilterHandler/ILikeHandler.php | 2 +- tests/Reader/IterableHandler/ILikeTest.php | 1 + tests/Reader/IterableHandler/LikeTest.php | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Reader/Iterable/FilterHandler/ILikeHandler.php b/src/Reader/Iterable/FilterHandler/ILikeHandler.php index a6c6b6b3..b7d601fd 100644 --- a/src/Reader/Iterable/FilterHandler/ILikeHandler.php +++ b/src/Reader/Iterable/FilterHandler/ILikeHandler.php @@ -27,6 +27,6 @@ public function match(object|array $item, FilterInterface $filter, array $iterab $itemValue = ArrayHelper::getValue($item, $filter->getField()); - return is_string($itemValue) && mb_stripos($itemValue, $filter->getValue()) !== false; + return is_string($itemValue) && stripos($itemValue, $filter->getValue()) !== false; } } diff --git a/tests/Reader/IterableHandler/ILikeTest.php b/tests/Reader/IterableHandler/ILikeTest.php index 5429032a..24eef62e 100644 --- a/tests/Reader/IterableHandler/ILikeTest.php +++ b/tests/Reader/IterableHandler/ILikeTest.php @@ -19,6 +19,7 @@ public static function matchDataProvider(): array [true, ['id' => 1, 'value' => 'Great Cat Fighter'], 'value', 'cat'], [false, ['id' => 1, 'value' => 'Great Cat Fighter'], 'id', '1'], [true, ['id' => 1, 'value' => 'πŸ™πŸ™‚πŸ™'], 'value', 'πŸ™‚'], + [true, ['id' => 1, 'value' => 'ΠŸΡ€ΠΈΠ²Π΅Ρ‚ ΠΌΠΈΡ€'], 'value', ' '], ]; } diff --git a/tests/Reader/IterableHandler/LikeTest.php b/tests/Reader/IterableHandler/LikeTest.php index 0502dc95..4bed7caf 100644 --- a/tests/Reader/IterableHandler/LikeTest.php +++ b/tests/Reader/IterableHandler/LikeTest.php @@ -19,6 +19,7 @@ public static function matchDataProvider(): array [false, ['id' => 1, 'value' => 'Great Cat Fighter'], 'value', 'cat'], [false, ['id' => 1, 'value' => 'Great Cat Fighter'], 'id', '1'], [true, ['id' => 1, 'value' => 'πŸ™πŸ™‚πŸ™'], 'value', 'πŸ™‚'], + [true, ['id' => 1, 'value' => 'ΠŸΡ€ΠΈΠ²Π΅Ρ‚ ΠΌΠΈΡ€'], 'value', ' '], ]; } From 042c38650e30d5033b464c2450d67ef8bd12c13b Mon Sep 17 00:00:00 2001 From: Alexey Rogachev Date: Tue, 2 Apr 2024 12:25:38 +0500 Subject: [PATCH 5/7] Update changelog and readme [skip ci] --- CHANGELOG.md | 2 ++ README.md | 1 + 2 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4912bf20..41a77911 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ `PaginatorInterface::getCurrentPageSize()` and `OffsetPaginator::getTotalItems()` (@vjik) - Chg #165: Simplify `FilterInterface` and `FilterHandlerInterface` (@vjik) - Chg #166: Remove `EqualsEmpty` filter (@vjik) +- Bug #173: Make `Like` filter case-sensitive (@arogachev) +- New #173: Add `ILike` filter (case-insensitive variation of `Like` filter) (@arogachev) ## 1.0.1 January 25, 2023 diff --git a/README.md b/README.md index 0f459ac1..13022ccf 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,7 @@ Filter could be composed with: - `EqualsNull` - `GreaterThan` - `GreaterThanOrEqual` +- `ILike` - `In` - `LessThan` - `LessThanOrEqual` From b4548145698560866e91a02126a13825849c51d6 Mon Sep 17 00:00:00 2001 From: Alexey Rogachev Date: Tue, 2 Apr 2024 12:36:36 +0500 Subject: [PATCH 6/7] Use mb functions again --- composer.json | 1 + src/Reader/Iterable/FilterHandler/ILikeHandler.php | 2 +- src/Reader/Iterable/FilterHandler/LikeHandler.php | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 8cef1c22..cb55fae2 100644 --- a/composer.json +++ b/composer.json @@ -32,6 +32,7 @@ ], "require": { "php": "^8.1", + "ext-mbstring": "*", "yiisoft/arrays": "^3.0" }, "require-dev": { diff --git a/src/Reader/Iterable/FilterHandler/ILikeHandler.php b/src/Reader/Iterable/FilterHandler/ILikeHandler.php index b7d601fd..a6c6b6b3 100644 --- a/src/Reader/Iterable/FilterHandler/ILikeHandler.php +++ b/src/Reader/Iterable/FilterHandler/ILikeHandler.php @@ -27,6 +27,6 @@ public function match(object|array $item, FilterInterface $filter, array $iterab $itemValue = ArrayHelper::getValue($item, $filter->getField()); - return is_string($itemValue) && stripos($itemValue, $filter->getValue()) !== false; + return is_string($itemValue) && mb_stripos($itemValue, $filter->getValue()) !== false; } } diff --git a/src/Reader/Iterable/FilterHandler/LikeHandler.php b/src/Reader/Iterable/FilterHandler/LikeHandler.php index 7dac3e0c..7ab04382 100644 --- a/src/Reader/Iterable/FilterHandler/LikeHandler.php +++ b/src/Reader/Iterable/FilterHandler/LikeHandler.php @@ -27,6 +27,6 @@ public function match(object|array $item, FilterInterface $filter, array $iterab $itemValue = ArrayHelper::getValue($item, $filter->getField()); - return is_string($itemValue) && str_contains($itemValue, $filter->getValue()); + return is_string($itemValue) && mb_strpos($itemValue, $filter->getValue()) !== false; } } From 0c4eb15f77cd6b318fc08c0443ee8e58699f1f50 Mon Sep 17 00:00:00 2001 From: Alexey Rogachev Date: Tue, 2 Apr 2024 12:40:54 +0500 Subject: [PATCH 7/7] Ignore mutants --- src/Reader/Iterable/FilterHandler/ILikeHandler.php | 1 + src/Reader/Iterable/FilterHandler/LikeHandler.php | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Reader/Iterable/FilterHandler/ILikeHandler.php b/src/Reader/Iterable/FilterHandler/ILikeHandler.php index a6c6b6b3..65ff00b1 100644 --- a/src/Reader/Iterable/FilterHandler/ILikeHandler.php +++ b/src/Reader/Iterable/FilterHandler/ILikeHandler.php @@ -27,6 +27,7 @@ public function match(object|array $item, FilterInterface $filter, array $iterab $itemValue = ArrayHelper::getValue($item, $filter->getField()); + /** @infection-ignore-all MBString No suitable test case was found yet. */ return is_string($itemValue) && mb_stripos($itemValue, $filter->getValue()) !== false; } } diff --git a/src/Reader/Iterable/FilterHandler/LikeHandler.php b/src/Reader/Iterable/FilterHandler/LikeHandler.php index 7ab04382..05eb5621 100644 --- a/src/Reader/Iterable/FilterHandler/LikeHandler.php +++ b/src/Reader/Iterable/FilterHandler/LikeHandler.php @@ -27,6 +27,7 @@ public function match(object|array $item, FilterInterface $filter, array $iterab $itemValue = ArrayHelper::getValue($item, $filter->getField()); + /** @infection-ignore-all MBString No suitable test case was found yet. */ return is_string($itemValue) && mb_strpos($itemValue, $filter->getValue()) !== false; } }