Skip to content

Commit

Permalink
refactor: PageableInterface::getPages() now returns Iterator inst…
Browse files Browse the repository at this point in the history
…ead of `Traversable` (non-backward compatible for implementors) (#247)
  • Loading branch information
priyadi authored Jan 3, 2025
1 parent b7dbe42 commit a59a81b
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 10 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

# 0.20.0

* refactor: `PageableInterface::getPages()` now returns `Iterator` instead of
`Traversable` (non-backward compatible for implementors)

# 0.19.1

* chore: static analysis
Expand Down
76 changes: 76 additions & 0 deletions packages/rekapager-contracts/src/Internal/PageableIterator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

declare(strict_types=1);

/*
* This file is part of rekalogika/rekapager package.
*
* (c) Priyadi Iman Nurcahyo <https://rekalogika.dev>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

namespace Rekalogika\Contracts\Rekapager\Internal;

use Rekalogika\Contracts\Rekapager\Exception\LogicException;
use Rekalogika\Contracts\Rekapager\PageInterface;

/**
* @template TKey of array-key
* @template-covariant T
* @implements \Iterator<int,PageInterface<TKey,T>>
*/
final class PageableIterator implements \Iterator
{
private int $position = 0;

/**
* @var PageInterface<TKey,T>
*/
private ?PageInterface $currentPage;

/**
* @param PageInterface<TKey,T> $startPage
*/
public function __construct(
private readonly PageInterface $startPage,
) {
$this->currentPage = $this->startPage;
}

public function current(): mixed
{
if ($this->currentPage === null) {
throw new LogicException('The iterator is not valid');
}

return $this->currentPage;
}

public function next(): void
{
if ($this->currentPage === null) {
return;
}

$this->currentPage = $this->currentPage->getNextPage();
$this->position++;
}

public function key(): mixed
{
return $this->position;
}

public function valid(): bool
{
return $this->currentPage !== null;
}

public function rewind(): void
{
$this->currentPage = $this->startPage;
$this->position = 0;
}
}
4 changes: 2 additions & 2 deletions packages/rekapager-contracts/src/PageableInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ public function getLastPage(): ?PageInterface;
*
* @param object|null $start The identifier of the starting page. If null,
* it will start from the first page.
* @return \Traversable<PageInterface<TKey,T>>
* @return \Iterator<PageInterface<TKey,T>>
*/
public function getPages(?object $start = null): \Traversable;
public function getPages(?object $start = null): \Iterator;

/**
* Gets the number of items per page. The actual items in the page may be
Expand Down
11 changes: 4 additions & 7 deletions packages/rekapager-contracts/src/Trait/PageableTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace Rekalogika\Contracts\Rekapager\Trait;

use Rekalogika\Contracts\Rekapager\Internal\PageableIterator;
use Rekalogika\Contracts\Rekapager\PageInterface;

/**
Expand Down Expand Up @@ -56,20 +57,16 @@ public function getTotalPages(): ?int
}

/**
* @return \Traversable<PageInterface<TKey,T>>
* @return \Iterator<PageInterface<TKey,T>>
*/
public function getPages(?object $start = null): \Traversable
public function getPages(?object $start = null): \Iterator
{
if ($start === null) {
$page = $this->getFirstPage();
} else {
$page = $this->getPageByIdentifier($start);
}

while ($page !== null) {
yield $page;

$page = $page->getNextPage();
}
return new PageableIterator($page);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public function getPageIdentifierClass(): string
}

#[\Override]
public function getPages(?object $start = null): \Traversable
public function getPages(?object $start = null): \Iterator
{
return $this->pageable->getPages($start);
}
Expand Down
4 changes: 4 additions & 0 deletions tests/src/ArchitectureTests/ArchitectureTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ public function testPackageContracts(): Rule
->classes(
Selector::inNamespace('Rekalogika\Contracts\Rekapager'),
Selector::classname(\Traversable::class),
Selector::classname(\Iterator::class),
Selector::classname(\Countable::class),
Selector::classname(\UnexpectedValueException::class),
Selector::classname(\RuntimeException::class),
Expand Down Expand Up @@ -201,6 +202,7 @@ public function testPackageKeysetPagination(): Rule
Selector::classname(Base64Url::class),
Selector::classname(\Closure::class),
Selector::classname(\Traversable::class),
Selector::classname(\Iterator::class),
Selector::classname(\ArrayIterator::class),
Selector::classname(\BackedEnum::class),
Selector::classname(UuidInterface::class),
Expand All @@ -226,6 +228,7 @@ public function testPackageOffsetPagination(): Rule
Selector::classname(\Closure::class),
Selector::classname(\IteratorAggregate::class),
Selector::classname(\Traversable::class),
Selector::classname(\Iterator::class),
);
}

Expand All @@ -244,6 +247,7 @@ public function testPackagePagerfantaAdapter(): Rule
Selector::inNamespace('Rekalogika\Rekapager\Adapter\Common'),
Selector::classname(\Closure::class),
Selector::classname(\Traversable::class),
Selector::classname(\Iterator::class),
);
}

Expand Down

0 comments on commit a59a81b

Please sign in to comment.