Skip to content
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
- Enh #190: Use `str_contains` for case-sensitive match in `LikeHandler` (@samdark)
- Enh #194: Improve psalm annotations in `LimitableDataInterface` (@vjik)
- Bug #195: Fix invalid count in `IterableDataReader` when limit or/and offset used (@vjik)
- Enh #201: Disable sorting when limit is set explicitly in a paginator (@samdark)
- Enh #202: Check that correct sort is passed to `withSort()` of keyset paginator (@samdark)
- Enh #207: More secific Psalm type for OffsetPaginator::withCurrentPage() (@samdark)

Expand Down
18 changes: 14 additions & 4 deletions src/Paginator/OffsetPaginator.php
Original file line number Diff line number Diff line change
Expand Up @@ -224,15 +224,22 @@ public function getTotalPages(): int
return (int) ceil($this->getTotalItems() / $this->pageSize);
}

/**
* @psalm-assert-if-true SortableDataInterface $this->dataReader
*/
public function isSortable(): bool
{
if ($this->dataReader instanceof LimitableDataInterface && $this->dataReader->getLimit() !== null) {
return false;
}

return $this->dataReader instanceof SortableDataInterface;
}

public function withSort(?Sort $sort): static
{
if (!$this->dataReader instanceof SortableDataInterface) {
throw new LogicException('Data reader does not support sorting.');
if (!$this->isSortable()) {
throw new LogicException('Changing sorting is not supported.');
}

$new = clone $this;
Expand All @@ -245,15 +252,18 @@ public function getSort(): ?Sort
return $this->dataReader instanceof SortableDataInterface ? $this->dataReader->getSort() : null;
}

/**
* @psalm-assert-if-true FilterableDataInterface $this->dataReader
*/
public function isFilterable(): bool
{
return $this->dataReader instanceof FilterableDataInterface;
}

public function withFilter(FilterInterface $filter): static
{
if (!$this->dataReader instanceof FilterableDataInterface) {
throw new LogicException('Data reader does not support filtering.');
if (!$this->isFilterable()) {
throw new LogicException('Changing filtering is not supported.');
}

$new = clone $this;
Expand Down
8 changes: 4 additions & 4 deletions src/Paginator/PaginatorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public function getPageSize(): int;
public function getCurrentPageSize(): int;

/**
* @return bool Whether sorting is supported.
* @return bool Whether changing sorting via {@see withSorting()} is supported.
*/
public function isSortable(): bool;

Expand All @@ -104,7 +104,7 @@ public function isSortable(): bool;
*
* @param Sort|null $sort Sorting criteria or null for no sorting.
*
* @throws LogicException When sorting isn't supported.
* @throws LogicException When changing sorting isn't supported.
* @return static New instance.
*/
public function withSort(?Sort $sort): static;
Expand All @@ -117,7 +117,7 @@ public function withSort(?Sort $sort): static;
public function getSort(): ?Sort;

/**
* @return bool Whether filtering is supported.
* @return bool Whether changing filter via {@see withFilter()} is supported.
*/
public function isFilterable(): bool;

Expand All @@ -126,7 +126,7 @@ public function isFilterable(): bool;
*
* @param FilterInterface $filter Data reading criteria.
*
* @throws LogicException When filtering isn't supported.
* @throws LogicException When changing filter isn't supported.
* @return static New instance.
*/
public function withFilter(FilterInterface $filter): static;
Expand Down
9 changes: 5 additions & 4 deletions tests/Paginator/OffsetPaginatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -530,8 +530,9 @@ public function testImmutability(): void
public static function dataIsSupportSorting(): array
{
return [
[true, new IterableDataReader([])],
[false, new StubOffsetData()],
'IterableDataReader' => [true, new IterableDataReader([])],
'StubOffsetData' => [false, new StubOffsetData()],
'StubOffsetDataWithLimit' => [false, (new StubOffsetData())->withLimit(10)],
];
}

Expand Down Expand Up @@ -562,7 +563,7 @@ public function testWithSortNonSortableData(): void
$paginator = new OffsetPaginator(new StubOffsetData());

$this->expectException(LogicException::class);
$this->expectExceptionMessage('Data reader does not support sorting.');
$this->expectExceptionMessage('Changing sorting is not supported.');
$paginator->withSort(null);
}

Expand Down Expand Up @@ -601,7 +602,7 @@ public function testWithFilterNonFilterableData(): void
$paginator = new OffsetPaginator(new StubOffsetData());

$this->expectException(LogicException::class);
$this->expectExceptionMessage('Data reader does not support filtering.');
$this->expectExceptionMessage('Changing filtering is not supported.');
$paginator->withFilter(new Equals('id', 2));
}

Expand Down
14 changes: 11 additions & 3 deletions tests/Support/StubOffsetData.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ final class StubOffsetData implements
CountableDataInterface,
LimitableDataInterface
{
/**
* @var int|null
* @psalm-var non-negative-int
*/
private ?int $limit = null;

public function read(): iterable
{
return [];
Expand All @@ -32,17 +38,19 @@ public function count(): int

public function withLimit(?int $limit): static
{
return $this;
$new = clone $this;
$new->limit = $limit;
return $new;
}

public function withOffset(int $offset): static
{
return $this;
}

public function getLimit(): int
public function getLimit(): ?int
{
return 0;
return $this->limit;
}

public function getOffset(): int
Expand Down