0 follower

Final Class Yiisoft\Data\Paginator\OffsetPaginator

InheritanceYiisoft\Data\Paginator\OffsetPaginator
ImplementsYiisoft\Data\Paginator\PaginatorInterface

Offset paginator.

Advantages:

  • Total number of pages is available
  • Can get to specific page
  • Data can be unordered
  • The limit set in the data reader is taken into account

Disadvantages:

  • Performance degrades with page number increase
  • Insertions or deletions in the middle of the data are making results inconsistent

Public Methods

Hide inherited methods

Method Description Defined By
__construct() Yiisoft\Data\Paginator\OffsetPaginator
getCurrentPage() Get the current page number. Yiisoft\Data\Paginator\OffsetPaginator
getCurrentPageSize() Yiisoft\Data\Paginator\OffsetPaginator
getFilter() Yiisoft\Data\Paginator\OffsetPaginator
getNextToken() Yiisoft\Data\Paginator\OffsetPaginator
getOffset() Get offset for the current page, that is the number of items to skip before the current page is reached. Yiisoft\Data\Paginator\OffsetPaginator
getPageSize() Yiisoft\Data\Paginator\OffsetPaginator
getPreviousToken() Yiisoft\Data\Paginator\OffsetPaginator
getSort() Yiisoft\Data\Paginator\OffsetPaginator
getToken() Yiisoft\Data\Paginator\OffsetPaginator
getTotalItems() Get total number of items in the whole data reader being paginated. Yiisoft\Data\Paginator\OffsetPaginator
getTotalPages() Get total number of pages in a data reader being paginated. Yiisoft\Data\Paginator\OffsetPaginator
isFilterable() Yiisoft\Data\Paginator\OffsetPaginator
isOnFirstPage() Yiisoft\Data\Paginator\OffsetPaginator
isOnLastPage() Yiisoft\Data\Paginator\OffsetPaginator
isPaginationRequired() Yiisoft\Data\Paginator\OffsetPaginator
isSortable() Yiisoft\Data\Paginator\OffsetPaginator
nextPage() Yiisoft\Data\Paginator\OffsetPaginator
previousPage() Yiisoft\Data\Paginator\OffsetPaginator
read() Yiisoft\Data\Paginator\OffsetPaginator
readOne() Yiisoft\Data\Paginator\OffsetPaginator
withCurrentPage() Get a new instance with the given current page number set. Yiisoft\Data\Paginator\OffsetPaginator
withFilter() Yiisoft\Data\Paginator\OffsetPaginator
withPageSize() Yiisoft\Data\Paginator\OffsetPaginator
withSort() Yiisoft\Data\Paginator\OffsetPaginator
withToken() Yiisoft\Data\Paginator\OffsetPaginator

Constants

Hide inherited constants

Constant Value Description Defined By
DEFAULT_PAGE_SIZE 10 Page size that is used in case it is not set explicitly. Yiisoft\Data\Paginator\PaginatorInterface

Method Details

Hide inherited methods

__construct() public method

public __construct( Yiisoft\Data\Reader\ReadableDataInterface $dataReader ): mixed
$dataReader Yiisoft\Data\Reader\ReadableDataInterface

Data reader being paginated.

                public function __construct(ReadableDataInterface $dataReader)
{
    if (!$dataReader instanceof OffsetableDataInterface) {
        throw new InvalidArgumentException(sprintf(
            'Data reader should implement "%s" in order to be used with offset paginator.',
            OffsetableDataInterface::class,
        ));
    }
    if (!$dataReader instanceof CountableDataInterface) {
        throw new InvalidArgumentException(sprintf(
            'Data reader should implement "%s" in order to be used with offset paginator.',
            CountableDataInterface::class,
        ));
    }
    if (!$dataReader instanceof LimitableDataInterface) {
        throw new InvalidArgumentException(sprintf(
            'Data reader should implement "%s" in order to be used with offset paginator.',
            LimitableDataInterface::class,
        ));
    }
    $this->dataReader = $dataReader;
    $this->token = PageToken::next('1');
}

            
getCurrentPage() public method

