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 @@ -11,6 +11,7 @@
- Chg #154: Raise minimum required PHP version to 8.1 (@vjik)
- Bug #155: Fix `Sort` configuration preparation (@vjik)
- Bug #155: Fix same named order fields in `Sort` were not overriding previous ones (@vjik)
- New #158: Add methods `PaginatorInterface::isSortable()` and `PaginatorInterface::withSort()` (@vjik)

## 1.0.1 January 25, 2023

Expand Down
13 changes: 12 additions & 1 deletion src/Paginator/KeysetPaginator.php
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,20 @@ public function getNextPageToken(): ?string
return $this->isOnLastPage() ? null : $this->currentLastValue;
}

public function isSortable(): bool
{
return true;
}

public function withSort(?Sort $sort): static
{
$new = clone $this;
$new->dataReader = $this->dataReader->withSort($sort);
return $new;
}

public function getSort(): ?Sort
{
/** @psalm-var SortableDataInterface $this->dataReader */
return $this->dataReader->getSort();
}

Expand Down
17 changes: 17 additions & 0 deletions src/Paginator/OffsetPaginator.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Generator;
use InvalidArgumentException;
use LogicException;
use Yiisoft\Data\Reader\CountableDataInterface;
use Yiisoft\Data\Reader\LimitableDataInterface;
use Yiisoft\Data\Reader\OffsetableDataInterface;
Expand Down Expand Up @@ -201,6 +202,22 @@ public function getTotalPages(): int
return (int) ceil($this->getTotalItems() / $this->pageSize);
}

public function isSortable(): bool
{
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.');
}

$new = clone $this;
$new->dataReader = $this->dataReader->withSort($sort);
return $new;
}

public function getSort(): ?Sort
{
return $this->dataReader instanceof SortableDataInterface ? $this->dataReader->getSort() : null;
Expand Down
16 changes: 16 additions & 0 deletions src/Paginator/PaginatorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,22 @@ public function getPageSize(): int;
*/
public function getCurrentPageSize(): int;

/**
* @return bool Whether sorting is supported.
*/
public function isSortable(): bool;

/**
* Get a new instance with sorting set.
*
* @param Sort|null $sort Sorting criteria or null for no sorting.
*
* @return static New instance.
*
* @throw LogicException When sorting is not supported.
*/
public function withSort(?Sort $sort): static;

/**
* Get current sort object.
*
Expand Down
23 changes: 23 additions & 0 deletions tests/Paginator/KeysetPaginatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1035,4 +1035,27 @@ public function testPageTypeWithNextPageToken(
$this->assertSame($expectedIsOnLastPage, $paginator->isOnLastPage());
$this->assertSame($expectedIds, ArrayHelper::getColumn($paginator->read(), 'id', keepKeys: false));
}

public function testIsSortable(): void
{
$sort = Sort::only(['id'])->withOrderString('id');
$reader = (new IterableDataReader([]))->withSort($sort);
$paginator = new KeysetPaginator($reader);

$this->assertTrue($paginator->isSortable());
}

public function testWithSort()
{
$sort1 = Sort::only(['id'])->withOrderString('id');
$reader = (new IterableDataReader([]))->withSort($sort1);
$paginator1 = new KeysetPaginator($reader);

$sort2 = $sort1->withOrderString('-id');
$paginator2 = $paginator1->withSort($sort2);

$this->assertNotSame($paginator1, $paginator2);
$this->assertSame($sort1, $paginator1->getSort());
$this->assertSame($sort2, $paginator2->getSort());
}
}
41 changes: 41 additions & 0 deletions tests/Paginator/OffsetPaginatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Yiisoft\Data\Tests\Paginator;

use InvalidArgumentException;
use LogicException;
use PHPUnit\Framework\Attributes\DataProvider;
use Yiisoft\Data\Paginator\OffsetPaginator;
use Yiisoft\Data\Paginator\PaginatorException;
Expand All @@ -15,6 +16,7 @@
use Yiisoft\Data\Reader\OffsetableDataInterface;
use Yiisoft\Data\Reader\ReadableDataInterface;
use Yiisoft\Data\Reader\Sort;
use Yiisoft\Data\Tests\Support\StubOffsetData;
use Yiisoft\Data\Tests\TestCase;

final class OffsetPaginatorTest extends TestCase
Expand Down Expand Up @@ -514,4 +516,43 @@ public function testImmutability(): void
$this->assertNotSame($paginator, $paginator->withPageSize(1));
$this->assertNotSame($paginator, $paginator->withCurrentPage(1));
}

public static function dataIsSupportSorting(): array
{
return [
[true, new IterableDataReader([])],
[false, new StubOffsetData()],
];
}

#[DataProvider('dataIsSupportSorting')]
public function testIsSortable(bool $expected, ReadableDataInterface $reader): void
{
$paginator = new OffsetPaginator($reader);

$this->assertSame($expected, $paginator->isSortable());
}

public function testWithSort(): void
{
$sort1 = Sort::only(['id'])->withOrderString('id');
$reader = (new IterableDataReader([]))->withSort($sort1);
$paginator1 = new OffsetPaginator($reader);

$sort2 = $sort1->withOrderString('-id');
$paginator2 = $paginator1->withSort($sort2);

$this->assertNotSame($paginator1, $paginator2);
$this->assertSame($sort1, $paginator1->getSort());
$this->assertSame($sort2, $paginator2->getSort());
}

public function testWithSortNonSortableData(): void
{
$paginator = new OffsetPaginator(new StubOffsetData());

$this->expectException(LogicException::class);
$this->expectExceptionMessage('Data reader does not support sorting.');
$paginator->withSort(null);
}
}
42 changes: 42 additions & 0 deletions tests/Support/StubOffsetData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Data\Tests\Support;

use Yiisoft\Data\Reader\CountableDataInterface;
use Yiisoft\Data\Reader\LimitableDataInterface;
use Yiisoft\Data\Reader\OffsetableDataInterface;
use Yiisoft\Data\Reader\ReadableDataInterface;

final class StubOffsetData implements
ReadableDataInterface,
OffsetableDataInterface,
CountableDataInterface,
LimitableDataInterface
{
public function read(): iterable
{
return [];
}

public function readOne(): array|object|null
{
return null;
}

public function count(): int
{
return 0;
}

public function withLimit(int $limit): static
{
return $this;
}

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