Skip to content

Commit

Permalink
Make paginator covariant (#10002)
Browse files Browse the repository at this point in the history
  • Loading branch information
VincentLanglet authored Aug 30, 2022
1 parent 8dfe8b8 commit 8d03f8f
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 3 deletions.
7 changes: 4 additions & 3 deletions lib/Doctrine/ORM/Tools/Pagination/Paginator.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Doctrine\ORM\QueryBuilder;
use IteratorAggregate;
use ReturnTypeWillChange;
use Traversable;

use function array_key_exists;
use function array_map;
Expand All @@ -25,7 +26,7 @@
/**
* The paginator can handle various complex scenarios with DQL.
*
* @template T
* @template-covariant T
*/
class Paginator implements Countable, IteratorAggregate
{
Expand Down Expand Up @@ -124,8 +125,8 @@ public function count()
/**
* {@inheritdoc}
*
* @return ArrayIterator
* @psalm-return ArrayIterator<array-key, T>
* @return Traversable
* @psalm-return Traversable<array-key, T>
*/
#[ReturnTypeWillChange]
public function getIterator()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

declare(strict_types=1);

namespace Doctrine\StaticAnalysis\Tools\Pagination;

use Doctrine\ORM\Tools\Pagination\Paginator;

/**
* @template-covariant T of object
*/
abstract class PaginatorFactory
{
/** @var class-string<T> */
private $class;

/**
* @param class-string<T> $class
*/
final public function __construct(string $class)
{
$this->class = $class;
}

/**
* @return class-string<T>
*/
public function getClass(): string
{
return $this->class;
}

/**
* @psalm-return Paginator<T>
*/
abstract public function createPaginator(): Paginator;
}

interface Animal
{
}

class Cat implements Animal
{
}

/**
* @param Paginator<Animal> $paginator
*/
function getFirstAnimal(Paginator $paginator): ?Animal
{
foreach ($paginator as $result) {
return $result;
}

return null;
}

/**
* @param PaginatorFactory<Cat> $catPaginatorFactory
*/
function test(PaginatorFactory $catPaginatorFactory): ?Animal
{
return getFirstAnimal($catPaginatorFactory->createPaginator());
}

2 comments on commit 8d03f8f

@raziel057
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello, due to this change I got a phpstan issue when calling $paginator->getIterator()->getArrayCopy():

vendor/bin/phpstan analyse src/ --level=5
Note: Using configuration file ...\phpstan.neon.
 1124/1124 [============================] 100%

 ------ -------------------------------------------------------------------------------
  Line   XXX.php
 ------ -------------------------------------------------------------------------------
  95     Call to an undefined method Traversable<(int|string), mixed>::getArrayCopy().
 ------ -------------------------------------------------------------------------------

@raziel057
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think a valid way would be to use iterator_to_array($paginator->getIterator()) as a replacement in that case?

Please sign in to comment.