Get the current page number.

public getCurrentPage( ): integer
return integer

Current page number.

                public function getCurrentPage(): int
{
    /** @var positive-int */
    return (int) $this->token->value;
}

            
getCurrentPageSize() public method

public getCurrentPageSize( ): integer

                public function getCurrentPageSize(): int
{
    $pages = $this->getInternalTotalPages();
    if ($pages === 1) {
        return $this->getTotalItems();
    }
    $currentPage = $this->getCurrentPage();
    if ($currentPage < $pages) {
        return $this->pageSize;
    }
    if ($currentPage === $pages) {
        /** @psalm-var positive-int Because the total items number is more than offset */
        return $this->getTotalItems() - $this->getOffset();
    }
    return 0;
}

            
getFilter() public method

public getFilter( ): Yiisoft\Data\Reader\FilterInterface

                public function getFilter(): FilterInterface
{
    if (!$this->isFilterable()) {
        throw new LogicException('Data reader doesn\'t support filtering.');
    }
    return $this->dataReader->getFilter();
}

            
getNextToken() public method

public getNextToken( ): Yiisoft\Data\Paginator\PageToken|null

                public function getNextToken(): ?PageToken
{
    return $this->isOnLastPage() ? null : PageToken::next((string) ($this->getCurrentPage() + 1));
}

            
getOffset() public method

Get offset for the current page, that is the number of items to skip before the current page is reached.

public getOffset( ): integer
return integer

Offset.

                public function getOffset(): int
{
    return $this->pageSize * ($this->getCurrentPage() - 1);
}

            
getPageSize() public method

public getPageSize( ): integer

                public function getPageSize(): int
{
    return $this->pageSize;
}

            
getPreviousToken() public method

public getPreviousToken( ): Yiisoft\Data\Paginator\PageToken|null

                public function getPreviousToken(): ?PageToken
{
    return $this->isOnFirstPage() ? null : PageToken::next((string) ($this->getCurrentPage() - 1));
}

            
getSort() public method

public getSort( ): Yiisoft\Data\Reader\Sort|null

                public function getSort(): ?Sort
{
    return $this->dataReader instanceof SortableDataInterface ? $this->dataReader->getSort() : null;
}

            
getToken() public method

public getToken( ): Yiisoft\Data\Paginator\PageToken

                public function getToken(): PageToken
{
    return $this->token;
}

            
getTotalItems() public method

Get total number of items in the whole data reader being paginated.

public getTotalItems( ): integer
return integer

Total items number.

                public function getTotalItems(): int
{
    $count = $this->dataReader->count();
    $dataReaderLimit = $this->dataReader->getLimit();
    if ($dataReaderLimit !== null && $count > $dataReaderLimit) {
        return $dataReaderLimit;
    }
    return $count;
}

            
getTotalPages() public method

Get total number of pages in a data reader being paginated.

public getTotalPages( ): integer
return integer

Total pages number.

                public function getTotalPages(): int
{
    return (int) ceil($this->getTotalItems() / $this->pageSize);
}

            
isFilterable() public method

public isFilterable( ): boolean

                public function isFilterable(): bool
{
    return $this->dataReader instanceof FilterableDataInterface;
}

            
isOnFirstPage() public method

public isOnFirstPage( ): boolean

                public function isOnFirstPage(): bool
{
    return $this->token->value === '1';
}

            
isOnLastPage() public method

public isOnLastPage( ): boolean

                public function isOnLastPage(): bool
{
    return $this->getCurrentPage() >= $this->getInternalTotalPages();
}

            
isPaginationRequired() public method

public isPaginationRequired( ): boolean

                public function isPaginationRequired(): bool
{
    return $this->getTotalPages() > 1;
}

            
isSortable() public method

public isSortable( ): boolean

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

            
nextPage() public method

