From 9088e15648f9656742f82f21692998dd8817ddcd Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Wed, 10 Dec 2025 17:38:45 +0300 Subject: [PATCH 1/6] Adapt to changes in Yii Data --- src/FilterHandler.php | 17 +--- .../QueryFilterHandlerInterface.php | 3 +- src/QueryDataReader.php | 79 ++++++------------- tests/Sqlite/FilterHandlerTest.php | 41 ---------- 4 files changed, 27 insertions(+), 113 deletions(-) delete mode 100644 tests/Sqlite/FilterHandlerTest.php diff --git a/src/FilterHandler.php b/src/FilterHandler.php index dedf14c..40f5b99 100644 --- a/src/FilterHandler.php +++ b/src/FilterHandler.php @@ -32,25 +32,12 @@ final class FilterHandler /** * @psalm-param list $handlers */ - public function __construct( - array $handlers, - private readonly FieldMapperInterface $fieldMapper, - ) { + public function __construct(array $handlers, FieldMapperInterface $fieldMapper) + { $this->handlers = $this->prepareHandlers($handlers); $this->context = new Context($this, $fieldMapper); } - public function withAddedFilterHandlers(QueryFilterHandlerInterface ...$handlers): self - { - $new = clone $this; - $new->handlers = array_merge( - $this->handlers, - $this->prepareHandlers($handlers), - ); - $new->context = new Context($new, $this->fieldMapper); - return $new; - } - public function handle(FilterInterface $filter): ConditionInterface { return $this->getHandlerByOperator($filter::class)->getCondition($filter, $this->context); diff --git a/src/FilterHandler/QueryFilterHandlerInterface.php b/src/FilterHandler/QueryFilterHandlerInterface.php index b62f0a7..a647b3f 100644 --- a/src/FilterHandler/QueryFilterHandlerInterface.php +++ b/src/FilterHandler/QueryFilterHandlerInterface.php @@ -4,11 +4,10 @@ namespace Yiisoft\Data\Db\FilterHandler; -use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; use Yiisoft\Db\QueryBuilder\Condition\ConditionInterface; -interface QueryFilterHandlerInterface extends FilterHandlerInterface +interface QueryFilterHandlerInterface { public function getCondition(FilterInterface $filter, Context $context): ConditionInterface; } diff --git a/src/QueryDataReader.php b/src/QueryDataReader.php index bac355b..8cbca87 100644 --- a/src/QueryDataReader.php +++ b/src/QueryDataReader.php @@ -28,7 +28,6 @@ use Yiisoft\Data\Db\FilterHandler\OrXHandler; use Yiisoft\Data\Db\FilterHandler\QueryFilterHandlerInterface; use Yiisoft\Data\Reader\Filter\All; -use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; use Yiisoft\Data\Reader\Sort; use Yiisoft\Db\Expression\CompositeExpression; @@ -67,7 +66,7 @@ class QueryDataReader implements QueryDataReaderInterface /** * @psalm-param non-negative-int|null $limit - * @psalm-param list|null $filterHandlers + * @psalm-param list|null $addFilterHandlers * @psalm-param array|FieldMapperInterface $fieldMapper */ public function __construct( @@ -79,13 +78,33 @@ public function __construct( private FilterInterface $filter = new All(), private FilterInterface $having = new All(), private ?int $batchSize = null, - ?array $filterHandlers = null, + array $addFilterHandlers = [], array|FieldMapperInterface $fieldMapper = [], ) { $this->fieldMapper = is_array($fieldMapper) ? new ArrayFieldMapper($fieldMapper) : $fieldMapper; - $filterHandlers ??= $this->getDefaultFilterHandlers(); - $this->filterHandler = new FilterHandler($filterHandlers, $this->fieldMapper); + $this->filterHandler = new FilterHandler( + [ + new AllHandler(), + new NoneHandler(), + new AndXHandler(), + new OrXHandler(), + new EqualsHandler(), + new GreaterThanHandler(), + new GreaterThanOrEqualHandler(), + new LessThanHandler(), + new LessThanOrEqualHandler(), + new LikeHandler(), + new InHandler(), + new ExistsHandler(), + new NotHandler(), + new BetweenHandler(), + new EqualsNullHandler(), + new EqualsExpressionHandler(), + ...$addFilterHandlers, + ], + $this->fieldMapper, + ); } /** @@ -296,31 +315,6 @@ final public function withBatchSize(?int $batchSize): static return $new; } - /** - * @return static The new instance with the specified filter handlers added. - * - * @psalm-return static - */ - final public function withAddedFilterHandlers(FilterHandlerInterface ...$filterHandlers): static - { - foreach ($filterHandlers as $handler) { - if (!$handler instanceof QueryFilterHandlerInterface) { - throw new LogicException( - sprintf( - 'Filter handler must implement "%s".', - QueryFilterHandlerInterface::class, - ), - ); - } - } - /** @var QueryFilterHandlerInterface[] $filterHandlers */ - - $new = clone $this; - $new->count = $new->cache = null; - $new->filterHandler = $this->filterHandler->withAddedFilterHandlers(...$filterHandlers); - return $new; - } - final public function getSort(): ?Sort { return $this->sort; @@ -341,31 +335,6 @@ final public function getOffset(): int return $this->offset; } - /** - * @psalm-return list - */ - private function getDefaultFilterHandlers(): array - { - return [ - new AllHandler(), - new NoneHandler(), - new AndXHandler(), - new OrXHandler(), - new EqualsHandler(), - new GreaterThanHandler(), - new GreaterThanOrEqualHandler(), - new LessThanHandler(), - new LessThanOrEqualHandler(), - new LikeHandler(), - new InHandler(), - new ExistsHandler(), - new NotHandler(), - new BetweenHandler(), - new EqualsNullHandler(), - new EqualsExpressionHandler(), - ]; - } - private function convertSortToOrderBy(Sort $sort): array { $result = []; diff --git a/tests/Sqlite/FilterHandlerTest.php b/tests/Sqlite/FilterHandlerTest.php deleted file mode 100644 index 41cb397..0000000 --- a/tests/Sqlite/FilterHandlerTest.php +++ /dev/null @@ -1,41 +0,0 @@ -withAddedFilterHandlers($handler2, $handler3); - - $this->assertNotSame($handler, $handlerWithAdded); - - $this->assertInstanceOf(ConditionInterface::class, $handlerWithAdded->handle(new Equals('field', 'value'))); - $this->assertInstanceOf(ConditionInterface::class, $handlerWithAdded->handle(new None())); - $this->assertInstanceOf(ConditionInterface::class, $handlerWithAdded->handle(new All())); - - $this->expectException(LogicException::class); - $this->expectExceptionMessage('Operator "' . In::class . '" is not supported.'); - $handlerWithAdded->handle(new In('field', [])); - } -} From 57631937dcf90b6e45de1f5e3d5acc8ad26ab158 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Wed, 10 Dec 2025 17:40:57 +0300 Subject: [PATCH 2/6] fix --- tests/Sqlite/QueryDataReaderTest.php | 41 ---------------------------- 1 file changed, 41 deletions(-) diff --git a/tests/Sqlite/QueryDataReaderTest.php b/tests/Sqlite/QueryDataReaderTest.php index 889bfb4..6d0d746 100644 --- a/tests/Sqlite/QueryDataReaderTest.php +++ b/tests/Sqlite/QueryDataReaderTest.php @@ -22,47 +22,6 @@ final class QueryDataReaderTest extends TestCase { - public function testWithAddedFilterHandlers(): void - { - $db = TestHelper::createSqliteConnection(); - $columnBuilder = $db->getColumnBuilderClass(); - $db->createCommand()->createTable('test', ['id' => $columnBuilder::text()])->execute(); - - $handler1 = new AllHandler(); - $handler2 = new NoneHandler(); - $handler3 = new AndXHandler(); - - $dataReader = new QueryDataReader( - $db->createQuery()->from('test'), - filterHandlers: [$handler1], - ); - - $dataReaderWithAdded = $dataReader->withAddedFilterHandlers($handler2, $handler3); - - $this->assertNotSame($dataReader, $dataReaderWithAdded); - - $dataReaderWithFilters = $dataReaderWithAdded->withFilter(new AndX(new All(), new None())); - $dataReaderWithFilters->read(); // No errors - - $dataReaderWithUnsupportedFilter = $dataReaderWithAdded->withFilter(new Equals('id', 'test')); - $this->expectException(LogicException::class); - $this->expectExceptionMessage('Operator "' . Equals::class . '" is not supported.'); - iterator_to_array($dataReaderWithUnsupportedFilter->read()); - } - - public function testWithAddedFilterHandlersWithIncorrectHandler(): void - { - $dataReader = new QueryDataReader( - TestHelper::createSqliteConnection()->createQuery(), - ); - - $iterableHandler = new \Yiisoft\Data\Reader\Iterable\FilterHandler\AllHandler(); - - $this->expectException(LogicException::class); - $this->expectExceptionMessage('Filter handler must implement "' . QueryFilterHandlerInterface::class . '".'); - $dataReader->withAddedFilterHandlers($iterableHandler); - } - public function testGetIteratorAfterRead(): void { $data = [['id' => '1'], ['id' => '2']]; From 4e6e79118d892373132d114158eb1ac8436c11ad Mon Sep 17 00:00:00 2001 From: vjik <525501+vjik@users.noreply.github.com> Date: Wed, 10 Dec 2025 14:42:20 +0000 Subject: [PATCH 3/6] Apply PHP CS Fixer and Rector changes (CI) --- src/FilterHandler.php | 2 +- src/QueryDataReader.php | 1 - tests/Sqlite/QueryDataReaderTest.php | 7 ------- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/FilterHandler.php b/src/FilterHandler.php index 40f5b99..24fae6d 100644 --- a/src/FilterHandler.php +++ b/src/FilterHandler.php @@ -22,7 +22,7 @@ */ final class FilterHandler { - private Context $context; + private readonly Context $context; /** * @psalm-var array diff --git a/src/QueryDataReader.php b/src/QueryDataReader.php index 8cbca87..069502b 100644 --- a/src/QueryDataReader.php +++ b/src/QueryDataReader.php @@ -6,7 +6,6 @@ use Generator; use InvalidArgumentException; -use LogicException; use RuntimeException; use Yiisoft\Data\Db\FieldMapper\ArrayFieldMapper; use Yiisoft\Data\Db\FieldMapper\FieldMapperInterface; diff --git a/tests/Sqlite/QueryDataReaderTest.php b/tests/Sqlite/QueryDataReaderTest.php index 6d0d746..fa0158c 100644 --- a/tests/Sqlite/QueryDataReaderTest.php +++ b/tests/Sqlite/QueryDataReaderTest.php @@ -5,17 +5,10 @@ namespace Yiisoft\Data\Db\Tests\Sqlite; use InvalidArgumentException; -use LogicException; use PHPUnit\Framework\TestCase; -use Yiisoft\Data\Db\FilterHandler\AllHandler; -use Yiisoft\Data\Db\FilterHandler\AndXHandler; -use Yiisoft\Data\Db\FilterHandler\NoneHandler; -use Yiisoft\Data\Db\FilterHandler\QueryFilterHandlerInterface; use Yiisoft\Data\Db\QueryDataReader; use Yiisoft\Data\Db\Tests\TestHelper; use Yiisoft\Data\Reader\Filter\All; -use Yiisoft\Data\Reader\Filter\AndX; -use Yiisoft\Data\Reader\Filter\Equals; use Yiisoft\Data\Reader\Filter\None; use Yiisoft\Data\Reader\Sort; use Yiisoft\Test\Support\Log\SimpleLogger; From f9e718f26f1567b59de126376f61f6c02903e3e2 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Wed, 10 Dec 2025 17:43:58 +0300 Subject: [PATCH 4/6] fix --- src/FilterHandler/QueryFilterHandlerInterface.php | 11 +++++++++++ src/QueryDataReader.php | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/FilterHandler/QueryFilterHandlerInterface.php b/src/FilterHandler/QueryFilterHandlerInterface.php index a647b3f..68171c5 100644 --- a/src/FilterHandler/QueryFilterHandlerInterface.php +++ b/src/FilterHandler/QueryFilterHandlerInterface.php @@ -10,4 +10,15 @@ interface QueryFilterHandlerInterface { public function getCondition(FilterInterface $filter, Context $context): ConditionInterface; + + /** + * Get matching filter class name. + * + * If the filter is active, a corresponding handler will be used during matching. + * + * @return string The filter class name. + * + * @psalm-return class-string + */ + public function getFilterClass(): string; } diff --git a/src/QueryDataReader.php b/src/QueryDataReader.php index 8cbca87..932bff0 100644 --- a/src/QueryDataReader.php +++ b/src/QueryDataReader.php @@ -66,7 +66,7 @@ class QueryDataReader implements QueryDataReaderInterface /** * @psalm-param non-negative-int|null $limit - * @psalm-param list|null $addFilterHandlers + * @psalm-param list $addFilterHandlers * @psalm-param array|FieldMapperInterface $fieldMapper */ public function __construct( From 87b97dfcc2514241441221cbd7e0cce9c3451430 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Wed, 10 Dec 2025 17:58:43 +0300 Subject: [PATCH 5/6] fix --- src/QueryDataReader.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/QueryDataReader.php b/src/QueryDataReader.php index 868df1f..1370020 100644 --- a/src/QueryDataReader.php +++ b/src/QueryDataReader.php @@ -116,6 +116,7 @@ final public function getIterator(): Generator /** @psalm-var array $data */ yield from $data; } + /** @infection-ignore-all */ return; } From ab4a0876b00ff0941624a1c00de941eb25af0632 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 11 Dec 2025 14:27:38 +0300 Subject: [PATCH 6/6] Rename addFilterHandlers to extraFilterHandlers (#124) * Initial plan * Rename addFilterHandlers to extraFilterHandlers Co-authored-by: vjik <525501+vjik@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: vjik <525501+vjik@users.noreply.github.com> --- src/QueryDataReader.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/QueryDataReader.php b/src/QueryDataReader.php index 1370020..c29cc00 100644 --- a/src/QueryDataReader.php +++ b/src/QueryDataReader.php @@ -65,7 +65,7 @@ class QueryDataReader implements QueryDataReaderInterface /** * @psalm-param non-negative-int|null $limit - * @psalm-param list $addFilterHandlers + * @psalm-param list $extraFilterHandlers * @psalm-param array|FieldMapperInterface $fieldMapper */ public function __construct( @@ -77,7 +77,7 @@ public function __construct( private FilterInterface $filter = new All(), private FilterInterface $having = new All(), private ?int $batchSize = null, - array $addFilterHandlers = [], + array $extraFilterHandlers = [], array|FieldMapperInterface $fieldMapper = [], ) { $this->fieldMapper = is_array($fieldMapper) ? new ArrayFieldMapper($fieldMapper) : $fieldMapper; @@ -100,7 +100,7 @@ public function __construct( new BetweenHandler(), new EqualsNullHandler(), new EqualsExpressionHandler(), - ...$addFilterHandlers, + ...$extraFilterHandlers, ], $this->fieldMapper, );