premier commit
This commit is contained in:
@@ -0,0 +1,429 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Framework\Pagination
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Framework\Pagination;
|
||||
|
||||
use ArrayIterator;
|
||||
use Grav\Framework\Pagination\Interfaces\PaginationInterface;
|
||||
use Grav\Framework\Route\Route;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
* Class AbstractPagination
|
||||
* @package Grav\Framework\Pagination
|
||||
*/
|
||||
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,
|
||||
'param' => null,
|
||||
'use_query_param' => false
|
||||
];
|
||||
/** @var array */
|
||||
private $items;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return $this->count() > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions(): array
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Route|null
|
||||
*/
|
||||
public function getRoute(): ?Route
|
||||
{
|
||||
return $this->route;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTotalPages(): int
|
||||
{
|
||||
return $this->pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getPageNumber(): int
|
||||
{
|
||||
return $this->page ?? 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $count
|
||||
* @return int|null
|
||||
*/
|
||||
public function getPrevNumber(int $count = 1): ?int
|
||||
{
|
||||
$page = $this->page - $count;
|
||||
|
||||
return $page >= 1 ? $page : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $count
|
||||
* @return int|null
|
||||
*/
|
||||
public function getNextNumber(int $count = 1): ?int
|
||||
{
|
||||
$page = $this->page + $count;
|
||||
|
||||
return $page <= $this->pages ? $page : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $page
|
||||
* @param string|null $label
|
||||
* @return PaginationPage|null
|
||||
*/
|
||||
public function getPage(int $page, string $label = null): ?PaginationPage
|
||||
{
|
||||
if ($page < 1 || $page > $this->pages) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$start = ($page - 1) * $this->limit;
|
||||
$type = $this->getOptions()['type'];
|
||||
$param = $this->getOptions()['param'];
|
||||
$useQuery = $this->getOptions()['use_query_param'];
|
||||
if ($type === 'page') {
|
||||
$param = $param ?? 'page';
|
||||
$offset = $page;
|
||||
} else {
|
||||
$param = $param ?? 'start';
|
||||
$offset = $start;
|
||||
}
|
||||
|
||||
if ($useQuery) {
|
||||
$route = $this->route->withQueryParam($param, $offset);
|
||||
} else {
|
||||
$route = $this->route->withGravParam($param, $offset);
|
||||
}
|
||||
|
||||
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' => $route
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $label
|
||||
* @param int $count
|
||||
* @return PaginationPage|null
|
||||
*/
|
||||
public function getFirstPage(string $label = null, int $count = 0): ?PaginationPage
|
||||
{
|
||||
return $this->getPage(1 + $count, $label ?? $this->getOptions()['label_first'] ?? null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $label
|
||||
* @param int $count
|
||||
* @return PaginationPage|null
|
||||
*/
|
||||
public function getPrevPage(string $label = null, int $count = 1): ?PaginationPage
|
||||
{
|
||||
return $this->getPage($this->page - $count, $label ?? $this->getOptions()['label_prev'] ?? null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $label
|
||||
* @param int $count
|
||||
* @return PaginationPage|null
|
||||
*/
|
||||
public function getNextPage(string $label = null, int $count = 1): ?PaginationPage
|
||||
{
|
||||
return $this->getPage($this->page + $count, $label ?? $this->getOptions()['label_next'] ?? null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $label
|
||||
* @param int $count
|
||||
* @return PaginationPage|null
|
||||
*/
|
||||
public function getLastPage(string $label = null, int $count = 0): ?PaginationPage
|
||||
{
|
||||
return $this->getPage($this->pages - $count, $label ?? $this->getOptions()['label_last'] ?? null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getStart(): int
|
||||
{
|
||||
return $this->start ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLimit(): int
|
||||
{
|
||||
return $this->limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTotal(): int
|
||||
{
|
||||
return $this->total;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
$this->loadItems();
|
||||
|
||||
return count($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArrayIterator
|
||||
* @phpstan-return ArrayIterator<int,PaginationPage>
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function getIterator()
|
||||
{
|
||||
$this->loadItems();
|
||||
|
||||
return new ArrayIterator($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getPages(): array
|
||||
{
|
||||
$this->loadItems();
|
||||
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Route $route
|
||||
* @return $this
|
||||
*/
|
||||
protected function setRoute(Route $route)
|
||||
{
|
||||
$this->route = $route;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|null $options
|
||||
* @return $this
|
||||
*/
|
||||
protected function setOptions(array $options = null)
|
||||
{
|
||||
$this->options = $options ? array_merge($this->defaultOptions, $options) : $this->defaultOptions;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $page
|
||||
* @return $this
|
||||
*/
|
||||
protected function setPage(int $page = null)
|
||||
{
|
||||
$this->page = (int)max($page, 1);
|
||||
$this->start = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Route $route
|
||||
* @param int $total
|
||||
* @param int|null $pos
|
||||
* @param int|null $limit
|
||||
* @param array|null $options
|
||||
* @return void
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Framework\Pagination
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Framework\Pagination;
|
||||
|
||||
use Grav\Framework\Pagination\Interfaces\PaginationPageInterface;
|
||||
|
||||
/**
|
||||
* Class AbstractPaginationPage
|
||||
* @package Grav\Framework\Pagination
|
||||
*/
|
||||
abstract class AbstractPaginationPage implements PaginationPageInterface
|
||||
{
|
||||
/** @var array */
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isActive(): bool
|
||||
{
|
||||
return $this->options['active'] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return $this->options['enabled'] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions(): array
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
*/
|
||||
public function getNumber(): ?int
|
||||
{
|
||||
return $this->options['number'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLabel(): string
|
||||
{
|
||||
return $this->options['label'] ?? (string)$this->getNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getUrl(): ?string
|
||||
{
|
||||
return $this->options['route'] ? (string)$this->options['route']->getUri() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*/
|
||||
protected function setOptions(array $options): void
|
||||
{
|
||||
$this->options = $options;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Framework\Pagination
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Framework\Pagination\Interfaces;
|
||||
|
||||
use Countable;
|
||||
use Grav\Framework\Pagination\PaginationPage;
|
||||
use IteratorAggregate;
|
||||
|
||||
/**
|
||||
* Interface PaginationInterface
|
||||
* @package Grav\Framework\Pagination\Interfaces
|
||||
* @extends IteratorAggregate<int,PaginationPage>
|
||||
*/
|
||||
interface PaginationInterface extends Countable, IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTotalPages(): int;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getPageNumber(): int;
|
||||
|
||||
/**
|
||||
* @param int $count
|
||||
* @return int|null
|
||||
*/
|
||||
public function getPrevNumber(int $count = 1): ?int;
|
||||
|
||||
/**
|
||||
* @param int $count
|
||||
* @return int|null
|
||||
*/
|
||||
public function getNextNumber(int $count = 1): ?int;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getStart(): int;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLimit(): int;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTotal(): int;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function count(): int;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions(): array;
|
||||
|
||||
/**
|
||||
* @param int $page
|
||||
* @param string|null $label
|
||||
* @return PaginationPage|null
|
||||
*/
|
||||
public function getPage(int $page, string $label = null): ?PaginationPage;
|
||||
|
||||
/**
|
||||
* @param string|null $label
|
||||
* @param int $count
|
||||
* @return PaginationPage|null
|
||||
*/
|
||||
public function getFirstPage(string $label = null, int $count = 0): ?PaginationPage;
|
||||
|
||||
/**
|
||||
* @param string|null $label
|
||||
* @param int $count
|
||||
* @return PaginationPage|null
|
||||
*/
|
||||
public function getPrevPage(string $label = null, int $count = 1): ?PaginationPage;
|
||||
|
||||
/**
|
||||
* @param string|null $label
|
||||
* @param int $count
|
||||
* @return PaginationPage|null
|
||||
*/
|
||||
public function getNextPage(string $label = null, int $count = 1): ?PaginationPage;
|
||||
|
||||
/**
|
||||
* @param string|null $label
|
||||
* @param int $count
|
||||
* @return PaginationPage|null
|
||||
*/
|
||||
public function getLastPage(string $label = null, int $count = 0): ?PaginationPage;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Framework\Pagination
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Framework\Pagination\Interfaces;
|
||||
|
||||
/**
|
||||
* Interface PaginationPageInterface
|
||||
* @package Grav\Framework\Pagination\Interfaces
|
||||
*/
|
||||
interface PaginationPageInterface
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isActive(): bool;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isEnabled(): bool;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions(): array;
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
*/
|
||||
public function getNumber(): ?int;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLabel(): string;
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getUrl(): ?string;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Framework\Pagination
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Framework\Pagination;
|
||||
|
||||
use Grav\Framework\Route\Route;
|
||||
|
||||
/**
|
||||
* Class Pagination
|
||||
* @package Grav\Framework\Pagination
|
||||
*/
|
||||
class Pagination extends AbstractPagination
|
||||
{
|
||||
/**
|
||||
* Pagination constructor.
|
||||
* @param Route $route
|
||||
* @param int $total
|
||||
* @param int|null $pos
|
||||
* @param int|null $limit
|
||||
* @param array|null $options
|
||||
*/
|
||||
public function __construct(Route $route, int $total, int $pos = null, int $limit = null, array $options = null)
|
||||
{
|
||||
$this->initialize($route, $total, $pos, $limit, $options);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Framework\Pagination
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Framework\Pagination;
|
||||
|
||||
/**
|
||||
* Class PaginationPage
|
||||
* @package Grav\Framework\Pagination
|
||||
*/
|
||||
class PaginationPage extends AbstractPaginationPage
|
||||
{
|
||||
/**
|
||||
* PaginationPage constructor.
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
$this->setOptions($options);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user