Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

app updates #86

Merged
merged 9 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ composer.lock
/vendor/
.php-cs-fixer.cache
.phpunit.result.cache

/node_modules
1 change: 1 addition & 0 deletions .husky/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
_
4 changes: 4 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn lint-staged
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.58",
"phpunit/phpunit": "^9.6.15",
"phpunit/phpunit": "^9.6.15|^10.5.20|^11.1.3",
"phpstan/phpstan": "^1.11.3",
"rector/rector": "^1.1",
"vimeo/psalm": "^5.24",
Expand Down
12 changes: 12 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"devDependencies": {
"husky": ">=6",
"lint-staged": ">=10"
},
"lint-staged": {
"*.php": "php-cs-fixer fix --config=.php-cs-fixer.dist.php"
},
"scripts": {
"prepare": "husky install"
}
}
1 change: 1 addition & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@
<UnusedClass errorLevel="suppress" />
<PossiblyUnusedMethod errorLevel="suppress" />
<PossiblyUnusedProperty errorLevel="suppress" />
<UndefinedAttributeClass errorLevel="suppress" />
</issueHandlers>
</psalm>
26 changes: 13 additions & 13 deletions rector.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@

use Rector\Config\RectorConfig;
use Rector\Doctrine\Set\DoctrineSetList;
use Rector\Set\ValueObject\LevelSetList;
use Rector\Set\ValueObject\SetList;

return static function (RectorConfig $config): void {
$config->importShortClasses();
$config->importNames();

$config->paths([
return RectorConfig::configure()
->withImportNames()
->withPaths([
__DIR__ . '/src',
__DIR__ . '/tests',
]);

$config->import(LevelSetList::UP_TO_PHP_80);
$config->import(SetList::CODE_QUALITY);
$config->import(DoctrineSetList::DOCTRINE_CODE_QUALITY);
};
])
->withPhpSets()
->withPreparedSets(
deadCode: true,
codeQuality: true
)
->withSets([
DoctrineSetList::DOCTRINE_CODE_QUALITY,
])
;
2 changes: 1 addition & 1 deletion src/Configuration/OrderConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
use Closure;
use Doctrine\Common\Collections\Criteria;

