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 mixed __construct ( Yiisoft\Data\Reader\ReadableDataInterface $dataReader )
$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 integer getCurrentPage ( )
return integer

Current page number.

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

            
getCurrentPageSize() public method

public integer getCurrentPageSize ( )

                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 Yiisoft\Data\Reader\FilterInterface getFilter ( )

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

            
getNextToken() public method

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

                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 integer getOffset ( )
return integer

Offset.

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

            
getPageSize() public method

public integer getPageSize ( )

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

            
getPreviousToken() public method

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

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

            
getSort() public method

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

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

            
getToken() public method

public Yiisoft\Data\Paginator\PageToken getToken ( )

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

            
getTotalItems() public method

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

public integer getTotalItems ( )
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 integer getTotalPages ( )
return integer

Total pages number.

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

            
isFilterable() public method

public boolean isFilterable ( )

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

            
isOnFirstPage() public method

public boolean isOnFirstPage ( )

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

            
isOnLastPage() public method

public boolean isOnLastPage ( )

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

            
isPaginationRequired() public method

public boolean isPaginationRequired ( )

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

            
isSortable() public method

public boolean isSortable ( )

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

            
nextPage() public method

public static|null nextPage ( )

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

            
previousPage() public method

public static|null previousPage ( )

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

            
read() public method

public iterable read ( )

                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 array|object|null readOne ( )

                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 self withCurrentPage ( integer $page )
$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 Yiisoft\Data\Paginator\OffsetPaginator withFilter ( Yiisoft\Data\Reader\FilterInterface $filter )
$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 Yiisoft\Data\Paginator\OffsetPaginator withPageSize ( integer $pageSize )
$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 Yiisoft\Data\Paginator\OffsetPaginator withSort ( Yiisoft\Data\Reader\Sort|null $sort )
$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 Yiisoft\Data\Paginator\OffsetPaginator withToken ( Yiisoft\Data\Paginator\PageToken|null $token )
$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);
}