diff --git a/.gitattributes b/.gitattributes index d2354a6..2f53ec6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -21,18 +21,16 @@ *.gif binary *.ttf binary -# Ignore some meta files when creating an archive of this repository -/.github export-ignore -/.editorconfig export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore -/.phpunit-watcher.yml export-ignore -/.styleci.yml export-ignore -/infection.json.dist export-ignore -/phpunit.xml.dist export-ignore -/psalm.xml export-ignore -/tests export-ignore -/docs export-ignore +# Exclude development and metadata files from distribution archive +* export-ignore +/src/ -export-ignore +/src/** -export-ignore +/tests/ -export-ignore +/tests/** -export-ignore +/composer.json -export-ignore +/README.md -export-ignore +/CHANGELOG.md -export-ignore +/LICENSE.md -export-ignore # Avoid merge conflicts in CHANGELOG # https://about.gitlab.com/2015/02/10/gitlab-reduced-merge-conflicts-by-90-percent-with-changelog-placeholders/ diff --git a/.github/workflows/bc.yml_ b/.github/workflows/bc.yml_ index 85232cc..0ea4a5c 100644 --- a/.github/workflows/bc.yml_ +++ b/.github/workflows/bc.yml_ @@ -30,4 +30,4 @@ jobs: os: >- ['ubuntu-latest'] php: >- - ['8.3'] + ['8.4'] diff --git a/.github/workflows/composer-require-checker.yml b/.github/workflows/composer-require-checker.yml index a93390b..d2ef508 100644 --- a/.github/workflows/composer-require-checker.yml +++ b/.github/workflows/composer-require-checker.yml @@ -31,4 +31,4 @@ jobs: os: >- ['ubuntu-latest'] php: >- - ['8.1', '8.2', '8.3', '8.4'] + ['8.1', '8.2', '8.3', '8.4', '8.5'] diff --git a/.github/workflows/mssql.yml b/.github/workflows/mssql.yml index a4e0aff..462abb1 100644 --- a/.github/workflows/mssql.yml +++ b/.github/workflows/mssql.yml @@ -34,6 +34,7 @@ jobs: - 8.2 - 8.3 - 8.4 + - 8.5 mssql: - server: 2022-latest diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index ced4b61..820f01a 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -27,7 +27,7 @@ jobs: os: >- ['ubuntu-latest'] php: >- - ['8.4'] + ['8.5'] min-covered-msi: 100 secrets: STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }} diff --git a/.github/workflows/mysql.yml b/.github/workflows/mysql.yml index 01ef6ba..314bfe1 100644 --- a/.github/workflows/mysql.yml +++ b/.github/workflows/mysql.yml @@ -41,6 +41,7 @@ jobs: - 8.2 - 8.3 - 8.4 + - 8.5 mysql: - 5.7 diff --git a/.github/workflows/pgsql.yml b/.github/workflows/pgsql.yml index a76ec22..24d40cf 100644 --- a/.github/workflows/pgsql.yml +++ b/.github/workflows/pgsql.yml @@ -41,6 +41,7 @@ jobs: - 8.2 - 8.3 - 8.4 + - 8.5 pgsql: - 9 diff --git a/.github/workflows/sqlite.yml b/.github/workflows/sqlite.yml index 6195dad..1e7f6d8 100644 --- a/.github/workflows/sqlite.yml +++ b/.github/workflows/sqlite.yml @@ -37,6 +37,7 @@ jobs: - 8.2 - 8.3 - 8.4 + - 8.5 steps: - name: Checkout. diff --git a/composer.json b/composer.json index f8ac4cc..38d57aa 100644 --- a/composer.json +++ b/composer.json @@ -32,11 +32,11 @@ "prefer-stable": true, "minimum-stability": "dev", "require": { - "php": "8.1 - 8.4", + "php": "8.1 - 8.5", "ext-mbstring": "*", "cycle/database": "^2.11", "cycle/orm": "^2.9", - "yiisoft/data": "dev-master" + "yiisoft/data": "^2.0" }, "require-dev": { "maglnet/composer-require-checker": "^4.7", @@ -44,7 +44,7 @@ "rector/rector": "^2.1.5", "roave/infection-static-analysis-plugin": "^1.35", "spatie/phpunit-watcher": "^1.24", - "vimeo/psalm": "^5.26.1 || ^6.10.3", + "vimeo/psalm": "^5.26.1 || ^6.14.1", "vlucas/phpdotenv": "^5.6" }, "autoload": { diff --git a/src/Reader/EntityReader.php b/src/Reader/EntityReader.php index 8324a53..a20b938 100644 --- a/src/Reader/EntityReader.php +++ b/src/Reader/EntityReader.php @@ -14,7 +14,6 @@ use Yiisoft\Data\Cycle\Reader\FilterHandler\LikeHandler\LikeHandlerFactory; use Yiisoft\Data\Reader\DataReaderInterface; use Yiisoft\Data\Reader\Filter\All; -use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; use Yiisoft\Data\Reader\Sort; use Yiisoft\Data\Cycle\Reader\Cache\CachedCollection; @@ -40,11 +39,14 @@ final class EntityReader implements DataReaderInterface private CachedCollection $itemsCache; private CachedCollection $oneItemCache; /** - * @psalm-var array $handlers + * @psalm-var array $handlers */ private array $filterHandlers = []; - public function __construct(Select|SelectQuery $query) + /** + * @param QueryBuilderFilterHandler[] $extraFilterHandlers + **/ + public function __construct(Select|SelectQuery $query, array $extraFilterHandlers = []) { $this->query = clone $query; $this->countCache = new CachedCount($this->query); @@ -70,6 +72,7 @@ public function __construct(Select|SelectQuery $query) new FilterHandler\LessThanOrEqualHandler(), $likeHandler, new FilterHandler\NotHandler(), + ...$extraFilterHandlers, ); $this->filter = new All(); @@ -145,22 +148,6 @@ public function withFilter(FilterInterface $filter): static return $new; } - /** - * @psalm-mutation-free - */ - #[\Override] - public function withAddedFilterHandlers(FilterHandlerInterface ...$filterHandlers): static - { - $new = clone $this; - /** @psalm-suppress ImpureMethodCall */ - $new->setFilterHandlers(...$filterHandlers); - /** @psalm-suppress ImpureMethodCall */ - $new->resetCountCache(); - $new->itemsCache = new CachedCollection(); - $new->oneItemCache = new CachedCollection(); - return $new; - } - #[\Override] public function count(): int { @@ -207,13 +194,11 @@ public function getSql(): string return (string)($query instanceof Select ? $query->buildQuery() : $query); } - private function setFilterHandlers(FilterHandlerInterface ...$filterHandlers): void + private function setFilterHandlers(QueryBuilderFilterHandler ...$filterHandlers): void { $handlers = []; foreach ($filterHandlers as $filterHandler) { - if ($filterHandler instanceof QueryBuilderFilterHandler) { - $handlers[$filterHandler->getFilterClass()] = $filterHandler; - } + $handlers[$filterHandler->getFilterClass()] = $filterHandler; } $this->filterHandlers = array_merge($this->filterHandlers, $handlers); } @@ -238,7 +223,7 @@ private function buildSelectQuery(): SelectQuery|Select private function makeFilterClosure(FilterInterface $filter): Closure { - return function (QueryBuilder $select) use ($filter) { + return function (QueryBuilder|SelectQuery $select) use ($filter) { if (!array_key_exists($filter::class, $this->filterHandlers)) { throw new NotSupportedFilterException($filter::class); } diff --git a/src/Reader/FilterHandler/AllHandler.php b/src/Reader/FilterHandler/AllHandler.php index c6375fe..6a3af5b 100644 --- a/src/Reader/FilterHandler/AllHandler.php +++ b/src/Reader/FilterHandler/AllHandler.php @@ -5,13 +5,13 @@ namespace Yiisoft\Data\Cycle\Reader\FilterHandler; use Cycle\Database\Injection\Expression; +use Cycle\Database\Query\SelectQuery; use Cycle\ORM\Select\QueryBuilder; use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; use Yiisoft\Data\Reader\Filter\All; -use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; -final class AllHandler implements QueryBuilderFilterHandler, FilterHandlerInterface +final class AllHandler implements QueryBuilderFilterHandler { #[\Override] public function getFilterClass(): string @@ -24,7 +24,7 @@ public function getAsWhereArguments(FilterInterface $filter, array $handlers): a { /** @var All $filter */ return [ - static function (QueryBuilder $select) { + static function (QueryBuilder|SelectQuery $select) { $select->where(new Expression('1 = 1')); }, ]; diff --git a/src/Reader/FilterHandler/AndXHandler.php b/src/Reader/FilterHandler/AndXHandler.php index 85566b9..029d8b2 100644 --- a/src/Reader/FilterHandler/AndXHandler.php +++ b/src/Reader/FilterHandler/AndXHandler.php @@ -4,14 +4,14 @@ namespace Yiisoft\Data\Cycle\Reader\FilterHandler; +use Cycle\Database\Query\SelectQuery; use Cycle\ORM\Select\QueryBuilder; use Yiisoft\Data\Cycle\Exception\NotSupportedFilterException; use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; use Yiisoft\Data\Reader\Filter\AndX; -use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; -final class AndXHandler implements QueryBuilderFilterHandler, FilterHandlerInterface +final class AndXHandler implements QueryBuilderFilterHandler { #[\Override] public function getFilterClass(): string @@ -24,7 +24,7 @@ public function getAsWhereArguments(FilterInterface $filter, array $handlers): a { /** @var AndX $filter */ return [ - static function (QueryBuilder $select) use ($filter, $handlers) { + static function (QueryBuilder|SelectQuery $select) use ($filter, $handlers) { foreach ($filter->filters as $subFilter) { $handler = $handlers[$subFilter::class] ?? null; if ($handler === null) { diff --git a/src/Reader/FilterHandler/BetweenHandler.php b/src/Reader/FilterHandler/BetweenHandler.php index 3b739e5..07124dd 100644 --- a/src/Reader/FilterHandler/BetweenHandler.php +++ b/src/Reader/FilterHandler/BetweenHandler.php @@ -6,10 +6,9 @@ use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; use Yiisoft\Data\Reader\Filter\Between; -use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; -final class BetweenHandler implements QueryBuilderFilterHandler, FilterHandlerInterface +final class BetweenHandler implements QueryBuilderFilterHandler { #[\Override] public function getFilterClass(): string diff --git a/src/Reader/FilterHandler/EqualsHandler.php b/src/Reader/FilterHandler/EqualsHandler.php index 933be1a..501b492 100644 --- a/src/Reader/FilterHandler/EqualsHandler.php +++ b/src/Reader/FilterHandler/EqualsHandler.php @@ -6,10 +6,9 @@ use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; use Yiisoft\Data\Reader\Filter\Equals; -use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; -final class EqualsHandler implements QueryBuilderFilterHandler, FilterHandlerInterface +final class EqualsHandler implements QueryBuilderFilterHandler { #[\Override] public function getFilterClass(): string diff --git a/src/Reader/FilterHandler/EqualsNullHandler.php b/src/Reader/FilterHandler/EqualsNullHandler.php index 7c8f469..1769616 100644 --- a/src/Reader/FilterHandler/EqualsNullHandler.php +++ b/src/Reader/FilterHandler/EqualsNullHandler.php @@ -6,10 +6,9 @@ use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; use Yiisoft\Data\Reader\Filter\EqualsNull; -use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; -final class EqualsNullHandler implements QueryBuilderFilterHandler, FilterHandlerInterface +final class EqualsNullHandler implements QueryBuilderFilterHandler { #[\Override] public function getFilterClass(): string diff --git a/src/Reader/FilterHandler/GreaterThanHandler.php b/src/Reader/FilterHandler/GreaterThanHandler.php index f152e3f..ce240ad 100644 --- a/src/Reader/FilterHandler/GreaterThanHandler.php +++ b/src/Reader/FilterHandler/GreaterThanHandler.php @@ -6,10 +6,9 @@ use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; use Yiisoft\Data\Reader\Filter\GreaterThan; -use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; -final class GreaterThanHandler implements QueryBuilderFilterHandler, FilterHandlerInterface +final class GreaterThanHandler implements QueryBuilderFilterHandler { #[\Override] public function getFilterClass(): string diff --git a/src/Reader/FilterHandler/GreaterThanOrEqualHandler.php b/src/Reader/FilterHandler/GreaterThanOrEqualHandler.php index ee3c6ce..1c5cf17 100644 --- a/src/Reader/FilterHandler/GreaterThanOrEqualHandler.php +++ b/src/Reader/FilterHandler/GreaterThanOrEqualHandler.php @@ -6,10 +6,9 @@ use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; use Yiisoft\Data\Reader\Filter\GreaterThanOrEqual; -use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; -final class GreaterThanOrEqualHandler implements QueryBuilderFilterHandler, FilterHandlerInterface +final class GreaterThanOrEqualHandler implements QueryBuilderFilterHandler { #[\Override] public function getFilterClass(): string diff --git a/src/Reader/FilterHandler/InHandler.php b/src/Reader/FilterHandler/InHandler.php index 3ed693d..e198d71 100644 --- a/src/Reader/FilterHandler/InHandler.php +++ b/src/Reader/FilterHandler/InHandler.php @@ -7,10 +7,9 @@ use Cycle\Database\Injection\Parameter; use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; use Yiisoft\Data\Reader\Filter\In; -use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; -final class InHandler implements QueryBuilderFilterHandler, FilterHandlerInterface +final class InHandler implements QueryBuilderFilterHandler { #[\Override] public function getFilterClass(): string diff --git a/src/Reader/FilterHandler/LessThanHandler.php b/src/Reader/FilterHandler/LessThanHandler.php index 3ee5997..b428744 100644 --- a/src/Reader/FilterHandler/LessThanHandler.php +++ b/src/Reader/FilterHandler/LessThanHandler.php @@ -6,10 +6,9 @@ use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; use Yiisoft\Data\Reader\Filter\LessThan; -use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; -final class LessThanHandler implements QueryBuilderFilterHandler, FilterHandlerInterface +final class LessThanHandler implements QueryBuilderFilterHandler { #[\Override] public function getFilterClass(): string diff --git a/src/Reader/FilterHandler/LessThanOrEqualHandler.php b/src/Reader/FilterHandler/LessThanOrEqualHandler.php index a5948ad..4041af9 100644 --- a/src/Reader/FilterHandler/LessThanOrEqualHandler.php +++ b/src/Reader/FilterHandler/LessThanOrEqualHandler.php @@ -6,10 +6,9 @@ use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; use Yiisoft\Data\Reader\Filter\LessThanOrEqual; -use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; -final class LessThanOrEqualHandler implements QueryBuilderFilterHandler, FilterHandlerInterface +final class LessThanOrEqualHandler implements QueryBuilderFilterHandler { #[\Override] public function getFilterClass(): string diff --git a/src/Reader/FilterHandler/LikeHandler/BaseLikeHandler.php b/src/Reader/FilterHandler/LikeHandler/BaseLikeHandler.php index ac99db4..6ad5d2a 100644 --- a/src/Reader/FilterHandler/LikeHandler/BaseLikeHandler.php +++ b/src/Reader/FilterHandler/LikeHandler/BaseLikeHandler.php @@ -5,11 +5,11 @@ namespace Yiisoft\Data\Cycle\Reader\FilterHandler\LikeHandler; use Stringable; +use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; use Yiisoft\Data\Reader\Filter\Like; use Yiisoft\Data\Reader\Filter\LikeMode; -use Yiisoft\Data\Reader\FilterHandlerInterface; -abstract class BaseLikeHandler implements FilterHandlerInterface +abstract class BaseLikeHandler implements QueryBuilderFilterHandler { protected array $escapingReplacements = [ '%' => '\%', diff --git a/src/Reader/FilterHandler/LikeHandler/LikeHandlerFactory.php b/src/Reader/FilterHandler/LikeHandler/LikeHandlerFactory.php index 25f1a7b..c6bcf85 100644 --- a/src/Reader/FilterHandler/LikeHandler/LikeHandlerFactory.php +++ b/src/Reader/FilterHandler/LikeHandler/LikeHandlerFactory.php @@ -5,14 +5,14 @@ namespace Yiisoft\Data\Cycle\Reader\FilterHandler\LikeHandler; use RuntimeException; -use Yiisoft\Data\Reader\FilterHandlerInterface; +use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; /** * @internal */ final class LikeHandlerFactory { - public static function getLikeHandler(string $driverType): FilterHandlerInterface + public static function getLikeHandler(string $driverType): QueryBuilderFilterHandler { // default - ignored due to the complexity of testing and preventing splitting of databaseDriver argument. // @codeCoverageIgnoreStart diff --git a/src/Reader/FilterHandler/LikeHandler/MysqlLikeHandler.php b/src/Reader/FilterHandler/LikeHandler/MysqlLikeHandler.php index 5199c78..fd64ad8 100644 --- a/src/Reader/FilterHandler/LikeHandler/MysqlLikeHandler.php +++ b/src/Reader/FilterHandler/LikeHandler/MysqlLikeHandler.php @@ -4,11 +4,10 @@ namespace Yiisoft\Data\Cycle\Reader\FilterHandler\LikeHandler; -use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; use Yiisoft\Data\Reader\Filter\Like; use Yiisoft\Data\Reader\FilterInterface; -final class MysqlLikeHandler extends BaseLikeHandler implements QueryBuilderFilterHandler +final class MysqlLikeHandler extends BaseLikeHandler { #[\Override] public function getAsWhereArguments(FilterInterface $filter, array $handlers): array diff --git a/src/Reader/FilterHandler/LikeHandler/PostgresLikeHandler.php b/src/Reader/FilterHandler/LikeHandler/PostgresLikeHandler.php index 8c27fef..a140873 100644 --- a/src/Reader/FilterHandler/LikeHandler/PostgresLikeHandler.php +++ b/src/Reader/FilterHandler/LikeHandler/PostgresLikeHandler.php @@ -4,11 +4,10 @@ namespace Yiisoft\Data\Cycle\Reader\FilterHandler\LikeHandler; -use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; use Yiisoft\Data\Reader\Filter\Like; use Yiisoft\Data\Reader\FilterInterface; -final class PostgresLikeHandler extends BaseLikeHandler implements QueryBuilderFilterHandler +final class PostgresLikeHandler extends BaseLikeHandler { #[\Override] public function getAsWhereArguments(FilterInterface $filter, array $handlers): array diff --git a/src/Reader/FilterHandler/LikeHandler/SqlServerLikeHandler.php b/src/Reader/FilterHandler/LikeHandler/SqlServerLikeHandler.php index 3cb5ef3..2199e8a 100644 --- a/src/Reader/FilterHandler/LikeHandler/SqlServerLikeHandler.php +++ b/src/Reader/FilterHandler/LikeHandler/SqlServerLikeHandler.php @@ -5,11 +5,10 @@ namespace Yiisoft\Data\Cycle\Reader\FilterHandler\LikeHandler; use Yiisoft\Data\Cycle\Exception\NotSupportedFilterOptionException; -use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; use Yiisoft\Data\Reader\Filter\Like; use Yiisoft\Data\Reader\FilterInterface; -final class SqlServerLikeHandler extends BaseLikeHandler implements QueryBuilderFilterHandler +final class SqlServerLikeHandler extends BaseLikeHandler { public function __construct() { diff --git a/src/Reader/FilterHandler/LikeHandler/SqliteLikeHandler.php b/src/Reader/FilterHandler/LikeHandler/SqliteLikeHandler.php index 5cc9ccb..c363557 100644 --- a/src/Reader/FilterHandler/LikeHandler/SqliteLikeHandler.php +++ b/src/Reader/FilterHandler/LikeHandler/SqliteLikeHandler.php @@ -5,11 +5,10 @@ namespace Yiisoft\Data\Cycle\Reader\FilterHandler\LikeHandler; use Yiisoft\Data\Cycle\Exception\NotSupportedFilterOptionException; -use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; use Yiisoft\Data\Reader\Filter\Like; use Yiisoft\Data\Reader\FilterInterface; -final class SqliteLikeHandler extends BaseLikeHandler implements QueryBuilderFilterHandler +final class SqliteLikeHandler extends BaseLikeHandler { public function __construct() { diff --git a/src/Reader/FilterHandler/NoneHandler.php b/src/Reader/FilterHandler/NoneHandler.php index d48c64d..8260b75 100644 --- a/src/Reader/FilterHandler/NoneHandler.php +++ b/src/Reader/FilterHandler/NoneHandler.php @@ -5,13 +5,13 @@ namespace Yiisoft\Data\Cycle\Reader\FilterHandler; use Cycle\Database\Injection\Expression; +use Cycle\Database\Query\SelectQuery; use Cycle\ORM\Select\QueryBuilder; use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; use Yiisoft\Data\Reader\Filter\None; -use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; -final class NoneHandler implements QueryBuilderFilterHandler, FilterHandlerInterface +final class NoneHandler implements QueryBuilderFilterHandler { #[\Override] public function getFilterClass(): string @@ -24,7 +24,7 @@ public function getAsWhereArguments(FilterInterface $filter, array $handlers): a { /** @var None $filter */ return [ - static function (QueryBuilder $select) { + static function (QueryBuilder|SelectQuery $select) { $select->where(new Expression('1 = 0')); }, ]; diff --git a/src/Reader/FilterHandler/NotHandler.php b/src/Reader/FilterHandler/NotHandler.php index 75942ec..65cb483 100644 --- a/src/Reader/FilterHandler/NotHandler.php +++ b/src/Reader/FilterHandler/NotHandler.php @@ -18,10 +18,9 @@ use Yiisoft\Data\Reader\Filter\Like; use Yiisoft\Data\Reader\Filter\Not; use Yiisoft\Data\Reader\Filter\OrX; -use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; -final class NotHandler implements QueryBuilderFilterHandler, FilterHandlerInterface +final class NotHandler implements QueryBuilderFilterHandler { #[\Override] public function getFilterClass(): string diff --git a/src/Reader/FilterHandler/OrXHandler.php b/src/Reader/FilterHandler/OrXHandler.php index f6f8925..f063ce7 100644 --- a/src/Reader/FilterHandler/OrXHandler.php +++ b/src/Reader/FilterHandler/OrXHandler.php @@ -4,14 +4,14 @@ namespace Yiisoft\Data\Cycle\Reader\FilterHandler; +use Cycle\Database\Query\SelectQuery; use Cycle\ORM\Select\QueryBuilder; use Yiisoft\Data\Cycle\Exception\NotSupportedFilterException; use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; use Yiisoft\Data\Reader\Filter\OrX; -use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; -final class OrXHandler implements QueryBuilderFilterHandler, FilterHandlerInterface +final class OrXHandler implements QueryBuilderFilterHandler { #[\Override] public function getFilterClass(): string @@ -24,7 +24,7 @@ public function getAsWhereArguments(FilterInterface $filter, array $handlers): a { /** @var OrX $filter */ return [ - static function (QueryBuilder $select) use ($filter, $handlers) { + static function (QueryBuilder|SelectQuery $select) use ($filter, $handlers) { foreach ($filter->filters as $subFilter) { $handler = $handlers[$subFilter::class] ?? null; if ($handler === null) { diff --git a/src/Reader/QueryBuilderFilterHandler.php b/src/Reader/QueryBuilderFilterHandler.php index c8f067b..35d726a 100644 --- a/src/Reader/QueryBuilderFilterHandler.php +++ b/src/Reader/QueryBuilderFilterHandler.php @@ -4,13 +4,23 @@ namespace Yiisoft\Data\Cycle\Reader; -use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; interface QueryBuilderFilterHandler { /** - * @psalm-param array $handlers + * 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; + + /** + * @psalm-param array $handlers */ public function getAsWhereArguments(FilterInterface $filter, array $handlers): array; } diff --git a/tests/Feature/Base/Reader/BaseEntityReaderTestCase.php b/tests/Feature/Base/Reader/BaseEntityReaderTestCase.php index 0b95fb6..7ca1485 100644 --- a/tests/Feature/Base/Reader/BaseEntityReaderTestCase.php +++ b/tests/Feature/Base/Reader/BaseEntityReaderTestCase.php @@ -5,8 +5,10 @@ namespace Yiisoft\Data\Cycle\Tests\Feature\Base\Reader; use Cycle\Database\Exception\StatementException; +use InvalidArgumentException; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; +use ReflectionProperty; use Yiisoft\Data\Cycle\Exception\NotSupportedFilterException; use Yiisoft\Data\Cycle\Reader\Cache\CachedCollection; use Yiisoft\Data\Cycle\Reader\EntityReader; @@ -18,6 +20,9 @@ use Yiisoft\Data\Reader\Sort; use Yiisoft\Data\Tests\Common\FixtureTrait; +use function iterator_to_array; +use function preg_replace; + abstract class BaseEntityReaderTestCase extends TestCase { use DataTrait; @@ -35,7 +40,7 @@ public function testReadOneFromItemsCache(): void { $reader = (new EntityReader($this->select('user')))->withLimit(3); - $ref = (new \ReflectionProperty($reader, 'itemsCache')); + $ref = (new ReflectionProperty($reader, 'itemsCache')); self::assertFalse($ref->getValue($reader)->isCollected()); $reader->read(); @@ -49,15 +54,15 @@ public function testReadOneFromItemsCache(): void public function testGetIterator(): void { $reader = (new EntityReader($this->select('user')))->withLimit(1); - $this->assertFixtures([0], [\iterator_to_array($reader->getIterator())[0]]); + $this->assertFixtures([0], [iterator_to_array($reader->getIterator())[0]]); - $ref = (new \ReflectionProperty($reader, 'itemsCache')); + $ref = (new ReflectionProperty($reader, 'itemsCache')); $cache = new CachedCollection(); $cache->setCollection([['foo' => 'bar']]); $ref->setValue($reader, $cache); - self::assertSame(['foo' => 'bar'], (array) \iterator_to_array($reader->getIterator())[0]); + self::assertSame(['foo' => 'bar'], (array) iterator_to_array($reader->getIterator())[0]); } public function testRead(): void @@ -127,7 +132,7 @@ public function testLimit(): void public function testLimitException(): void { - $this->expectException(\InvalidArgumentException::class); + $this->expectException(InvalidArgumentException::class); (new EntityReader($this->select('user')))->withLimit(-1); } @@ -160,7 +165,7 @@ public function testFilter(): void public function testFilterHandlers(): void { - $baseReader = (new EntityReader($this->select('user')))->withAddedFilterHandlers(new StubFilterHandler()); + $baseReader = (new EntityReader($this->select('user'), [new StubFilterHandler()])); $reader = $baseReader->withFilter(new Equals('number', 2)); $this->assertFixtures([1], $reader->read()); @@ -202,7 +207,7 @@ public static function dataGetSql(): array public function testGetSql(string $expectedSql): void { $reader = (new EntityReader($this->select('user')))->withLimit(2)->withOffset(1); - $this->assertSame(\preg_replace('/\s+/', '', $expectedSql), \preg_replace('/\s+/', '', $reader->getSql())); + $this->assertSame(preg_replace('/\s+/', '', $expectedSql), preg_replace('/\s+/', '', $reader->getSql())); } public function testMakeFilterClosureException(): void @@ -213,4 +218,16 @@ public function testMakeFilterClosureException(): void $this->expectExceptionMessage(sprintf('Filter "%s" is not supported.', NotSupportedFilter::class)); $reader->withFilter(new NotSupportedFilter()); } + + public function testMakeFilterClosureSupportSelectQuery(): void + { + $reader = (new EntityReader( + $this + ->select('user') + ->buildQuery() + ->columns('number', 'email'), + )); + + $this->assertCount(5, $reader->read()); + } } diff --git a/tests/Feature/Base/Reader/ReaderWithFilter/BaseReaderWithAllTestCase.php b/tests/Feature/Base/Reader/ReaderWithFilter/BaseReaderWithAllTestCase.php index fdc5227..d964e1e 100644 --- a/tests/Feature/Base/Reader/ReaderWithFilter/BaseReaderWithAllTestCase.php +++ b/tests/Feature/Base/Reader/ReaderWithFilter/BaseReaderWithAllTestCase.php @@ -4,9 +4,54 @@ namespace Yiisoft\Data\Cycle\Tests\Feature\Base\Reader\ReaderWithFilter; +use Yiisoft\Data\Cycle\Reader\EntityReader; use Yiisoft\Data\Cycle\Tests\Feature\DataTrait; +use Yiisoft\Data\Reader\Filter\All; abstract class BaseReaderWithAllTestCase extends \Yiisoft\Data\Tests\Common\Reader\ReaderWithFilter\BaseReaderWithAllTestCase { use DataTrait; + + public function testWithReader(): void + { + $reader = ( + new EntityReader( + $this + ->select('user') + ->buildQuery() + ->columns('id', 'number'), + ) + )->withFilter(new All()); + + $actualResults = $reader->read(); + + $expectedResult = [ + ['id' => 1, 'number' => 1], + ['id' => 2, 'number' => 2], + ['id' => 3, 'number' => 3], + ['id' => 4, 'number' => 4], + ['id' => 5, 'number' => 5], + ]; + + $this->assertCount(5, $actualResults); + $actualResultsById = []; + foreach ($actualResults as $result) { + $actualResultsById[$result['id']] = $result; + } + foreach ($expectedResult as $expectedItem) { + $id = $expectedItem['id']; + + $this->assertArrayHasKey($id, $actualResultsById, "Результат с ID {$id} не найден."); + $actualItem = $actualResultsById[$id]; + + $this->assertEquals($expectedItem['id'], $actualItem['id']); + + $this->assertEqualsWithDelta( + $expectedItem['number'], + $actualItem['number'], + 0.01, + "The balance for user ID {$id} is not as expected." + ); + } + } } diff --git a/tests/Feature/Base/Reader/ReaderWithFilter/BaseReaderWithAndXTestCase.php b/tests/Feature/Base/Reader/ReaderWithFilter/BaseReaderWithAndXTestCase.php index 2041ce4..f8ff9c9 100644 --- a/tests/Feature/Base/Reader/ReaderWithFilter/BaseReaderWithAndXTestCase.php +++ b/tests/Feature/Base/Reader/ReaderWithFilter/BaseReaderWithAndXTestCase.php @@ -25,4 +25,29 @@ public function testNotSupportedFilterException(): void new AndX(new Equals('balance', '100.0'), new NotSupportedFilter(), new Equals('email', 'seed@beat')), ); } + + public function testFilterSupportSelectQuery(): void + { + $reader = (new EntityReader( + $this + ->select('user') + ->buildQuery() + ->columns('id', 'balance'), + )); + + $reader = $reader->withFilter(new AndX(new Equals('balance', 100.0), new Equals('id', 3))); + $result = $reader->read(); + + $expectedResult = [ + ['id' => 3, 'balance' => 100.0], + ]; + + $this->assertCount(1, $result); + $this->assertEquals($expectedResult[0]['id'], $result[0]['id']); + $this->assertEqualsWithDelta( + $expectedResult[0]['balance'], + $result[0]['balance'], + 0.01, + ); + } } diff --git a/tests/Feature/Base/Reader/ReaderWithFilter/BaseReaderWithNoneTestCase.php b/tests/Feature/Base/Reader/ReaderWithFilter/BaseReaderWithNoneTestCase.php index 0e4ef60..7ad32e8 100644 --- a/tests/Feature/Base/Reader/ReaderWithFilter/BaseReaderWithNoneTestCase.php +++ b/tests/Feature/Base/Reader/ReaderWithFilter/BaseReaderWithNoneTestCase.php @@ -4,9 +4,26 @@ namespace Yiisoft\Data\Cycle\Tests\Feature\Base\Reader\ReaderWithFilter; +use Yiisoft\Data\Cycle\Reader\EntityReader; use Yiisoft\Data\Cycle\Tests\Feature\DataTrait; +use Yiisoft\Data\Reader\Filter\None; abstract class BaseReaderWithNoneTestCase extends \Yiisoft\Data\Tests\Common\Reader\ReaderWithFilter\BaseReaderWithNoneTestCase { use DataTrait; + + public function testFilterSupportSelectQuery(): void + { + $reader = (new EntityReader( + $this + ->select('user') + ->buildQuery() + ->columns('id', 'balance'), + )); + + $reader = $reader->withFilter(new None()); + $result = $reader->read(); + + $this->assertSame([], $result); + } } diff --git a/tests/Feature/Base/Reader/ReaderWithFilter/BaseReaderWithOrXTestCase.php b/tests/Feature/Base/Reader/ReaderWithFilter/BaseReaderWithOrXTestCase.php index d618c83..f14481d 100644 --- a/tests/Feature/Base/Reader/ReaderWithFilter/BaseReaderWithOrXTestCase.php +++ b/tests/Feature/Base/Reader/ReaderWithFilter/BaseReaderWithOrXTestCase.php @@ -23,4 +23,43 @@ public function testNotsupportedFilterException(): void $this->expectExceptionMessage(sprintf('Filter "%s" is not supported.', NotSupportedFilter::class)); $reader->withFilter(new OrX(new Equals('number', 2), new NotSupportedFilter(), new Equals('number', 3))); } + + public function testFilterSupportSelectQuery(): void + { + $reader = (new EntityReader( + $this + ->select('user') + ->buildQuery() + ->columns('id', 'balance'), + )); + + $reader = $reader->withFilter(new OrX(new Equals('balance', 100.0), new Equals('id', 2))); + $actualResults = $reader->read(); + + $expectedResult = [ + ['id' => 2, 'balance' => 1.0], + ['id' => 3, 'balance' => 100.0], + ]; + + $this->assertCount(2, $actualResults); + $actualResultsById = []; + foreach ($actualResults as $result) { + $actualResultsById[$result['id']] = $result; + } + foreach ($expectedResult as $expectedItem) { + $id = $expectedItem['id']; + + $this->assertArrayHasKey($id, $actualResultsById, "Результат с ID {$id} не найден."); + $actualItem = $actualResultsById[$id]; + + $this->assertEquals($expectedItem['id'], $actualItem['id']); + + $this->assertEqualsWithDelta( + $expectedItem['balance'], + $actualItem['balance'], + 0.01, + "The balance for user ID {$id} is not as expected." + ); + } + } } diff --git a/tests/Support/StubFilterHandler.php b/tests/Support/StubFilterHandler.php index bc5f3c7..16c84ab 100644 --- a/tests/Support/StubFilterHandler.php +++ b/tests/Support/StubFilterHandler.php @@ -5,10 +5,9 @@ namespace Yiisoft\Data\Cycle\Tests\Support; use Yiisoft\Data\Cycle\Reader\QueryBuilderFilterHandler; -use Yiisoft\Data\Reader\FilterHandlerInterface; use Yiisoft\Data\Reader\FilterInterface; -final class StubFilterHandler implements QueryBuilderFilterHandler, FilterHandlerInterface +final class StubFilterHandler implements QueryBuilderFilterHandler { public function getFilterClass(): string {