diff --git a/phpstan.neon b/phpstan.neon index 6909da9..ce86abc 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -4,4 +4,3 @@ includes: parameters: ignoreErrors: - identifier: missingType.iterableValue - - identifier: missingType.generics diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 12abbc7..80c9e4f 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -21,6 +21,7 @@ ./src/Entity/AbstractEntity.php ./src/Cache/ShlinkPredisClient.php + ./src/Paginator/Util/PagerfantaUtilsTrait.php diff --git a/src/Paginator/Paginator.php b/src/Paginator/Paginator.php index 96a10d1..2325885 100644 --- a/src/Paginator/Paginator.php +++ b/src/Paginator/Paginator.php @@ -8,6 +8,10 @@ use function max; +/** + * @template T + * @extends Pagerfanta + */ class Paginator extends Pagerfanta { public const ALL_ITEMS = -1; diff --git a/src/Paginator/Util/PagerfantaUtils.php b/src/Paginator/Util/PagerfantaUtils.php new file mode 100644 index 0000000..a7d61bf --- /dev/null +++ b/src/Paginator/Util/PagerfantaUtils.php @@ -0,0 +1,58 @@ + $paginator + * @param null|callable(T): mixed $serializer + */ + public static function serializePaginator( + Pagerfanta $paginator, + ?callable $serializer = null, + string $dataProp = 'data', + ): array { + $currentPageItems = ArrayUtils::iteratorToArray($paginator->getCurrentPageResults()); + + return [ + $dataProp => self::serializeItems($currentPageItems, $serializer), + 'pagination' => [ + 'currentPage' => $paginator->getCurrentPage(), + 'pagesCount' => $paginator->getNbPages(), + 'itemsPerPage' => $paginator->getMaxPerPage(), + 'itemsInCurrentPage' => count($currentPageItems), + 'totalItems' => $paginator->getNbResults(), + ], + ]; + } + + /** + * @param T[] $items + * @param null|callable(T): array $serializer + */ + private static function serializeItems(array $items, ?callable $serializer = null): array + { + return $serializer === null ? $items : array_map($serializer, $items); + } + + /** + * @param Pagerfanta $paginator + */ + public static function formatCurrentPageMessage(Pagerfanta $paginator, string $pattern): string + { + return sprintf($pattern, $paginator->getCurrentPage(), $paginator->getNbPages()); + } +} diff --git a/src/Paginator/Util/PagerfantaUtilsTrait.php b/src/Paginator/Util/PagerfantaUtilsTrait.php index bd5bad6..15ee1c4 100644 --- a/src/Paginator/Util/PagerfantaUtilsTrait.php +++ b/src/Paginator/Util/PagerfantaUtilsTrait.php @@ -4,42 +4,33 @@ namespace Shlinkio\Shlink\Common\Paginator\Util; -use Laminas\Stdlib\ArrayUtils; use Pagerfanta\Pagerfanta; use Shlinkio\Shlink\Common\Rest\DataTransformerInterface; -use function array_map; -use function count; -use function sprintf; - +/** + * @deprecated Use PagerfantaUtils instead + */ trait PagerfantaUtilsTrait { + /** + * @template T + * @param Pagerfanta $paginator + */ private function serializePaginator( Pagerfanta $paginator, ?DataTransformerInterface $transformer = null, string $dataProp = 'data', ): array { - $currentPageItems = ArrayUtils::iteratorToArray($paginator->getCurrentPageResults()); - - return [ - $dataProp => $this->serializeItems($currentPageItems, $transformer), - 'pagination' => [ - 'currentPage' => $paginator->getCurrentPage(), - 'pagesCount' => $paginator->getNbPages(), - 'itemsPerPage' => $paginator->getMaxPerPage(), - 'itemsInCurrentPage' => count($currentPageItems), - 'totalItems' => $paginator->getNbResults(), - ], - ]; - } - - private function serializeItems(array $items, ?DataTransformerInterface $transformer = null): array - { - return $transformer === null ? $items : array_map([$transformer, 'transform'], $items); + $serializer = $transformer !== null ? fn ($value) => $transformer->transform($value) : null; + return PagerfantaUtils::serializePaginator($paginator, $serializer, $dataProp); } + /** + * @template T + * @param Pagerfanta $paginator + */ private function formatCurrentPageMessage(Pagerfanta $paginator, string $pattern): string { - return sprintf($pattern, $paginator->getCurrentPage(), $paginator->getNbPages()); + return PagerfantaUtils::formatCurrentPageMessage($paginator, $pattern); } } diff --git a/src/Rest/DataTransformerInterface.php b/src/Rest/DataTransformerInterface.php index 3672a5c..bf06d0f 100644 --- a/src/Rest/DataTransformerInterface.php +++ b/src/Rest/DataTransformerInterface.php @@ -4,6 +4,7 @@ namespace Shlinkio\Shlink\Common\Rest; +/** @deprecated */ interface DataTransformerInterface { /** diff --git a/src/Validation/OrderByFilter.php b/src/Validation/OrderByFilter.php index 0925130..c89548d 100644 --- a/src/Validation/OrderByFilter.php +++ b/src/Validation/OrderByFilter.php @@ -9,6 +9,9 @@ use function is_string; use function Shlinkio\Shlink\Common\parseOrderBy; +/** + * @extends AbstractFilter + */ class OrderByFilter extends AbstractFilter { /** diff --git a/test/Doctrine/Mapping/EnhancedPHPDriverTest.php b/test/Doctrine/Mapping/EnhancedPHPDriverTest.php index 1780723..8f3ac90 100644 --- a/test/Doctrine/Mapping/EnhancedPHPDriverTest.php +++ b/test/Doctrine/Mapping/EnhancedPHPDriverTest.php @@ -17,6 +17,7 @@ class EnhancedPHPDriverTest extends TestCase { private MockObject & FileLocator $loader; + /** @var MockObject & ClassMetadata */ private MockObject & ClassMetadata $meta; public function setUp(): void diff --git a/test/Mock/MockRepository.php b/test/Mock/MockRepository.php index 44e4bde..84b2db7 100644 --- a/test/Mock/MockRepository.php +++ b/test/Mock/MockRepository.php @@ -6,6 +6,9 @@ use Doctrine\ORM\EntityRepository; +/** + * @extends EntityRepository + */ class MockRepository extends EntityRepository { } diff --git a/test/Paginator/PaginatorTest.php b/test/Paginator/PaginatorTest.php index d2a54fe..ba435cf 100644 --- a/test/Paginator/PaginatorTest.php +++ b/test/Paginator/PaginatorTest.php @@ -11,9 +11,14 @@ use PHPUnit\Framework\TestCase; use Shlinkio\Shlink\Common\Paginator\Paginator; +/** + * @template T + */ class PaginatorTest extends TestCase { + /** @var Paginator */ private Paginator $paginator; + /** @var MockObject & AdapterInterface */ private MockObject & AdapterInterface $adapter; protected function setUp(): void diff --git a/test/Paginator/Util/PagerfantaUtilsTraitTest.php b/test/Paginator/Util/PagerfantaUtilsTest.php similarity index 79% rename from test/Paginator/Util/PagerfantaUtilsTraitTest.php rename to test/Paginator/Util/PagerfantaUtilsTest.php index 5ef929b..9d3dd47 100644 --- a/test/Paginator/Util/PagerfantaUtilsTraitTest.php +++ b/test/Paginator/Util/PagerfantaUtilsTest.php @@ -9,18 +9,22 @@ use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; -use Shlinkio\Shlink\Common\Paginator\Util\PagerfantaUtilsTrait; +use Shlinkio\Shlink\Common\Paginator\Util\PagerfantaUtils; use function range; -class PagerfantaUtilsTraitTest extends TestCase +/** + * @template T + */ +class PagerfantaUtilsTest extends TestCase { - use PagerfantaUtilsTrait; - + /** + * @param Pagerfanta $paginator + */ #[Test, DataProvider('providePaginatorAdapters')] public function paginatorIsSerializedAsExpected(array $expectedSerialization, Pagerfanta $paginator): void { - $result = $this->serializePaginator($paginator); + $result = PagerfantaUtils::serializePaginator($paginator); self::assertEquals($expectedSerialization, $result); } @@ -86,7 +90,7 @@ public static function providePaginatorAdapters(): iterable #[Test, DataProvider('provideDataProps')] public function paginatorIsSerializedWithExpectedDataProp(string $prop): void { - $result = $this->serializePaginator(new Pagerfanta(new ArrayAdapter([])), null, $prop); + $result = PagerfantaUtils::serializePaginator(new Pagerfanta(new ArrayAdapter([])), dataProp: $prop); self::assertArrayNotHasKey('data', $result); self::assertArrayHasKey($prop, $result); @@ -99,13 +103,27 @@ public static function provideDataProps(): iterable yield 'something' => ['something']; } + #[Test] + public function paginatorIsSerializedWithProvidedCallback(): void + { + ['data' => $data] = PagerfantaUtils::serializePaginator( + new Pagerfanta(new ArrayAdapter(range(1, 10))), + static fn (int $value) => $value * 2, + ); + + self::assertEquals([2, 4, 6, 8, 10, 12, 14, 16, 18, 20], $data); + } + + /** + * @param Pagerfanta $paginator + */ #[Test, DataProvider('providePaginatorsToFormat')] public function pageMessageIsProperlyFormatted( string $expectedMessage, string $pattern, Pagerfanta $paginator, ): void { - self::assertEquals($expectedMessage, $this->formatCurrentPageMessage($paginator, $pattern)); + self::assertEquals($expectedMessage, PagerfantaUtils::formatCurrentPageMessage($paginator, $pattern)); } public static function providePaginatorsToFormat(): iterable diff --git a/test/Repository/CustomRepository.php b/test/Repository/CustomRepository.php index ba84b46..406dc80 100644 --- a/test/Repository/CustomRepository.php +++ b/test/Repository/CustomRepository.php @@ -6,6 +6,9 @@ use Doctrine\ORM\EntityRepository; +/** + * @extends EntityRepository + */ class CustomRepository extends EntityRepository { }