From 22c4f412d76daad46178b2da1e703a8fce2d0479 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Wed, 25 Jun 2025 17:22:02 +0300 Subject: [PATCH 1/7] Add value reader to `IterableDataReader` --- src/Reader/Iterable/Context.php | 33 +++++++++++++++++++ .../Iterable/FilterHandler/AllHandler.php | 7 ++-- .../Iterable/FilterHandler/AnyHandler.php | 7 ++-- .../Iterable/FilterHandler/BetweenHandler.php | 6 ++-- .../Iterable/FilterHandler/EqualsHandler.php | 6 ++-- .../FilterHandler/EqualsNullHandler.php | 6 ++-- .../FilterHandler/GreaterThanHandler.php | 6 ++-- .../GreaterThanOrEqualHandler.php | 6 ++-- .../Iterable/FilterHandler/InHandler.php | 6 ++-- .../FilterHandler/LessThanHandler.php | 6 ++-- .../FilterHandler/LessThanOrEqualHandler.php | 6 ++-- .../Iterable/FilterHandler/LikeHandler.php | 6 ++-- .../Iterable/FilterHandler/NotHandler.php | 7 ++-- src/Reader/Iterable/IterableDataReader.php | 28 +++++++++++----- .../IterableFilterHandlerInterface.php | 4 +-- .../Iterable/ValueReader/FlatValueReader.php | 15 +++++++++ .../Iterable/ValueReader/PathValueReader.php | 20 +++++++++++ .../ValueReader/ValueReaderInterface.php | 10 ++++++ .../Iterable/FilterHandler/AllHandlerTest.php | 14 ++++++-- .../Iterable/FilterHandler/AnyHandlerTest.php | 14 ++++++-- .../FilterHandler/BetweenHandlerTest.php | 10 ++++-- .../FilterHandler/EqualsHandlerTest.php | 10 ++++-- .../FilterHandler/EqualsNullHandlerTest.php | 5 ++- .../FilterHandler/GreaterThanHandlerTest.php | 10 ++++-- .../GreaterThanOrEqualHandlerTest.php | 10 ++++-- .../Iterable/FilterHandler/InHandlerTest.php | 6 +++- .../FilterHandler/LessThanHandlerTest.php | 10 ++++-- .../LessThanOrEqualHandlerTest.php | 10 ++++-- .../FilterHandler/LikeHandlerTest.php | 7 ++-- .../Iterable/FilterHandler/NotHandlerTest.php | 14 ++++++-- .../Iterable/IterableDataReaderTest.php | 3 +- .../ReaderWithFilter/ReaderWithInTest.php | 22 +++++++++++++ tests/Support/CustomFilter/DigitalHandler.php | 3 +- 33 files changed, 258 insertions(+), 75 deletions(-) create mode 100644 src/Reader/Iterable/Context.php create mode 100644 src/Reader/Iterable/ValueReader/FlatValueReader.php create mode 100644 src/Reader/Iterable/ValueReader/PathValueReader.php create mode 100644 src/Reader/Iterable/ValueReader/ValueReaderInterface.php diff --git a/src/Reader/Iterable/Context.php b/src/Reader/Iterable/Context.php new file mode 100644 index 00000000..c439096e --- /dev/null +++ b/src/Reader/Iterable/Context.php @@ -0,0 +1,33 @@ + + */ + public readonly array $iterableFilterHandlers, + private readonly ValueReaderInterface $valueReader, + ) { + } + + /** + * @psalm-param class-string $class + */ + public function tryFindFilterHandler(string $class): ?IterableFilterHandlerInterface + { + return $this->iterableFilterHandlers[$class] ?? null; + } + + public function readValue(array|object $item, string $field): mixed + { + return $this->valueReader->read($item, $field); + } +} diff --git a/src/Reader/Iterable/FilterHandler/AllHandler.php b/src/Reader/Iterable/FilterHandler/AllHandler.php index 4fa14f80..70cfefeb 100644 --- a/src/Reader/Iterable/FilterHandler/AllHandler.php +++ b/src/Reader/Iterable/FilterHandler/AllHandler.php @@ -7,6 +7,7 @@ use LogicException; use Yiisoft\Data\Reader\Filter\All; use Yiisoft\Data\Reader\FilterInterface; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; use function sprintf; @@ -22,18 +23,18 @@ public function getFilterClass(): string return All::class; } - public function match(object|array $item, FilterInterface $filter, array $iterableFilterHandlers): bool + public function match(object|array $item, FilterInterface $filter, Context $context): bool { /** @var All $filter */ foreach ($filter->getFilters() as $subFilter) { - $filterHandler = $iterableFilterHandlers[$subFilter::class] ?? null; + $filterHandler = $context->tryFindFilterHandler($subFilter::class); if ($filterHandler === null) { throw new LogicException( sprintf('Filter "%s" is not supported.', $subFilter::class), ); } - if (!$filterHandler->match($item, $subFilter, $iterableFilterHandlers)) { + if (!$filterHandler->match($item, $subFilter, $context)) { return false; } } diff --git a/src/Reader/Iterable/FilterHandler/AnyHandler.php b/src/Reader/Iterable/FilterHandler/AnyHandler.php index 1f5349e2..e1d6966d 100644 --- a/src/Reader/Iterable/FilterHandler/AnyHandler.php +++ b/src/Reader/Iterable/FilterHandler/AnyHandler.php @@ -7,6 +7,7 @@ use LogicException; use Yiisoft\Data\Reader\Filter\Any; use Yiisoft\Data\Reader\FilterInterface; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; use function sprintf; @@ -22,18 +23,18 @@ public function getFilterClass(): string return Any::class; } - public function match(object|array $item, FilterInterface $filter, array $iterableFilterHandlers): bool + public function match(object|array $item, FilterInterface $filter, Context $context): bool { /** @var Any $filter */ foreach ($filter->getFilters() as $subFilter) { - $filterHandler = $iterableFilterHandlers[$subFilter::class] ?? null; + $filterHandler = $context->tryFindFilterHandler($subFilter::class); if ($filterHandler === null) { throw new LogicException( sprintf('Filter "%s" is not supported.', $subFilter::class), ); } - if ($filterHandler->match($item, $subFilter, $iterableFilterHandlers)) { + if ($filterHandler->match($item, $subFilter, $context)) { return true; } } diff --git a/src/Reader/Iterable/FilterHandler/BetweenHandler.php b/src/Reader/Iterable/FilterHandler/BetweenHandler.php index 5d87b94b..8f572714 100644 --- a/src/Reader/Iterable/FilterHandler/BetweenHandler.php +++ b/src/Reader/Iterable/FilterHandler/BetweenHandler.php @@ -5,9 +5,9 @@ namespace Yiisoft\Data\Reader\Iterable\FilterHandler; use DateTimeInterface; -use Yiisoft\Arrays\ArrayHelper; use Yiisoft\Data\Reader\Filter\Between; use Yiisoft\Data\Reader\FilterInterface; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; /** @@ -21,11 +21,11 @@ public function getFilterClass(): string return Between::class; } - public function match(array|object $item, FilterInterface $filter, array $iterableFilterHandlers): bool + public function match(object|array $item, FilterInterface $filter, Context $context): bool { /** @var Between $filter */ - $value = ArrayHelper::getValue($item, $filter->getField()); + $value = $context->readValue($item, $filter->getField()); $min = $filter->getMinValue(); $max = $filter->getMaxValue(); diff --git a/src/Reader/Iterable/FilterHandler/EqualsHandler.php b/src/Reader/Iterable/FilterHandler/EqualsHandler.php index 497c5155..efe68968 100644 --- a/src/Reader/Iterable/FilterHandler/EqualsHandler.php +++ b/src/Reader/Iterable/FilterHandler/EqualsHandler.php @@ -5,9 +5,9 @@ namespace Yiisoft\Data\Reader\Iterable\FilterHandler; use DateTimeInterface; -use Yiisoft\Arrays\ArrayHelper; use Yiisoft\Data\Reader\Filter\Equals; use Yiisoft\Data\Reader\FilterInterface; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; /** @@ -20,11 +20,11 @@ public function getFilterClass(): string return Equals::class; } - public function match(object|array $item, FilterInterface $filter, array $iterableFilterHandlers): bool + public function match(object|array $item, FilterInterface $filter, Context $context): bool { /** @var Equals $filter */ - $itemValue = ArrayHelper::getValue($item, $filter->getField()); + $itemValue = $context->readValue($item, $filter->getField()); $argumentValue = $filter->getValue(); if (!$itemValue instanceof DateTimeInterface) { diff --git a/src/Reader/Iterable/FilterHandler/EqualsNullHandler.php b/src/Reader/Iterable/FilterHandler/EqualsNullHandler.php index 72a82d1c..90c84572 100644 --- a/src/Reader/Iterable/FilterHandler/EqualsNullHandler.php +++ b/src/Reader/Iterable/FilterHandler/EqualsNullHandler.php @@ -4,9 +4,9 @@ namespace Yiisoft\Data\Reader\Iterable\FilterHandler; -use Yiisoft\Arrays\ArrayHelper; use Yiisoft\Data\Reader\Filter\EqualsNull; use Yiisoft\Data\Reader\FilterInterface; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; /** @@ -19,10 +19,10 @@ public function getFilterClass(): string return EqualsNull::class; } - public function match(array|object $item, FilterInterface $filter, array $iterableFilterHandlers): bool + public function match(object|array $item, FilterInterface $filter, Context $context): bool { /** @var EqualsNull $filter */ - return ArrayHelper::getValue($item, $filter->getField()) === null; + return $context->readValue($item, $filter->getField()) === null; } } diff --git a/src/Reader/Iterable/FilterHandler/GreaterThanHandler.php b/src/Reader/Iterable/FilterHandler/GreaterThanHandler.php index 72e36f85..cc185b5b 100644 --- a/src/Reader/Iterable/FilterHandler/GreaterThanHandler.php +++ b/src/Reader/Iterable/FilterHandler/GreaterThanHandler.php @@ -5,9 +5,9 @@ namespace Yiisoft\Data\Reader\Iterable\FilterHandler; use DateTimeInterface; -use Yiisoft\Arrays\ArrayHelper; use Yiisoft\Data\Reader\Filter\GreaterThan; use Yiisoft\Data\Reader\FilterInterface; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; /** @@ -20,11 +20,11 @@ public function getFilterClass(): string return GreaterThan::class; } - public function match(object|array $item, FilterInterface $filter, array $iterableFilterHandlers): bool + public function match(object|array $item, FilterInterface $filter, Context $context): bool { /** @var GreaterThan $filter */ - $itemValue = ArrayHelper::getValue($item, $filter->getField()); + $itemValue = $context->readValue($item, $filter->getField()); $argumentValue = $filter->getValue(); if (!$itemValue instanceof DateTimeInterface) { diff --git a/src/Reader/Iterable/FilterHandler/GreaterThanOrEqualHandler.php b/src/Reader/Iterable/FilterHandler/GreaterThanOrEqualHandler.php index 5e37b581..c39ac511 100644 --- a/src/Reader/Iterable/FilterHandler/GreaterThanOrEqualHandler.php +++ b/src/Reader/Iterable/FilterHandler/GreaterThanOrEqualHandler.php @@ -5,9 +5,9 @@ namespace Yiisoft\Data\Reader\Iterable\FilterHandler; use DateTimeInterface; -use Yiisoft\Arrays\ArrayHelper; use Yiisoft\Data\Reader\Filter\GreaterThanOrEqual; use Yiisoft\Data\Reader\FilterInterface; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; /** @@ -21,11 +21,11 @@ public function getFilterClass(): string return GreaterThanOrEqual::class; } - public function match(object|array $item, FilterInterface $filter, array $iterableFilterHandlers): bool + public function match(object|array $item, FilterInterface $filter, Context $context): bool { /** @var GreaterThanOrEqual $filter */ - $itemValue = ArrayHelper::getValue($item, $filter->getField()); + $itemValue = $context->readValue($item, $filter->getField()); $argumentValue = $filter->getValue(); if (!$itemValue instanceof DateTimeInterface) { diff --git a/src/Reader/Iterable/FilterHandler/InHandler.php b/src/Reader/Iterable/FilterHandler/InHandler.php index 48a6f47c..4d4a67fe 100644 --- a/src/Reader/Iterable/FilterHandler/InHandler.php +++ b/src/Reader/Iterable/FilterHandler/InHandler.php @@ -4,9 +4,9 @@ namespace Yiisoft\Data\Reader\Iterable\FilterHandler; -use Yiisoft\Arrays\ArrayHelper; use Yiisoft\Data\Reader\Filter\In; use Yiisoft\Data\Reader\FilterInterface; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; use function in_array; @@ -21,11 +21,11 @@ public function getFilterClass(): string return In::class; } - public function match(object|array $item, FilterInterface $filter, array $iterableFilterHandlers): bool + public function match(object|array $item, FilterInterface $filter, Context $context): bool { /** @var In $filter */ - $itemValue = ArrayHelper::getValue($item, $filter->getField()); + $itemValue = $context->readValue($item, $filter->getField()); $argumentValue = $filter->getValues(); return in_array($itemValue, $argumentValue); diff --git a/src/Reader/Iterable/FilterHandler/LessThanHandler.php b/src/Reader/Iterable/FilterHandler/LessThanHandler.php index b48d41c3..011a2d2f 100644 --- a/src/Reader/Iterable/FilterHandler/LessThanHandler.php +++ b/src/Reader/Iterable/FilterHandler/LessThanHandler.php @@ -5,9 +5,9 @@ namespace Yiisoft\Data\Reader\Iterable\FilterHandler; use DateTimeInterface; -use Yiisoft\Arrays\ArrayHelper; use Yiisoft\Data\Reader\Filter\LessThan; use Yiisoft\Data\Reader\FilterInterface; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; /** @@ -20,11 +20,11 @@ public function getFilterClass(): string return LessThan::class; } - public function match(object|array $item, FilterInterface $filter, array $iterableFilterHandlers): bool + public function match(object|array $item, FilterInterface $filter, Context $context): bool { /** @var LessThan $filter */ - $itemValue = ArrayHelper::getValue($item, $filter->getField()); + $itemValue = $context->readValue($item, $filter->getField()); $argumentValue = $filter->getValue(); if (!$itemValue instanceof DateTimeInterface) { diff --git a/src/Reader/Iterable/FilterHandler/LessThanOrEqualHandler.php b/src/Reader/Iterable/FilterHandler/LessThanOrEqualHandler.php index 14047393..5ddd9f62 100644 --- a/src/Reader/Iterable/FilterHandler/LessThanOrEqualHandler.php +++ b/src/Reader/Iterable/FilterHandler/LessThanOrEqualHandler.php @@ -5,9 +5,9 @@ namespace Yiisoft\Data\Reader\Iterable\FilterHandler; use DateTimeInterface; -use Yiisoft\Arrays\ArrayHelper; use Yiisoft\Data\Reader\Filter\LessThanOrEqual; use Yiisoft\Data\Reader\FilterInterface; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; /** @@ -21,11 +21,11 @@ public function getFilterClass(): string return LessThanOrEqual::class; } - public function match(object|array $item, FilterInterface $filter, array $iterableFilterHandlers): bool + public function match(object|array $item, FilterInterface $filter, Context $context): bool { /** @var LessThanOrEqual $filter */ - $itemValue = ArrayHelper::getValue($item, $filter->getField()); + $itemValue = $context->readValue($item, $filter->getField()); $argumentValue = $filter->getValue(); if (!$itemValue instanceof DateTimeInterface) { diff --git a/src/Reader/Iterable/FilterHandler/LikeHandler.php b/src/Reader/Iterable/FilterHandler/LikeHandler.php index 6e84b3d9..d0f0d024 100644 --- a/src/Reader/Iterable/FilterHandler/LikeHandler.php +++ b/src/Reader/Iterable/FilterHandler/LikeHandler.php @@ -4,9 +4,9 @@ namespace Yiisoft\Data\Reader\Iterable\FilterHandler; -use Yiisoft\Arrays\ArrayHelper; use Yiisoft\Data\Reader\Filter\Like; use Yiisoft\Data\Reader\FilterInterface; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; use function is_string; @@ -21,11 +21,11 @@ public function getFilterClass(): string return Like::class; } - public function match(object|array $item, FilterInterface $filter, array $iterableFilterHandlers): bool + public function match(object|array $item, FilterInterface $filter, Context $context): bool { /** @var Like $filter */ - $itemValue = ArrayHelper::getValue($item, $filter->getField()); + $itemValue = $context->readValue($item, $filter->getField()); if (!is_string($itemValue)) { return false; } diff --git a/src/Reader/Iterable/FilterHandler/NotHandler.php b/src/Reader/Iterable/FilterHandler/NotHandler.php index 3eaa6025..6a55515d 100644 --- a/src/Reader/Iterable/FilterHandler/NotHandler.php +++ b/src/Reader/Iterable/FilterHandler/NotHandler.php @@ -7,6 +7,7 @@ use LogicException; use Yiisoft\Data\Reader\Filter\Not; use Yiisoft\Data\Reader\FilterInterface; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; use function sprintf; @@ -21,16 +22,16 @@ public function getFilterClass(): string return Not::class; } - public function match(array|object $item, FilterInterface $filter, array $iterableFilterHandlers): bool + public function match(object|array $item, FilterInterface $filter, Context $context): bool { /** @var Not $filter */ $subFilter = $filter->getFilter(); - $filterHandler = $iterableFilterHandlers[$subFilter::class] ?? null; + $filterHandler = $context->tryFindFilterHandler($subFilter::class); if ($filterHandler === null) { throw new LogicException(sprintf('Filter "%s" is not supported.', $subFilter::class)); } - return !$filterHandler->match($item, $subFilter, $iterableFilterHandlers); + return !$filterHandler->match($item, $subFilter, $context); } } diff --git a/src/Reader/Iterable/IterableDataReader.php b/src/Reader/Iterable/IterableDataReader.php index 54cb77de..d2a39aa3 100644 --- a/src/Reader/Iterable/IterableDataReader.php +++ b/src/Reader/Iterable/IterableDataReader.php @@ -25,6 +25,8 @@ use Yiisoft\Data\Reader\Iterable\FilterHandler\LessThanOrEqualHandler; use Yiisoft\Data\Reader\Iterable\FilterHandler\LikeHandler; use Yiisoft\Data\Reader\Iterable\FilterHandler\NotHandler; +use Yiisoft\Data\Reader\Iterable\ValueReader\FlatValueReader; +use Yiisoft\Data\Reader\Iterable\ValueReader\ValueReaderInterface; use Yiisoft\Data\Reader\Sort; use function array_merge; @@ -61,15 +63,19 @@ final class IterableDataReader implements DataReaderInterface /** * @psalm-var array */ - private array $iterableFilterHandlers; + private array $coreFilterHandlers; + + private Context $context; /** * @param iterable $data Data to iterate. * @psalm-param iterable $data */ - public function __construct(private iterable $data) - { - $this->iterableFilterHandlers = $this->prepareFilterHandlers([ + public function __construct( + private readonly iterable $data, + private readonly ValueReaderInterface $valueReader = new FlatValueReader(), + ) { + $this->coreFilterHandlers = $this->prepareFilterHandlers([ new AllHandler(), new AnyHandler(), new BetweenHandler(), @@ -83,6 +89,7 @@ public function __construct(private iterable $data) new LikeHandler(), new NotHandler(), ]); + $this->context = new Context($this->coreFilterHandlers, $this->valueReader); } /** @@ -91,9 +98,12 @@ public function __construct(private iterable $data) public function withAddedFilterHandlers(FilterHandlerInterface ...$filterHandlers): static { $new = clone $this; - $new->iterableFilterHandlers = array_merge( - $this->iterableFilterHandlers, - $this->prepareFilterHandlers($filterHandlers) + $new->context = new Context( + array_merge( + $this->coreFilterHandlers, + $this->prepareFilterHandlers($filterHandlers), + ), + $this->valueReader, ); return $new; } @@ -222,13 +232,13 @@ private function internalRead(bool $useLimitAndOffset): array */ private function matchFilter(array|object $item, FilterInterface $filter): bool { - $handler = $this->iterableFilterHandlers[$filter::class] ?? null; + $handler = $this->context->tryFindFilterHandler($filter::class); if ($handler === null) { throw new RuntimeException(sprintf('Filter "%s" is not supported.', $filter::class)); } - return $handler->match($item, $filter, $this->iterableFilterHandlers); + return $handler->match($item, $filter, $this->context); } /** diff --git a/src/Reader/Iterable/IterableFilterHandlerInterface.php b/src/Reader/Iterable/IterableFilterHandlerInterface.php index fb3d8961..0e9348d5 100644 --- a/src/Reader/Iterable/IterableFilterHandlerInterface.php +++ b/src/Reader/Iterable/IterableFilterHandlerInterface.php @@ -19,10 +19,8 @@ interface IterableFilterHandlerInterface extends FilterHandlerInterface * * @param array|object $item Item to check. * @param FilterInterface $filter Matched filter. - * @param IterableFilterHandlerInterface[] $iterableFilterHandlers Iterable filter handlers to use in case it is - * a group filter. * * @return bool Whether item matches the filter. */ - public function match(array|object $item, FilterInterface $filter, array $iterableFilterHandlers): bool; + public function match(array|object $item, FilterInterface $filter, Context $context): bool; } diff --git a/src/Reader/Iterable/ValueReader/FlatValueReader.php b/src/Reader/Iterable/ValueReader/FlatValueReader.php new file mode 100644 index 00000000..2ae3a1f0 --- /dev/null +++ b/src/Reader/Iterable/ValueReader/FlatValueReader.php @@ -0,0 +1,15 @@ +delimiter); + } +} diff --git a/src/Reader/Iterable/ValueReader/ValueReaderInterface.php b/src/Reader/Iterable/ValueReader/ValueReaderInterface.php new file mode 100644 index 00000000..56d644f0 --- /dev/null +++ b/src/Reader/Iterable/ValueReader/ValueReaderInterface.php @@ -0,0 +1,10 @@ + 45, ]; - $this->assertSame($expected, $handler->match($item, new All(...$filters), $filterHandlers)); + $context = new Context($filterHandlers, new FlatValueReader()); + + $this->assertSame($expected, $handler->match($item, new All(...$filters), $context)); } public function testMatchFailIfFilterOperatorIsNotSupported(): void { + $handler = new AllHandler(); + $item = ['id' => 1]; + $filter = new All(new FilterWithoutHandler()); + $context = new Context([], new FlatValueReader()); + $this->expectException(LogicException::class); $this->expectExceptionMessage('Filter "' . FilterWithoutHandler::class . '" is not supported.'); - - (new AllHandler())->match(['id' => 1], new All(new FilterWithoutHandler()), []); + $handler->match($item, $filter, $context); } } diff --git a/tests/Reader/Iterable/FilterHandler/AnyHandlerTest.php b/tests/Reader/Iterable/FilterHandler/AnyHandlerTest.php index c3a678b2..deaed0d1 100644 --- a/tests/Reader/Iterable/FilterHandler/AnyHandlerTest.php +++ b/tests/Reader/Iterable/FilterHandler/AnyHandlerTest.php @@ -10,10 +10,12 @@ use Yiisoft\Data\Reader\Filter\Equals; use Yiisoft\Data\Reader\Filter\GreaterThanOrEqual; use Yiisoft\Data\Reader\Filter\LessThanOrEqual; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\FilterHandler\AnyHandler; use Yiisoft\Data\Reader\Iterable\FilterHandler\EqualsHandler; use Yiisoft\Data\Reader\Iterable\FilterHandler\GreaterThanOrEqualHandler; use Yiisoft\Data\Reader\Iterable\FilterHandler\LessThanOrEqualHandler; +use Yiisoft\Data\Reader\Iterable\ValueReader\FlatValueReader; use Yiisoft\Data\Tests\Support\CustomFilter\FilterWithoutHandler; use Yiisoft\Data\Tests\TestCase; @@ -70,14 +72,20 @@ public function testMatch(bool $expected, array $filters, array $filterHandlers) 'value' => 45, ]; - $this->assertSame($expected, $handler->match($item, new Any(...$filters), $filterHandlers)); + $context = new Context($filterHandlers, new FlatValueReader()); + + $this->assertSame($expected, $handler->match($item, new Any(...$filters), $context)); } public function testMatchFailIfFilterOperatorIsNotSupported(): void { + $handler = new AnyHandler(); + $item = ['id' => 1]; + $filter = new Any(new FilterWithoutHandler()); + $context = new Context([], new FlatValueReader()); + $this->expectException(LogicException::class); $this->expectExceptionMessage('Filter "' . FilterWithoutHandler::class . '" is not supported.'); - - (new AnyHandler())->match(['id' => 1], new Any(new FilterWithoutHandler()), []); + $handler->match($item, $filter, $context); } } diff --git a/tests/Reader/Iterable/FilterHandler/BetweenHandlerTest.php b/tests/Reader/Iterable/FilterHandler/BetweenHandlerTest.php index ed02b665..a0fa493c 100644 --- a/tests/Reader/Iterable/FilterHandler/BetweenHandlerTest.php +++ b/tests/Reader/Iterable/FilterHandler/BetweenHandlerTest.php @@ -7,8 +7,10 @@ use DateTimeImmutable; use PHPUnit\Framework\Attributes\DataProvider; use Yiisoft\Data\Reader\Filter\Between; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\FilterHandler\BetweenHandler; use Yiisoft\Data\Reader\Iterable\IterableDataReader; +use Yiisoft\Data\Reader\Iterable\ValueReader\FlatValueReader; use Yiisoft\Data\Tests\Support\Car; use Yiisoft\Data\Tests\TestCase; @@ -35,7 +37,9 @@ public function testMatchScalar(bool $expected, Between $filter): void 'value' => 45, ]; - $this->assertSame($expected, $handler->match($item, $filter, [])); + $context = new Context([], new FlatValueReader()); + + $this->assertSame($expected, $handler->match($item, $filter, $context)); } public static function matchDateTimeInterfaceDataProvider(): array @@ -59,7 +63,9 @@ public function testMatchDateTimeInterface(bool $expected, DateTimeImmutable $fr 'value' => new DateTimeImmutable('2022-02-22 16:00:45'), ]; - $this->assertSame($expected, $processor->match($item, new Between('value', $from, $to), [])); + $context = new Context([], new FlatValueReader()); + + $this->assertSame($expected, $processor->match($item, new Between('value', $from, $to), $context)); } public function testObjectWithGetters(): void diff --git a/tests/Reader/Iterable/FilterHandler/EqualsHandlerTest.php b/tests/Reader/Iterable/FilterHandler/EqualsHandlerTest.php index d0a11928..e770b6b7 100644 --- a/tests/Reader/Iterable/FilterHandler/EqualsHandlerTest.php +++ b/tests/Reader/Iterable/FilterHandler/EqualsHandlerTest.php @@ -7,8 +7,10 @@ use DateTimeImmutable; use PHPUnit\Framework\Attributes\DataProvider; use Yiisoft\Data\Reader\Filter\Equals; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\FilterHandler\EqualsHandler; use Yiisoft\Data\Reader\Iterable\IterableDataReader; +use Yiisoft\Data\Reader\Iterable\ValueReader\FlatValueReader; use Yiisoft\Data\Tests\Support\Car; use Yiisoft\Data\Tests\TestCase; @@ -34,7 +36,9 @@ public function testMatchScalar(bool $expected, mixed $value): void 'value' => 45, ]; - $this->assertSame($expected, $processor->match($item, new Equals('value', $value), [])); + $context = new Context([], new FlatValueReader()); + + $this->assertSame($expected, $processor->match($item, new Equals('value', $value), $context)); } public static function matchDateTimeInterfaceDataProvider(): array @@ -56,7 +60,9 @@ public function testMatchDateTimeInterface(bool $expected, DateTimeImmutable $va 'value' => new DateTimeImmutable('2022-02-22 16:00:45'), ]; - $this->assertSame($expected, $handler->match($item, new Equals('value', $value), [])); + $context = new Context([], new FlatValueReader()); + + $this->assertSame($expected, $handler->match($item, new Equals('value', $value), $context)); } public function testObjectWithGetters(): void diff --git a/tests/Reader/Iterable/FilterHandler/EqualsNullHandlerTest.php b/tests/Reader/Iterable/FilterHandler/EqualsNullHandlerTest.php index f04ca307..d35b1f1a 100644 --- a/tests/Reader/Iterable/FilterHandler/EqualsNullHandlerTest.php +++ b/tests/Reader/Iterable/FilterHandler/EqualsNullHandlerTest.php @@ -6,8 +6,10 @@ use PHPUnit\Framework\Attributes\DataProvider; use Yiisoft\Data\Reader\Filter\EqualsNull; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\FilterHandler\EqualsNullHandler; use Yiisoft\Data\Reader\Iterable\IterableDataReader; +use Yiisoft\Data\Reader\Iterable\ValueReader\FlatValueReader; use Yiisoft\Data\Tests\Support\Car; use Yiisoft\Data\Tests\TestCase; @@ -30,7 +32,8 @@ public static function matchDataProvider(): array #[DataProvider('matchDataProvider')] public function testMatch(bool $expected, array $item): void { - $this->assertSame($expected, (new EqualsNullHandler())->match($item, new EqualsNull('value'), [])); + $context = new Context([], new FlatValueReader()); + $this->assertSame($expected, (new EqualsNullHandler())->match($item, new EqualsNull('value'), $context)); } public function testObjectWithGetters(): void diff --git a/tests/Reader/Iterable/FilterHandler/GreaterThanHandlerTest.php b/tests/Reader/Iterable/FilterHandler/GreaterThanHandlerTest.php index 16ccd59a..1d3764d0 100644 --- a/tests/Reader/Iterable/FilterHandler/GreaterThanHandlerTest.php +++ b/tests/Reader/Iterable/FilterHandler/GreaterThanHandlerTest.php @@ -7,7 +7,9 @@ use DateTimeImmutable; use PHPUnit\Framework\Attributes\DataProvider; use Yiisoft\Data\Reader\Filter\GreaterThan; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\FilterHandler\GreaterThanHandler; +use Yiisoft\Data\Reader\Iterable\ValueReader\FlatValueReader; use Yiisoft\Data\Tests\TestCase; final class GreaterThanHandlerTest extends TestCase @@ -32,7 +34,9 @@ public function testMatchScalar(bool $expected, mixed $value): void 'value' => 45, ]; - $this->assertSame($expected, $handler->match($item, new GreaterThan('value', $value), [])); + $context = new Context([], new FlatValueReader()); + + $this->assertSame($expected, $handler->match($item, new GreaterThan('value', $value), $context)); } public static function matchDateTimeInterfaceDataProvider(): array @@ -54,6 +58,8 @@ public function testMatchDateTimeInterface(bool $expected, DateTimeImmutable $va 'value' => new DateTimeImmutable('2022-02-22 16:00:45'), ]; - $this->assertSame($expected, $handler->match($item, new GreaterThan('value', $value), [])); + $context = new Context([], new FlatValueReader()); + + $this->assertSame($expected, $handler->match($item, new GreaterThan('value', $value), $context)); } } diff --git a/tests/Reader/Iterable/FilterHandler/GreaterThanOrEqualHandlerTest.php b/tests/Reader/Iterable/FilterHandler/GreaterThanOrEqualHandlerTest.php index ea2305f0..adf442ed 100644 --- a/tests/Reader/Iterable/FilterHandler/GreaterThanOrEqualHandlerTest.php +++ b/tests/Reader/Iterable/FilterHandler/GreaterThanOrEqualHandlerTest.php @@ -7,7 +7,9 @@ use DateTimeImmutable; use PHPUnit\Framework\Attributes\DataProvider; use Yiisoft\Data\Reader\Filter\GreaterThanOrEqual; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\FilterHandler\GreaterThanOrEqualHandler; +use Yiisoft\Data\Reader\Iterable\ValueReader\FlatValueReader; use Yiisoft\Data\Tests\TestCase; final class GreaterThanOrEqualHandlerTest extends TestCase @@ -32,7 +34,9 @@ public function testMatchScalar(bool $expected, mixed $value): void 'value' => 45, ]; - $this->assertSame($expected, $processor->match($item, new GreaterThanOrEqual('value', $value), [])); + $context = new Context([], new FlatValueReader()); + + $this->assertSame($expected, $processor->match($item, new GreaterThanOrEqual('value', $value), $context)); } public static function matchDateTimeInterfaceDataProvider(): array @@ -54,6 +58,8 @@ public function testMatchDateTimeInterface(bool $expected, DateTimeImmutable $va 'value' => new DateTimeImmutable('2022-02-22 16:00:45'), ]; - $this->assertSame($expected, $processor->match($item, new GreaterThanOrEqual('value', $value), [])); + $context = new Context([], new FlatValueReader()); + + $this->assertSame($expected, $processor->match($item, new GreaterThanOrEqual('value', $value), $context)); } } diff --git a/tests/Reader/Iterable/FilterHandler/InHandlerTest.php b/tests/Reader/Iterable/FilterHandler/InHandlerTest.php index b365abbc..ece4ea2b 100644 --- a/tests/Reader/Iterable/FilterHandler/InHandlerTest.php +++ b/tests/Reader/Iterable/FilterHandler/InHandlerTest.php @@ -6,7 +6,9 @@ use PHPUnit\Framework\Attributes\DataProvider; use Yiisoft\Data\Reader\Filter\In; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\FilterHandler\InHandler; +use Yiisoft\Data\Reader\Iterable\ValueReader\FlatValueReader; use Yiisoft\Data\Tests\TestCase; final class InHandlerTest extends TestCase @@ -30,6 +32,8 @@ public function testMatch(bool $expected, array $value): void 'value' => 45, ]; - $this->assertSame($expected, $handler->match($item, new In('value', $value), [])); + $context = new Context([], new FlatValueReader()); + + $this->assertSame($expected, $handler->match($item, new In('value', $value), $context)); } } diff --git a/tests/Reader/Iterable/FilterHandler/LessThanHandlerTest.php b/tests/Reader/Iterable/FilterHandler/LessThanHandlerTest.php index 1f1853c1..db3fee12 100644 --- a/tests/Reader/Iterable/FilterHandler/LessThanHandlerTest.php +++ b/tests/Reader/Iterable/FilterHandler/LessThanHandlerTest.php @@ -7,7 +7,9 @@ use DateTimeImmutable; use PHPUnit\Framework\Attributes\DataProvider; use Yiisoft\Data\Reader\Filter\LessThan; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\FilterHandler\LessThanHandler; +use Yiisoft\Data\Reader\Iterable\ValueReader\FlatValueReader; use Yiisoft\Data\Tests\TestCase; final class LessThanHandlerTest extends TestCase @@ -32,7 +34,9 @@ public function testMatchScalar(bool $expected, mixed $value): void 'value' => 45, ]; - $this->assertSame($expected, $processor->match($item, new LessThan('value', $value), [])); + $context = new Context([], new FlatValueReader()); + + $this->assertSame($expected, $processor->match($item, new LessThan('value', $value), $context)); } public static function matchDateTimeInterfaceDataProvider(): array @@ -54,6 +58,8 @@ public function testMatchDateTimeInterface(bool $expected, DateTimeImmutable $va 'value' => new DateTimeImmutable('2022-02-22 16:00:45'), ]; - $this->assertSame($expected, $handler->match($item, new LessThan('value', $value), [])); + $context = new Context([], new FlatValueReader()); + + $this->assertSame($expected, $handler->match($item, new LessThan('value', $value), $context)); } } diff --git a/tests/Reader/Iterable/FilterHandler/LessThanOrEqualHandlerTest.php b/tests/Reader/Iterable/FilterHandler/LessThanOrEqualHandlerTest.php index 64783a0b..3c39cd01 100644 --- a/tests/Reader/Iterable/FilterHandler/LessThanOrEqualHandlerTest.php +++ b/tests/Reader/Iterable/FilterHandler/LessThanOrEqualHandlerTest.php @@ -7,7 +7,9 @@ use DateTimeImmutable; use PHPUnit\Framework\Attributes\DataProvider; use Yiisoft\Data\Reader\Filter\LessThanOrEqual; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\FilterHandler\LessThanOrEqualHandler; +use Yiisoft\Data\Reader\Iterable\ValueReader\FlatValueReader; use Yiisoft\Data\Tests\TestCase; final class LessThanOrEqualHandlerTest extends TestCase @@ -32,7 +34,9 @@ public function testMatchScalar(bool $expected, mixed $value): void 'value' => 45, ]; - $this->assertSame($expected, $handler->match($item, new LessThanOrEqual('value', $value), [])); + $context = new Context([], new FlatValueReader()); + + $this->assertSame($expected, $handler->match($item, new LessThanOrEqual('value', $value), $context)); } public static function matchDateTimeInterfaceDataProvider(): array @@ -54,6 +58,8 @@ public function testMatchDateTimeInterface(bool $expected, DateTimeImmutable $va 'value' => new DateTimeImmutable('2022-02-22 16:00:45'), ]; - $this->assertSame($expected, $handler->match($item, new LessThanOrEqual('value', $value), [])); + $context = new Context([], new FlatValueReader()); + + $this->assertSame($expected, $handler->match($item, new LessThanOrEqual('value', $value), $context)); } } diff --git a/tests/Reader/Iterable/FilterHandler/LikeHandlerTest.php b/tests/Reader/Iterable/FilterHandler/LikeHandlerTest.php index dc4a889d..0e16b826 100644 --- a/tests/Reader/Iterable/FilterHandler/LikeHandlerTest.php +++ b/tests/Reader/Iterable/FilterHandler/LikeHandlerTest.php @@ -6,7 +6,9 @@ use PHPUnit\Framework\Attributes\DataProvider; use Yiisoft\Data\Reader\Filter\Like; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\FilterHandler\LikeHandler; +use Yiisoft\Data\Reader\Iterable\ValueReader\FlatValueReader; use Yiisoft\Data\Tests\TestCase; final class LikeHandlerTest extends TestCase @@ -42,7 +44,8 @@ public static function matchDataProvider(): array #[DataProvider('matchDataProvider')] public function testMatch(bool $expected, array $item, string $field, string $value, ?bool $caseSensitive): void { - $processor = new LikeHandler(); - $this->assertSame($expected, $processor->match($item, new Like($field, $value, $caseSensitive), [])); + $filterHandler = new LikeHandler(); + $context = new Context([], new FlatValueReader()); + $this->assertSame($expected, $filterHandler->match($item, new Like($field, $value, $caseSensitive), $context)); } } diff --git a/tests/Reader/Iterable/FilterHandler/NotHandlerTest.php b/tests/Reader/Iterable/FilterHandler/NotHandlerTest.php index 082a48fd..bce556d4 100644 --- a/tests/Reader/Iterable/FilterHandler/NotHandlerTest.php +++ b/tests/Reader/Iterable/FilterHandler/NotHandlerTest.php @@ -9,8 +9,10 @@ use Yiisoft\Data\Reader\Filter\Equals; use Yiisoft\Data\Reader\Filter\Not; use Yiisoft\Data\Reader\FilterInterface; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\FilterHandler\EqualsHandler; use Yiisoft\Data\Reader\Iterable\FilterHandler\NotHandler; +use Yiisoft\Data\Reader\Iterable\ValueReader\FlatValueReader; use Yiisoft\Data\Tests\Support\CustomFilter\FilterWithoutHandler; use Yiisoft\Data\Tests\TestCase; @@ -36,14 +38,20 @@ public function testMatch(bool $expected, FilterInterface $filter, array $filter 'value' => 45, ]; - $this->assertSame($expected, $processor->match($item, new Not($filter), $filterHandlers)); + $context = new Context($filterHandlers, new FlatValueReader()); + + $this->assertSame($expected, $processor->match($item, new Not($filter), $context)); } public function testMatchFailIfFilterOperatorIsNotSupported(): void { + $handler = new NotHandler(); + $item = ['id' => 1]; + $filter = new Not(new FilterWithoutHandler()); + $context = new Context([], new FlatValueReader()); + $this->expectException(LogicException::class); $this->expectExceptionMessage('Filter "' . FilterWithoutHandler::class . '" is not supported.'); - - (new NotHandler())->match(['id' => 1], new Not(new FilterWithoutHandler()), []); + $handler->match($item, $filter, $context); } } diff --git a/tests/Reader/Iterable/IterableDataReaderTest.php b/tests/Reader/Iterable/IterableDataReaderTest.php index 7f478d46..9234ae03 100644 --- a/tests/Reader/Iterable/IterableDataReaderTest.php +++ b/tests/Reader/Iterable/IterableDataReaderTest.php @@ -21,6 +21,7 @@ use Yiisoft\Data\Reader\Filter\Not; use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\IterableDataReader; use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; use Yiisoft\Data\Reader\Sort; @@ -427,7 +428,7 @@ public function getFilterClass(): string public function match( array|object $item, FilterInterface $filter, - array $iterableFilterHandlers + Context $context, ): bool { /** @var Equals $filter */ return $item[$filter->getField()] === 2; diff --git a/tests/Reader/Iterable/ReaderWithFilter/ReaderWithInTest.php b/tests/Reader/Iterable/ReaderWithFilter/ReaderWithInTest.php index 67a49428..d2b07f64 100644 --- a/tests/Reader/Iterable/ReaderWithFilter/ReaderWithInTest.php +++ b/tests/Reader/Iterable/ReaderWithFilter/ReaderWithInTest.php @@ -4,9 +4,31 @@ namespace Yiisoft\Data\Tests\Reader\Iterable\ReaderWithFilter; +use Yiisoft\Data\Reader\Filter\In; +use Yiisoft\Data\Reader\Iterable\IterableDataReader; +use Yiisoft\Data\Reader\Iterable\ValueReader\PathValueReader; use Yiisoft\Data\Tests\Common\Reader\ReaderWithFilter\BaseReaderWithInTestCase; +use function PHPUnit\Framework\assertSame; + final class ReaderWithInTest extends BaseReaderWithInTestCase { use ReaderTrait; + + public function testNested(): void + { + $row1 = ['id' => 1, 'person' => ['name' => 'John', 'age' => 30]]; + $row2 = ['id' => 2, 'person' => ['name' => 'Jane', 'age' => 25]]; + $row3 = ['id' => 3, 'person' => ['name' => 'Doe', 'age' => 40]]; + $reader = new IterableDataReader( + [$row1, $row2, $row3], + new PathValueReader(), + ); + + $filter = new In('person.name', ['John', 'Jane']); + + $result = $reader->withFilter($filter)->read(); + + assertSame([$row1, $row2], $result); + } } diff --git a/tests/Support/CustomFilter/DigitalHandler.php b/tests/Support/CustomFilter/DigitalHandler.php index 033cd33c..74b02d8d 100644 --- a/tests/Support/CustomFilter/DigitalHandler.php +++ b/tests/Support/CustomFilter/DigitalHandler.php @@ -6,6 +6,7 @@ use Yiisoft\Arrays\ArrayHelper; use Yiisoft\Data\Reader\FilterInterface; +use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; final class DigitalHandler implements IterableFilterHandlerInterface @@ -15,7 +16,7 @@ public function getFilterClass(): string return Digital::class; } - public function match(object|array $item, FilterInterface $filter, array $iterableFilterHandlers): bool + public function match(object|array $item, FilterInterface $filter, Context $context): bool { /** @var Digital $filter */ return ctype_digit((string) ArrayHelper::getValue($item, $filter->field)); From df36fb457b1f22c8b813c0e4bf5d36685054da0a Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Thu, 26 Jun 2025 13:51:20 +0300 Subject: [PATCH 2/7] improve --- src/Reader/Iterable/Context.php | 10 ++++++++-- src/Reader/Iterable/FilterHandler/AllHandler.php | 10 +--------- src/Reader/Iterable/FilterHandler/AnyHandler.php | 10 +--------- src/Reader/Iterable/FilterHandler/NotHandler.php | 8 +------- src/Reader/Iterable/IterableDataReader.php | 8 +------- tests/Reader/Iterable/IterableDataReaderTest.php | 3 ++- 6 files changed, 14 insertions(+), 35 deletions(-) diff --git a/src/Reader/Iterable/Context.php b/src/Reader/Iterable/Context.php index c439096e..5810e7e1 100644 --- a/src/Reader/Iterable/Context.php +++ b/src/Reader/Iterable/Context.php @@ -4,9 +4,12 @@ namespace Yiisoft\Data\Reader\Iterable; +use LogicException; use Yiisoft\Data\Reader\FilterInterface; use Yiisoft\Data\Reader\Iterable\ValueReader\ValueReaderInterface; +use function sprintf; + final class Context { public function __construct( @@ -21,9 +24,12 @@ public function __construct( /** * @psalm-param class-string $class */ - public function tryFindFilterHandler(string $class): ?IterableFilterHandlerInterface + public function getFilterHandler(string $class): IterableFilterHandlerInterface { - return $this->iterableFilterHandlers[$class] ?? null; + return $this->iterableFilterHandlers[$class] + ?? throw new LogicException( + sprintf('Filter "%s" is not supported.', $class), + ); } public function readValue(array|object $item, string $field): mixed diff --git a/src/Reader/Iterable/FilterHandler/AllHandler.php b/src/Reader/Iterable/FilterHandler/AllHandler.php index 70cfefeb..b13ddce2 100644 --- a/src/Reader/Iterable/FilterHandler/AllHandler.php +++ b/src/Reader/Iterable/FilterHandler/AllHandler.php @@ -4,14 +4,11 @@ namespace Yiisoft\Data\Reader\Iterable\FilterHandler; -use LogicException; use Yiisoft\Data\Reader\Filter\All; use Yiisoft\Data\Reader\FilterInterface; use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; -use function sprintf; - /** * `All` iterable filter handler allows combining multiple sub-filters. * The filter matches only if all the sub-filters match. @@ -28,12 +25,7 @@ public function match(object|array $item, FilterInterface $filter, Context $cont /** @var All $filter */ foreach ($filter->getFilters() as $subFilter) { - $filterHandler = $context->tryFindFilterHandler($subFilter::class); - if ($filterHandler === null) { - throw new LogicException( - sprintf('Filter "%s" is not supported.', $subFilter::class), - ); - } + $filterHandler = $context->getFilterHandler($subFilter::class); if (!$filterHandler->match($item, $subFilter, $context)) { return false; } diff --git a/src/Reader/Iterable/FilterHandler/AnyHandler.php b/src/Reader/Iterable/FilterHandler/AnyHandler.php index e1d6966d..4657762e 100644 --- a/src/Reader/Iterable/FilterHandler/AnyHandler.php +++ b/src/Reader/Iterable/FilterHandler/AnyHandler.php @@ -4,14 +4,11 @@ namespace Yiisoft\Data\Reader\Iterable\FilterHandler; -use LogicException; use Yiisoft\Data\Reader\Filter\Any; use Yiisoft\Data\Reader\FilterInterface; use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; -use function sprintf; - /** * `Any` iterable filter handler allows combining multiple sub-filters. * The filter matches if any of the sub-filters match. @@ -28,12 +25,7 @@ public function match(object|array $item, FilterInterface $filter, Context $cont /** @var Any $filter */ foreach ($filter->getFilters() as $subFilter) { - $filterHandler = $context->tryFindFilterHandler($subFilter::class); - if ($filterHandler === null) { - throw new LogicException( - sprintf('Filter "%s" is not supported.', $subFilter::class), - ); - } + $filterHandler = $context->getFilterHandler($subFilter::class); if ($filterHandler->match($item, $subFilter, $context)) { return true; } diff --git a/src/Reader/Iterable/FilterHandler/NotHandler.php b/src/Reader/Iterable/FilterHandler/NotHandler.php index 6a55515d..a65b7f74 100644 --- a/src/Reader/Iterable/FilterHandler/NotHandler.php +++ b/src/Reader/Iterable/FilterHandler/NotHandler.php @@ -4,14 +4,11 @@ namespace Yiisoft\Data\Reader\Iterable\FilterHandler; -use LogicException; use Yiisoft\Data\Reader\Filter\Not; use Yiisoft\Data\Reader\FilterInterface; use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface; -use function sprintf; - /** * `Not` iterable filter handler negates another filter. */ @@ -28,10 +25,7 @@ public function match(object|array $item, FilterInterface $filter, Context $cont $subFilter = $filter->getFilter(); - $filterHandler = $context->tryFindFilterHandler($subFilter::class); - if ($filterHandler === null) { - throw new LogicException(sprintf('Filter "%s" is not supported.', $subFilter::class)); - } + $filterHandler = $context->getFilterHandler($subFilter::class); return !$filterHandler->match($item, $subFilter, $context); } } diff --git a/src/Reader/Iterable/IterableDataReader.php b/src/Reader/Iterable/IterableDataReader.php index d2a39aa3..07d6049a 100644 --- a/src/Reader/Iterable/IterableDataReader.php +++ b/src/Reader/Iterable/IterableDataReader.php @@ -6,7 +6,6 @@ use Generator; use InvalidArgumentException; -use RuntimeException; use Traversable; use Yiisoft\Arrays\ArrayHelper; use Yiisoft\Data\Reader\DataReaderException; @@ -232,12 +231,7 @@ private function internalRead(bool $useLimitAndOffset): array */ private function matchFilter(array|object $item, FilterInterface $filter): bool { - $handler = $this->context->tryFindFilterHandler($filter::class); - - if ($handler === null) { - throw new RuntimeException(sprintf('Filter "%s" is not supported.', $filter::class)); - } - + $handler = $this->context->getFilterHandler($filter::class); return $handler->match($item, $filter, $this->context); } diff --git a/tests/Reader/Iterable/IterableDataReaderTest.php b/tests/Reader/Iterable/IterableDataReaderTest.php index 9234ae03..0b58461f 100644 --- a/tests/Reader/Iterable/IterableDataReaderTest.php +++ b/tests/Reader/Iterable/IterableDataReaderTest.php @@ -7,6 +7,7 @@ use ArrayIterator; use Generator; use InvalidArgumentException; +use LogicException; use RuntimeException; use Yiisoft\Data\Reader\DataReaderException; use Yiisoft\Data\Reader\Filter\All; @@ -447,7 +448,7 @@ public function testNotSupportedFilter(): void $dataReader = (new IterableDataReader(self::DEFAULT_DATASET)) ->withFilter(new FilterWithoutHandler()); - $this->expectException(RuntimeException::class); + $this->expectException(LogicException::class); $this->expectExceptionMessage('Filter "' . FilterWithoutHandler::class . '" is not supported.'); $dataReader->read(); From 100597f447f909936f42137b5c3ecefde8cea420 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Thu, 26 Jun 2025 10:51:38 +0000 Subject: [PATCH 3/7] Apply fixes from StyleCI --- tests/Reader/Iterable/IterableDataReaderTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Reader/Iterable/IterableDataReaderTest.php b/tests/Reader/Iterable/IterableDataReaderTest.php index 0b58461f..e633ac03 100644 --- a/tests/Reader/Iterable/IterableDataReaderTest.php +++ b/tests/Reader/Iterable/IterableDataReaderTest.php @@ -8,7 +8,6 @@ use Generator; use InvalidArgumentException; use LogicException; -use RuntimeException; use Yiisoft\Data\Reader\DataReaderException; use Yiisoft\Data\Reader\Filter\All; use Yiisoft\Data\Reader\Filter\Any; From 7fd5eb83fda088af7ad51d2a4fd64d0fa50d0e3d Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Thu, 26 Jun 2025 13:59:20 +0300 Subject: [PATCH 4/7] changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a114f47..e0880da8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,8 @@ - Chg #211, #221: Change PHP constraint in `composer.json` to `8.1 - 8.4` (@vjik) - New #223: Add `Sort::getDefaultOrder()` method (@vjik) - Enh #223: `KeysetPaginator` now uses default order from `Sort` when no sort is set (@vjik) +- Chg #224: Change `$iterableFilterHandlers` to context object in `IterableFilterHandlerInterface::match()` (@vjik) +- New #224: Add filtering by nested values support in `IterableDataReader` (@vjik) ## 1.0.1 January 25, 2023 From 14bffcd2db89bd677f5686290fc9346f2fd83aa1 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Thu, 26 Jun 2025 14:00:46 +0300 Subject: [PATCH 5/7] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 82c8647a..4505b45d 100644 --- a/README.md +++ b/README.md @@ -189,7 +189,7 @@ class OwnIterableNotTwoFilterHandler implements IterableFilterHandlerInterface return OwnNotTwoFilter::getOperator(); } - public function match(array $item, array $arguments, array $filterHandlers): bool + public function match(array $item, array $arguments, Context $context): bool { [$field] = $arguments; return $item[$field] != 2; From fc7dd0152f5e8cd61870fb2299fc8c791c275402 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Thu, 26 Jun 2025 15:12:54 +0300 Subject: [PATCH 6/7] Update tests/Support/CustomFilter/DigitalHandler.php Co-authored-by: Sergei Tigrov --- tests/Support/CustomFilter/DigitalHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Support/CustomFilter/DigitalHandler.php b/tests/Support/CustomFilter/DigitalHandler.php index 74b02d8d..98d304c1 100644 --- a/tests/Support/CustomFilter/DigitalHandler.php +++ b/tests/Support/CustomFilter/DigitalHandler.php @@ -19,6 +19,6 @@ public function getFilterClass(): string public function match(object|array $item, FilterInterface $filter, Context $context): bool { /** @var Digital $filter */ - return ctype_digit((string) ArrayHelper::getValue($item, $filter->field)); + return ctype_digit((string) $context->readValue($item, $filter->field)); } } From f22076370f4aaaa3d1bc739386ccf338357023e2 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Thu, 26 Jun 2025 12:13:03 +0000 Subject: [PATCH 7/7] Apply fixes from StyleCI --- tests/Support/CustomFilter/DigitalHandler.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Support/CustomFilter/DigitalHandler.php b/tests/Support/CustomFilter/DigitalHandler.php index 98d304c1..dd5dd778 100644 --- a/tests/Support/CustomFilter/DigitalHandler.php +++ b/tests/Support/CustomFilter/DigitalHandler.php @@ -4,7 +4,6 @@ namespace Yiisoft\Data\Tests\Support\CustomFilter; -use Yiisoft\Arrays\ArrayHelper; use Yiisoft\Data\Reader\FilterInterface; use Yiisoft\Data\Reader\Iterable\Context; use Yiisoft\Data\Reader\Iterable\IterableFilterHandlerInterface;