public nextPage( ): static|null

                public function nextPage(): ?static
{
    $nextToken = $this->getNextToken();
    return $nextToken === null
        ? null
        : $this->withToken($nextToken);
}

            
previousPage() public method

public previousPage( ): static|null

                public function previousPage(): ?static
{
    $previousToken = $this->getPreviousToken();
    return $previousToken === null
        ? null
        : $this->withToken($previousToken);
}

            
read() public method

public read( ): iterable

                public function read(): iterable
{
    $currentPage = $this->getCurrentPage();
    if ($currentPage > $this->getInternalTotalPages()) {
        throw new PageNotFoundException($currentPage);
    }
    $limit = $this->pageSize;
    $dataReaderLimit = $this->dataReader->getLimit();
    if ($dataReaderLimit !== null && ($this->getOffset() + $this->pageSize) > $dataReaderLimit) {
        /** @psalm-var non-negative-int $limit */
        $limit = $dataReaderLimit - $this->getOffset();
    }
    yield from $this->dataReader
        ->withLimit($limit)
        ->withOffset($this->getOffset())
        ->read();
}

            
readOne() public method

public readOne( ): array|object|null

                public function readOne(): array|object|null
{
    $limit = 1;
    $dataReaderLimit = $this->dataReader->getLimit();
    if ($dataReaderLimit !== null && ($this->getOffset() + 1) > $dataReaderLimit) {
        $limit = 0;
    }
    return $this->dataReader
        ->withLimit($limit)
        ->withOffset($this->getOffset())
        ->readOne();
}

            
withCurrentPage() public method

Get a new instance with the given current page number set.

public withCurrentPage( integer $page ): self
$page integer

Page number.

return self

New instance.

throws InvalidArgumentException

If page is not a positive number.

                public function withCurrentPage(int $page): self
{
    /** @psalm-suppress DocblockTypeContradiction */
    if ($page < 1) {
        throw new InvalidArgumentException('Current page should be at least 1.');
    }
    $new = clone $this;
    $new->token = PageToken::next((string) $page);
    return $new;
}

            
withFilter() public method

public withFilter( Yiisoft\Data\Reader\FilterInterface $filter ): Yiisoft\Data\Paginator\OffsetPaginator
$filter Yiisoft\Data\Reader\FilterInterface

                public function withFilter(FilterInterface $filter): static
{
    if (!$this->isFilterable()) {
        throw new LogicException('Data reader doesn\'t support filtering.');
    }
    $new = clone $this;
    $new->dataReader = $this->dataReader->withFilter($filter);
    return $new;
}

            
withPageSize() public method

public withPageSize( integer $pageSize ): Yiisoft\Data\Paginator\OffsetPaginator
$pageSize integer

                public function withPageSize(int $pageSize): static
{
    /** @psalm-suppress DocblockTypeContradiction We don't believe in psalm types */
    if ($pageSize < 1) {
        throw new InvalidArgumentException('Page size should be at least 1.');
    }
    $new = clone $this;
    $new->pageSize = $pageSize;
    return $new;
}

            
withSort() public method

public withSort( Yiisoft\Data\Reader\Sort|null $sort ): Yiisoft\Data\Paginator\OffsetPaginator
$sort Yiisoft\Data\Reader\Sort|null

                public function withSort(?Sort $sort): static
{
    if (!$this->isSortable()) {
        throw new LogicException('Changing sorting is not supported.');
    }
    $new = clone $this;
    $new->dataReader = $this->dataReader->withSort($sort);
    return $new;
}

            
withToken() public method

public withToken( Yiisoft\Data\Paginator\PageToken|null $token ): Yiisoft\Data\Paginator\OffsetPaginator
$token Yiisoft\Data\Paginator\PageToken|null

                public function withToken(?PageToken $token): static
{
    if ($token === null) {
        $page = 1;
    } else {
        $page = (int) $token->value;
        if ($page < 1) {
            throw new InvalidPageException('Current page should be at least 1.');
        }
    }
    return $this->withCurrentPage($page);
}