scaffold/src/Helpers/Paginate.php

144 lines
3.2 KiB
PHP

<?php
/**
* Read the documentation at:
* https://codeberg.org/vlw/scaffold/docs/Database/Paginate.md
*/
namespace vlw\Scaffold\Helpers;
class Paginate {
public const KEY = "p";
public const DEFAULT_RANGE = 3;
public const DEFAULT_PAGE_SIZE = 25;
/**
* Start a new Paginate instance
*
* @param int $total Total amount of items to paginate
* @param ?int $size Amount of items to display on each page
* @param ?int $current Index of current page
*/
public function __construct(
public int $total = 0,
public ?int $size = null,
public ?int $current = null
) {
if ($this->current === null) {
// Parse current page from search parameters
$this->current = array_key_exists($this->key, $_GET) ? $this->clamp((int) $_GET[$this->key]) : 0;
}
if ($this->size === null) {
$this->size = self::DEFAULT_PAGE_SIZE;
}
}
/**
* Search parameter to use as key for page number
*/
public string $key = "p";
/**
* Get current database offset
*
* @return int Database offset of first item on current page
*/
public int $offset {
get => max(0, $this->current * $this->size);
}
/**
* Get total amount of pages
*
* @return int Total number of pages
*/
public int $pages {
get => ceil($this->total / $this->size);
}
/**
* Returns true if a previous page exists
*
* @return bool Previous page exists
*/
public bool $previous {
get => $this->current > 0;
}
/**
* True if a next page exists
*
* @return bool Next page exists
*/
public bool $next {
get => $this->current + 1 < $this->pages;
}
/**
* Get pages witin ±range from current page
*
* @param ?int $range Desired range from current page to return
* @return array<int> Indecies of pages within the desired range
*/
public function range(?int $range = self::DEFAULT_RANGE): array {
$start = max(1, $this->current - max(0, $range - 2));
$end = min($this->pages, $this->current + $range);
$range = [];
for ($i = $start; $i <= $end; $i++) {
$range[] = $i;
}
return $range;
}
/**
* Returns a url to a page by index
*
* @param int $page Page index
* @return string Search parameters to the target page
*/
public function idx(int $page): string {
return $this->url($page - 1);
}
/**
* Returns a url to the previous page
*
* @return string Search parameters to the previous page
*/
public function previous(): string {
return $this->url($this->current - 1);
}
/**
* Returns a url to the next page
*
* @return string Search parameters to the next page
*/
public function next(): string {
return $this->url($this->current + 1);
}
/**
* Clamp page within range of all pages
*
* @param int $page Page index
* @return int Clamped page index
*/
private function clamp(int $page): int {
return max(0, min($page, $this->pages - 1));
}
/**
* Construct search parameters for a page while preserving existing search parameters
*
* @param int $page Page index
* @return string A search parameter to the target page
*/
private function url(int $page): string {
return "?" . http_build_query(array_merge($_GET, [$this->key => $page]));
}
}