class OrderConfiguration
final class OrderConfiguration
{
public function __construct(
private string $fieldName,
Expand Down
2 changes: 1 addition & 1 deletion src/Configuration/OrderConfigurations.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
* @implements IteratorAggregate<int, OrderConfiguration>
* @implements ArrayAccess<int, OrderConfiguration>
*/
class OrderConfigurations implements IteratorAggregate, Countable, ArrayAccess
final class OrderConfigurations implements IteratorAggregate, Countable, ArrayAccess
{
/** @var array<int|string, OrderConfiguration> */
private array $orderConfigurations;
Expand Down
2 changes: 1 addition & 1 deletion src/Iterator/ChunkIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
*
* @implements IteratorAggregate<TKey, TValue>
*/
class ChunkIterator implements IteratorAggregate
final class ChunkIterator implements IteratorAggregate
{
/**
* @param iterable<TKey, TValue> $data
Expand Down
32 changes: 31 additions & 1 deletion src/Pagination/CursorPagination.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,30 @@

use function count;

use Countable;
use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\Query\Expr\Comparison;
use Doctrine\ORM\Query\Expr\Orx;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Tools\Pagination\Paginator;
use Generator;
use IteratorAggregate;
use LogicException;
use Silarhi\CursorPagination\Configuration\OrderConfigurations;
use Silarhi\CursorPagination\Iterator\ChunkIterator;

/**
* @template-covariant T
*
* @implements IteratorAggregate<int, T>
*/
class CursorPagination
final class CursorPagination implements IteratorAggregate, Countable
{
/** @var array<int|string, mixed> */
private array $afterValues = [];

private ?int $nbResults = null;

public function __construct(
private QueryBuilder $queryBuilder,
private OrderConfigurations $orderConfigurations,
Expand All @@ -41,6 +47,30 @@ public function __construct(
) {
}

public function getNbPages(): int
{
return 0 >= $this->maxPerPages
? 0
: (int) ceil($this->count() / $this->maxPerPages);
}

public function getIterator(): Generator
{
return $this->getResults();
}

public function count(): int
{
if (null === $this->nbResults) {
$paginator = new Paginator($this->queryBuilder, $this->fetchJoinCollection);
$paginator->setUseOutputWalkers($this->useOutputWalkers);

$this->nbResults = $paginator->count();
}

return $this->nbResults;
}

/**
* @return iterable<int, array<T>>
*/
Expand Down
2 changes: 1 addition & 1 deletion tests/DoctrineTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ protected function setUp(): void
parent::setUp();

if (!extension_loaded('pdo_sqlite')) {
$this->markTestSkipped('Extension pdo_sqlite is required.');
self::markTestSkipped('Extension pdo_sqlite is required.');
}

$connection = DriverManager::getConnection(
Expand Down
2 changes: 1 addition & 1 deletion tests/Entity/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class User
final class User
{
#[ORM\Id]
#[ORM\GeneratedValue]
Expand Down
2 changes: 1 addition & 1 deletion tests/Fixtures/UserDataLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
use Doctrine\Persistence\ObjectManager;
use Silarhi\CursorPagination\Tests\Entity\User;

class UserDataLoader implements FixtureInterface
final class UserDataLoader implements FixtureInterface
{
public function load(ObjectManager $manager): void
{
Expand Down
6 changes: 4 additions & 2 deletions tests/Iterator/ChunkIteratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,19 @@

use function count;

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Silarhi\CursorPagination\Iterator\ChunkIterator;

class ChunkIteratorTest extends TestCase
final class ChunkIteratorTest extends TestCase
{
/**
* @dataProvider provideChunk
*
* @param iterable<int, mixed> $data
* @param array<int, mixed> $expectedYields
*/
#[DataProvider('provideChunk')]
public function testGetIterator(iterable $data, int $size, array $expectedYields): void
{
$iterator = new ChunkIterator($data, $size);
Expand All @@ -40,7 +42,7 @@ public function testGetIterator(iterable $data, int $size, array $expectedYields
/**
* @return iterable<int, array{data: iterable<int, mixed>, size: int, expectedYields: array<int, array<int, mixed>>}>
*/
public function provideChunk(): iterable
public static function provideChunk(): iterable
{
yield [
'data' => [1, 2, 3, 4, 5],
Expand Down
64 changes: 52 additions & 12 deletions tests/Pagination/CursorPaginationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,18 @@

use function count;

use PHPUnit\Framework\Attributes\DataProvider;
use Silarhi\CursorPagination\Configuration\OrderConfiguration;
use Silarhi\CursorPagination\Configuration\OrderConfigurations;
use Silarhi\CursorPagination\Pagination\CursorPagination;
use Silarhi\CursorPagination\Tests\DoctrineTestCase;
use Silarhi\CursorPagination\Tests\Entity\User;

class CursorPaginationTest extends DoctrineTestCase
final class CursorPaginationTest extends DoctrineTestCase
{
public function testSimplePagination(): void
{
$queryBuilder = $this
->entityManager
->getRepository(User::class)
->createQueryBuilder('u')
;

/** @var CursorPagination<User> $pagination */
$pagination = new CursorPagination($queryBuilder, new OrderConfigurations(
new OrderConfiguration('u.id', fn (User $user) => $user->getId()),
), 2);
$pagination = $this->getSimpleCursorPagination();

$expectedResults = range(1, 10);
$index = 0;
Expand Down Expand Up @@ -61,6 +53,7 @@ public function testSimplePagination(): void
/**
* @dataProvider provideInverse
*/
#[DataProvider('provideInverse')]
public function testComplexPagination(bool $inverseConfigurations, bool $reverseOrder): void
{
$queryBuilder = $this
Expand Down Expand Up @@ -152,11 +145,58 @@ public function testComplexReversedPagination(): void
/**
* @return iterable<int, array<int, bool>>
*/
public function provideInverse(): iterable
public static function provideInverse(): iterable
{
yield [true, true];
yield [true, false];
yield [false, true];
yield [false, false];
}

/**
* @dataProvider provideInverse
*/
#[DataProvider('provideInverse')]
public function testCount(bool $loadResultsBeforeCount): void
{
$pagination = $this->getSimpleCursorPagination();

if ($loadResultsBeforeCount) {
iterator_to_array($pagination->getResults());
}

self::assertEquals(10, $pagination->count());
self::assertEquals(10, count($pagination));
}

/**
* @return iterable<int, array<int, bool>>
*/
public function provideLoadResults(): iterable
{
yield [true];
yield [false];
}

public function testGetPages(): void
{
$pagination = $this->getSimpleCursorPagination();

self::assertEquals(5, $pagination->getNbPages());
}

/**
* @return CursorPagination<User>
*/
private function getSimpleCursorPagination(): CursorPagination
{
$queryBuilder = $this
->entityManager
->getRepository(User::class)
->createQueryBuilder('u');

return new CursorPagination($queryBuilder, new OrderConfigurations(
new OrderConfiguration('u.id', fn (User $user) => $user->getId()),
), 2);
}
}
Loading