123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- <?php
- /**
- * @package Grav\Framework\Pagination
- *
- * @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
- * @license MIT License; see LICENSE file for details.
- */
- namespace Grav\Framework\Pagination;
- use Grav\Framework\Pagination\Interfaces\PaginationInterface;
- use Grav\Framework\Route\Route;
- class AbstractPagination implements PaginationInterface
- {
- /** @var Route Base rouse used for the pagination. */
- protected $route;
- /** @var int|null Current page. */
- protected $page;
- /** @var int|null The record number to start displaying from. */
- protected $start;
- /** @var int Number of records to display per page. */
- protected $limit;
- /** @var int Total number of records. */
- protected $total;
- /** @var array Pagination options */
- protected $options;
- /** @var bool View all flag. */
- protected $viewAll;
- /** @var int Total number of pages. */
- protected $pages;
- /** @var int Value pagination object begins at. */
- protected $pagesStart;
- /** @var int Value pagination object ends at .*/
- protected $pagesStop;
- /** @var array */
- protected $defaultOptions = [
- 'type' => 'page',
- 'limit' => 10,
- 'display' => 5,
- 'opening' => 0,
- 'ending' => 0,
- 'url' => null
- ];
- /** @var array */
- private $items;
- public function isEnabled(): bool
- {
- return $this->count() > 1;
- }
- public function getOptions(): array
- {
- return $this->options;
- }
- public function getRoute(): ?Route
- {
- return $this->route;
- }
- public function getTotalPages(): int
- {
- return $this->pages;
- }
- public function getPageNumber(): int
- {
- return $this->page;
- }
- public function getPrevNumber(int $count = 1): ?int
- {
- $page = $this->page - $count;
- return $page >= 1 ? $page : null;
- }
- public function getNextNumber(int $count = 1): ?int
- {
- $page = $this->page + $count;
- return $page <= $this->pages ? $page : null;
- }
- public function getPage(int $page, string $label = null): ?PaginationPage
- {
- if ($page < 1 || $page > $this->pages) {
- return null;
- }
- $start = ($page - 1) * $this->limit;
- if ($this->getOptions()['type'] === 'page') {
- $name = 'page';
- $offset = $page;
- } else {
- $name = 'start';
- $offset = $start;
- }
- return new PaginationPage(
- [
- 'label' => $label ?? (string)$page,
- 'number' => $page,
- 'offset_start' => $start,
- 'offset_end' => min($start + $this->limit, $this->total) - 1,
- 'enabled' => $page !== $this->page || $this->viewAll,
- 'active' => $page === $this->page,
- 'route' => $this->route->withGravParam($name, $offset)
- ]
- );
- }
- public function getFirstPage(string $label = null, int $count = 0): ?PaginationPage
- {
- return $this->getPage(1 + $count, $label ?? $this->getOptions()['label_first'] ?? null);
- }
- public function getPrevPage(string $label = null, int $count = 1): ?PaginationPage
- {
- return $this->getPage($this->page - $count, $label ?? $this->getOptions()['label_prev'] ?? null);
- }
- public function getNextPage(string $label = null, int $count = 1): ?PaginationPage
- {
- return $this->getPage($this->page + $count, $label ?? $this->getOptions()['label_next'] ?? null);
- }
- public function getLastPage(string $label = null, int $count = 0): ?PaginationPage
- {
- return $this->getPage($this->pages - $count, $label ?? $this->getOptions()['label_last'] ?? null);
- }
- public function getStart(): int
- {
- return $this->start;
- }
- public function getLimit(): int
- {
- return $this->limit;
- }
- public function getTotal(): int
- {
- return $this->total;
- }
- public function count(): int
- {
- $this->loadItems();
- return \count($this->items);
- }
- public function getIterator()
- {
- $this->loadItems();
- return new \ArrayIterator($this->items);
- }
- public function getPages(): array
- {
- $this->loadItems();
- return $this->items;
- }
- protected function loadItems()
- {
- $this->calculateRange();
- // Make list like: 1 ... 4 5 6 ... 10
- $range = range($this->pagesStart, $this->pagesStop);
- //$range[] = 1;
- //$range[] = $this->pages;
- natsort($range);
- $range = array_unique($range);
- $this->items = [];
- foreach ($range as $i) {
- $this->items[$i] = $this->getPage($i);
- }
- }
- protected function setRoute(Route $route)
- {
- $this->route = $route;
- return $this;
- }
- protected function setOptions(array $options = null)
- {
- $this->options = $options ? array_merge($this->defaultOptions, $options) : $this->defaultOptions;
- return $this;
- }
- protected function setPage(int $page = null)
- {
- $this->page = (int)max($page, 1);
- $this->start = null;
- return $this;
- }
- /**
- * @param int $start
- * @return $this
- */
- protected function setStart(int $start = null)
- {
- $this->start = (int)max($start, 0);
- $this->page = null;
- return $this;
- }
- /**
- * @param int|null $limit
- * @return $this
- */
- protected function setLimit(int $limit = null)
- {
- $this->limit = (int)max($limit ?? $this->getOptions()['limit'], 0);
- // No limit, display all records in a single page.
- $this->viewAll = !$limit;
- return $this;
- }
- /**
- * @param int $total
- * @return $this
- */
- protected function setTotal(int $total)
- {
- $this->total = (int)max($total, 0);
- return $this;
- }
- protected function initialize(Route $route, int $total, int $pos = null, int $limit = null, array $options = null)
- {
- $this->setRoute($route);
- $this->setOptions($options);
- $this->setTotal($total);
- if ($this->getOptions()['type'] === 'start') {
- $this->setStart($pos);
- } else {
- $this->setPage($pos);
- }
- $this->setLimit($limit);
- $this->calculateLimits();
- }
- protected function calculateLimits()
- {
- $limit = $this->limit;
- $total = $this->total;
- if (!$limit || $limit > $total) {
- // All records fit into a single page.
- $this->start = 0;
- $this->page = 1;
- $this->pages = 1;
- return;
- }
- if (null === $this->start) {
- // If we are using page, convert it to start.
- $this->start = (int)(($this->page - 1) * $limit);
- }
- if ($this->start > $total - $limit) {
- // If start is greater than total count (i.e. we are asked to display records that don't exist)
- // then set start to display the last natural page of results.
- $this->start = (int)max(0, (ceil($total / $limit) - 1) * $limit);
- }
- // Set the total pages and current page values.
- $this->page = (int)ceil(($this->start + 1) / $limit);
- $this->pages = (int)ceil($total / $limit);
- }
- protected function calculateRange()
- {
- $options = $this->getOptions();
- $displayed = $options['display'];
- $opening = $options['opening'];
- $ending = $options['ending'];
- // Set the pagination iteration loop values.
- $this->pagesStart = $this->page - (int)($displayed / 2);
- if ($this->pagesStart < 1 + $opening) {
- $this->pagesStart = 1 + $opening;
- }
- if ($this->pagesStart + $displayed - $opening > $this->pages) {
- $this->pagesStop = $this->pages;
- if ($this->pages < $displayed) {
- $this->pagesStart = 1 + $opening;
- } else {
- $this->pagesStart = $this->pages - $displayed + 1 + $opening;
- }
- } else {
- $this->pagesStop = (int)max(1, $this->pagesStart + $displayed - 1 - $ending);
- }
- }
- }
|