Skip to content

Commit 11dc863

Browse files
EranNLtaylorotwell
andauthored
[11.x] Added generics to paginators (#53512)
* Added generics to paginators * Added types tests * Added missing extends in doc and added cursor paginator types * Formatting * Formatting * Formatting * Moved back to covariant templates * Formatting * formatting --------- Co-authored-by: Taylor Otwell <[email protected]>
1 parent bab8683 commit 11dc863

File tree

10 files changed

+130
-17
lines changed

10 files changed

+130
-17
lines changed

src/Illuminate/Contracts/Pagination/CursorPaginator.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
namespace Illuminate\Contracts\Pagination;
44

5+
/**
6+
* @template TKey of array-key
7+
*
8+
* @template-covariant TValue
9+
*/
510
interface CursorPaginator
611
{
712
/**
@@ -53,7 +58,7 @@ public function nextPageUrl();
5358
/**
5459
* Get all of the items being paginated.
5560
*
56-
* @return array
61+
* @return array<TKey, TValue>
5762
*/
5863
public function items();
5964

src/Illuminate/Contracts/Pagination/LengthAwarePaginator.php

+7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
namespace Illuminate\Contracts\Pagination;
44

5+
/**
6+
* @template TKey of array-key
7+
*
8+
* @template-covariant TValue
9+
*
10+
* @extends Paginator<TKey, TValue>
11+
*/
512
interface LengthAwarePaginator extends Paginator
613
{
714
/**

src/Illuminate/Contracts/Pagination/Paginator.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
namespace Illuminate\Contracts\Pagination;
44

5+
/**
6+
* @template TKey of array-key
7+
*
8+
* @template-covariant TValue
9+
*/
510
interface Paginator
611
{
712
/**
@@ -46,7 +51,7 @@ public function previousPageUrl();
4651
/**
4752
* Get all of the items being paginated.
4853
*
49-
* @return array
54+
* @return array<TKey, TValue>
5055
*/
5156
public function items();
5257

src/Illuminate/Pagination/AbstractCursorPaginator.php

+8-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818
use Traversable;
1919

2020
/**
21-
* @mixin \Illuminate\Support\Collection
21+
* @template TKey of array-key
22+
*
23+
* @template-covariant TValue
24+
*
25+
* @mixin \Illuminate\Support\Collection<TKey, TValue>
2226
*/
2327
abstract class AbstractCursorPaginator implements Htmlable, Stringable
2428
{
@@ -27,7 +31,7 @@ abstract class AbstractCursorPaginator implements Htmlable, Stringable
2731
/**
2832
* All of the items being paginated.
2933
*
30-
* @var \Illuminate\Support\Collection
34+
* @var \Illuminate\Support\Collection<TKey, TValue>
3135
*/
3236
protected $items;
3337

@@ -388,7 +392,7 @@ public function loadMorphCount($relation, $relations)
388392
/**
389393
* Get the slice of items being paginated.
390394
*
391-
* @return array
395+
* @return array<TKey, TValue>
392396
*/
393397
public function items()
394398
{
@@ -524,7 +528,7 @@ public static function viewFactory()
524528
/**
525529
* Get an iterator for the items.
526530
*
527-
* @return \ArrayIterator
531+
* @return \ArrayIterator<TKey, TValue>
528532
*/
529533
public function getIterator(): Traversable
530534
{

src/Illuminate/Pagination/AbstractPaginator.php

+10-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
use Traversable;
1313

1414
/**
15-
* @mixin \Illuminate\Support\Collection
15+
* @template TKey of array-key
16+
*
17+
* @template-covariant TValue
18+
*
19+
* @mixin \Illuminate\Support\Collection<TKey, TValue>
1620
*/
1721
abstract class AbstractPaginator implements Htmlable, Stringable
1822
{
@@ -21,7 +25,7 @@ abstract class AbstractPaginator implements Htmlable, Stringable
2125
/**
2226
* All of the items being paginated.
2327
*
24-
* @var \Illuminate\Support\Collection
28+
* @var \Illuminate\Support\Collection<TKey, TValue>
2529
*/
2630
protected $items;
2731

@@ -310,7 +314,7 @@ public function loadMorphCount($relation, $relations)
310314
/**
311315
* Get the slice of items being paginated.
312316
*
313-
* @return array
317+
* @return array<TKey, TValue>
314318
*/
315319
public function items()
316320
{
@@ -649,7 +653,7 @@ public static function useBootstrapFive()
649653
/**
650654
* Get an iterator for the items.
651655
*
652-
* @return \ArrayIterator
656+
* @return \ArrayIterator<TKey, TValue>
653657
*/
654658
public function getIterator(): Traversable
655659
{
@@ -689,7 +693,7 @@ public function count(): int
689693
/**
690694
* Get the paginator's underlying collection.
691695
*
692-
* @return \Illuminate\Support\Collection
696+
* @return \Illuminate\Support\Collection<TKey, TValue>
693697
*/
694698
public function getCollection()
695699
{
@@ -699,7 +703,7 @@ public function getCollection()
699703
/**
700704
* Set the paginator's underlying collection.
701705
*
702-
* @param \Illuminate\Support\Collection $collection
706+
* @param \Illuminate\Support\Collection<TKey, TValue> $collection
703707
* @return $this
704708
*/
705709
public function setCollection(Collection $collection)

src/Illuminate/Pagination/CursorPaginator.php

+14-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@
1111
use IteratorAggregate;
1212
use JsonSerializable;
1313

14+
/**
15+
* @template TKey of array-key
16+
*
17+
* @template-covariant TValue
18+
*
19+
* @extends AbstractCursorPaginator<TKey, TValue>
20+
*
21+
* @implements Arrayable<TKey, TValue>
22+
* @implements ArrayAccess<TKey, TValue>
23+
* @implements IteratorAggregate<TKey, TValue>
24+
* @implements PaginatorContract<TKey, TValue>
25+
*/
1426
class CursorPaginator extends AbstractCursorPaginator implements Arrayable, ArrayAccess, Countable, IteratorAggregate, Jsonable, JsonSerializable, PaginatorContract
1527
{
1628
/**
@@ -23,7 +35,7 @@ class CursorPaginator extends AbstractCursorPaginator implements Arrayable, Arra
2335
/**
2436
* Create a new paginator instance.
2537
*
26-
* @param mixed $items
38+
* @param Collection<TKey, TValue>|Arrayable<TKey, TValue>|iterable<TKey, TValue>|null $items
2739
* @param int $perPage
2840
* @param \Illuminate\Pagination\Cursor|null $cursor
2941
* @param array $options (path, query, fragment, pageName)
@@ -47,7 +59,7 @@ public function __construct($items, $perPage, $cursor = null, array $options = [
4759
/**
4860
* Set the items for the paginator.
4961
*
50-
* @param mixed $items
62+
* @param Collection<TKey, TValue>|Arrayable<TKey, TValue>|iterable<TKey, TValue>|null $items
5163
* @return void
5264
*/
5365
protected function setItems($items)

src/Illuminate/Pagination/LengthAwarePaginator.php

+13-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@
1111
use IteratorAggregate;
1212
use JsonSerializable;
1313

14+
/**
15+
* @template TKey of array-key
16+
*
17+
* @template-covariant TValue
18+
*
19+
* @extends AbstractPaginator<TKey, TValue>
20+
*
21+
* @implements Arrayable<TKey, TValue>
22+
* @implements ArrayAccess<TKey, TValue>
23+
* @implements IteratorAggregate<TKey, TValue>
24+
* @implements LengthAwarePaginatorContract<TKey, TValue>
25+
*/
1426
class LengthAwarePaginator extends AbstractPaginator implements Arrayable, ArrayAccess, Countable, IteratorAggregate, Jsonable, JsonSerializable, LengthAwarePaginatorContract
1527
{
1628
/**
@@ -30,7 +42,7 @@ class LengthAwarePaginator extends AbstractPaginator implements Arrayable, Array
3042
/**
3143
* Create a new paginator instance.
3244
*
33-
* @param mixed $items
45+
* @param Collection<TKey, TValue>|Arrayable<TKey, TValue>|iterable<TKey, TValue>|null $items
3446
* @param int $total
3547
* @param int $perPage
3648
* @param int|null $currentPage

src/Illuminate/Pagination/Paginator.php

+14-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@
1111
use IteratorAggregate;
1212
use JsonSerializable;
1313

14+
/**
15+
* @template TKey of array-key
16+
*
17+
* @template-covariant TValue
18+
*
19+
* @extends AbstractPaginator<TKey, TValue>
20+
*
21+
* @implements Arrayable<TKey, TValue>
22+
* @implements ArrayAccess<TKey, TValue>
23+
* @implements IteratorAggregate<TKey, TValue>
24+
* @implements PaginatorContract<TKey, TValue>
25+
*/
1426
class Paginator extends AbstractPaginator implements Arrayable, ArrayAccess, Countable, IteratorAggregate, Jsonable, JsonSerializable, PaginatorContract
1527
{
1628
/**
@@ -23,7 +35,7 @@ class Paginator extends AbstractPaginator implements Arrayable, ArrayAccess, Cou
2335
/**
2436
* Create a new paginator instance.
2537
*
26-
* @param mixed $items
38+
* @param TValue[] $items
2739
* @param int $perPage
2840
* @param int|null $currentPage
2941
* @param array $options (path, query, fragment, pageName)
@@ -60,7 +72,7 @@ protected function setCurrentPage($currentPage)
6072
/**
6173
* Set the items for the paginator.
6274
*
63-
* @param mixed $items
75+
* @param Collection<TKey, TValue>|Arrayable<TKey, TValue>|iterable<TKey, TValue>|null $items
6476
* @return void
6577
*/
6678
protected function setItems($items)

tests/Pagination/PaginatorTest.php

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ class PaginatorTest extends TestCase
99
{
1010
public function testSimplePaginatorReturnsRelevantContextInformation()
1111
{
12+
/** @var Paginator<int, string> $p */
1213
$p = new Paginator(['item3', 'item4', 'item5'], 2, 2);
1314

1415
$this->assertEquals(2, $p->currentPage());

types/Pagination/Paginator.php

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
use Illuminate\Pagination\CursorPaginator;
4+
use Illuminate\Pagination\LengthAwarePaginator;
5+
use Illuminate\Pagination\Paginator;
6+
7+
use function PHPStan\Testing\assertType;
8+
9+
$items = [new Post(), new Post(), new Post()];
10+
11+
/** @var Paginator<int, Post> $paginator */
12+
$paginator = new Paginator($items, 1, 1);
13+
14+
assertType('array<int, Post>', $paginator->items());
15+
assertType('ArrayIterator<int, Post>', $paginator->getIterator());
16+
17+
$paginator->each(function ($post) {
18+
assertType('Post', $post);
19+
});
20+
21+
foreach ($paginator as $post) {
22+
assertType('Post', $post);
23+
}
24+
25+
/** @var LengthAwarePaginator<int, Post> $lengthAwarePaginator */
26+
$lengthAwarePaginator = new LengthAwarePaginator($items, 1, 1);
27+
28+
assertType('array<int, Post>', $lengthAwarePaginator->items());
29+
assertType('ArrayIterator<int, Post>', $lengthAwarePaginator->getIterator());
30+
31+
$lengthAwarePaginator->each(function ($post) {
32+
assertType('Post', $post);
33+
});
34+
35+
foreach ($lengthAwarePaginator as $post) {
36+
assertType('Post', $post);
37+
}
38+
39+
/** @var CursorPaginator<int, Post> $cursorPaginator */
40+
$cursorPaginator = new CursorPaginator($items, 1);
41+
42+
assertType('array<int, Post>', $cursorPaginator->items());
43+
assertType('ArrayIterator<int, Post>', $cursorPaginator->getIterator());
44+
45+
$cursorPaginator->each(function ($post) {
46+
assertType('Post', $post);
47+
});
48+
49+
foreach ($cursorPaginator as $post) {
50+
assertType('Post', $post);
51+
}

0 commit comments

Comments
 (0)