417 lines
No EOL
8.5 KiB
PHP
417 lines
No EOL
8.5 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Pagination
|
|
*
|
|
* @package Kirby Toolkit
|
|
* @author Bastian Allgeier <bastian@getkirby.com>
|
|
* @link http://getkirby.com
|
|
* @copyright Bastian Allgeier
|
|
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
|
*/
|
|
class Pagination {
|
|
|
|
// configuration
|
|
public static $defaults = array(
|
|
'variable' => 'page',
|
|
'method' => 'param',
|
|
'omitFirstPage' => true,
|
|
'page' => false,
|
|
'url' => null,
|
|
'redirect' => false,
|
|
);
|
|
|
|
// options
|
|
protected $options = array();
|
|
|
|
// the current page
|
|
protected $page = null;
|
|
|
|
// total count of items
|
|
protected $count = 0;
|
|
|
|
// the number of displayed rows
|
|
protected $limit = 0;
|
|
|
|
// the total number of pages
|
|
protected $pages = 0;
|
|
|
|
// the offset for the slice function
|
|
protected $offset = 0;
|
|
|
|
// the range start for ranged pagination
|
|
protected $rangeStart = 0;
|
|
|
|
// the range end for ranged pagination
|
|
protected $rangeEnd = 0;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param mixed $count Either an integer or a Collection
|
|
* @param int $limit The number of items per page
|
|
* @param array $params Additional parameters to control the pagination object
|
|
*/
|
|
public function __construct($count, $limit, $params = array()) {
|
|
|
|
// You can still pass an entire collection
|
|
if($count instanceof Collection) {
|
|
$count = $count->count();
|
|
}
|
|
|
|
$this->options = array_merge(static::$defaults, $params);
|
|
$this->count = (int)$count;
|
|
$this->limit = (int)$limit;
|
|
$this->pages = (int)ceil($this->count / $this->limit);
|
|
$this->offset = (int)(($this->page()-1) * $this->limit);
|
|
|
|
}
|
|
|
|
/**
|
|
* Returns the current page number
|
|
*
|
|
* @return int
|
|
*/
|
|
public function page() {
|
|
|
|
if(!is_null($this->page)) return $this->page;
|
|
|
|
if($this->options['page']) {
|
|
$this->page = $this->options['page'];
|
|
} else {
|
|
$this->page = ($this->options['method'] == 'query') ? get($this->options['variable']) : param($this->options['variable']);
|
|
}
|
|
|
|
// make sure the page is an int
|
|
$this->page = intval($this->page);
|
|
|
|
// set the first page correctly
|
|
if($this->page == 0) {
|
|
$this->page = 1;
|
|
}
|
|
|
|
// sanitize the page if too low
|
|
if($this->page < 1) {
|
|
$this->redirect();
|
|
$this->page = 1;
|
|
}
|
|
|
|
// sanitize the page if too high
|
|
if($this->page > $this->pages && $this->count > 0) {
|
|
$this->redirect();
|
|
$this->page = $this->lastPage();
|
|
}
|
|
|
|
// return the sanitized page number
|
|
return $this->page;
|
|
|
|
}
|
|
|
|
/**
|
|
* Redirects to an error page if the redirect option is set
|
|
* and the pagination is beyond the allowed boundaries
|
|
*/
|
|
public function redirect() {
|
|
if($redirect = $this->options['redirect']) {
|
|
go($redirect);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the total number of pages
|
|
*
|
|
* @return int
|
|
*/
|
|
public function countPages() {
|
|
return $this->pages;
|
|
}
|
|
|
|
/**
|
|
* Alternative for countPages()
|
|
*
|
|
* @return int
|
|
*/
|
|
public function pages() {
|
|
return $this->pages;
|
|
}
|
|
|
|
/**
|
|
* Returns the current offset
|
|
* This is used for the slice() method together with
|
|
* the limit to get the correct items from collections
|
|
*
|
|
* @return int
|
|
*/
|
|
public function offset() {
|
|
return $this->offset;
|
|
}
|
|
|
|
/**
|
|
* Returns the chosen limit
|
|
* This is used for the slice() method together with
|
|
* the offset to get the correct items from collections
|
|
*
|
|
* @return int
|
|
*/
|
|
public function limit() {
|
|
return $this->limit;
|
|
}
|
|
|
|
/**
|
|
* Checks if multiple pages are needed
|
|
* or if the collection can be displayed on a single page
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function hasPages() {
|
|
return $this->countPages() > 1;
|
|
}
|
|
|
|
/**
|
|
* Returns the total number of items in the collection
|
|
*
|
|
* @return int
|
|
*/
|
|
public function countItems() {
|
|
return $this->count;
|
|
}
|
|
|
|
/**
|
|
* Alternative for countItems()
|
|
*
|
|
* @return int
|
|
*/
|
|
public function items() {
|
|
return $this->count;
|
|
}
|
|
|
|
/**
|
|
* Returns a page url for any given page number
|
|
*
|
|
* @param int $page The page number
|
|
* @return string The url
|
|
*/
|
|
public function pageURL($page) {
|
|
|
|
if($this->options['method'] == 'query') {
|
|
|
|
$query = url::query($this->options['url']);
|
|
|
|
if($page == 1 && $this->options['omitFirstPage']) {
|
|
unset($query[$this->options['variable']]);
|
|
} else {
|
|
$query[$this->options['variable']] = $page;
|
|
}
|
|
|
|
return url::build(array('query' => $query), $this->options['url']);
|
|
|
|
} else {
|
|
|
|
$params = url::params($this->options['url']);
|
|
|
|
if($page == 1 && $this->options['omitFirstPage']) {
|
|
unset($params[$this->options['variable']]);
|
|
} else {
|
|
$params[$this->options['variable']] = $page;
|
|
}
|
|
|
|
return url::build(array('params' => $params), $this->options['url']);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Returns the number of the first page
|
|
*
|
|
* @return int
|
|
*/
|
|
public function firstPage() {
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Checks if the current page is the first page
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function isFirstPage() {
|
|
return ($this->page == $this->firstPage()) ? true : false;
|
|
}
|
|
|
|
/**
|
|
* Returns the url for the first page
|
|
*
|
|
* @return string
|
|
*/
|
|
public function firstPageURL() {
|
|
return $this->pageURL(1);
|
|
}
|
|
|
|
/**
|
|
* Returns the number of the last page
|
|
*
|
|
* @return int
|
|
*/
|
|
public function lastPage() {
|
|
return $this->pages;
|
|
}
|
|
|
|
/**
|
|
* Checks if the current page is the last page
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function isLastPage() {
|
|
return $this->page == $this->lastPage();
|
|
}
|
|
|
|
/**
|
|
* Returns the url for the last page
|
|
*
|
|
* @return string
|
|
*/
|
|
public function lastPageURL() {
|
|
return $this->pageURL($this->lastPage());
|
|
}
|
|
|
|
/**
|
|
* Returns the number of the previous page
|
|
*
|
|
* @return int
|
|
*/
|
|
public function prevPage() {
|
|
return $this->hasPrevPage() ? $this->page-1 : $this->page;
|
|
}
|
|
|
|
/**
|
|
* Returns the url for the previous page
|
|
*
|
|
* @return string
|
|
*/
|
|
public function prevPageURL() {
|
|
return $this->pageURL($this->prevPage());
|
|
}
|
|
|
|
/**
|
|
* Checks if there's a previous page
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function hasPrevPage() {
|
|
return $this->page > 1;
|
|
}
|
|
|
|
/**
|
|
* Returns the number of the next page
|
|
*
|
|
* @return int
|
|
*/
|
|
public function nextPage() {
|
|
return $this->hasNextPage() ? $this->page+1 : $this->page;
|
|
}
|
|
|
|
/**
|
|
* Returns the url for the next page
|
|
*
|
|
* @return string
|
|
*/
|
|
public function nextPageURL() {
|
|
return $this->pageURL($this->nextPage());
|
|
}
|
|
|
|
/**
|
|
* Checks if there's a next page
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function hasNextPage() {
|
|
return $this->page < $this->pages;
|
|
}
|
|
|
|
/**
|
|
* Returns the index number of the first item on the current page
|
|
* Can be used to display something like
|
|
* "Currently showing 1 - 10 of 123 items"
|
|
*
|
|
* @return int
|
|
*/
|
|
public function numStart() {
|
|
return $this->offset+1;
|
|
}
|
|
|
|
/**
|
|
* Returns the index number of the last item on the current page
|
|
* Can be used to display something like
|
|
* "Currently showing 1 - 10 of 123 items"
|
|
*
|
|
* @return int
|
|
*/
|
|
public function numEnd() {
|
|
$end = $this->offset+$this->limit;
|
|
if($end > $this->items()) $end = $this->items();
|
|
return $end;
|
|
}
|
|
|
|
/**
|
|
* Creates a range of page numbers for Google-like pagination
|
|
*
|
|
* @return array
|
|
*/
|
|
public function range($range=5) {
|
|
|
|
if($this->countPages() <= $range) {
|
|
$this->rangeStart = 1;
|
|
$this->rangeEnd = $this->countPages();
|
|
return range($this->rangeStart, $this->rangeEnd);
|
|
}
|
|
|
|
$this->rangeStart = $this->page - (int)floor($range/2);
|
|
$this->rangeEnd = $this->page + (int)floor($range/2);
|
|
|
|
if($this->rangeStart <= 0) {
|
|
$this->rangeEnd += abs($this->rangeStart)+1;
|
|
$this->rangeStart = 1;
|
|
}
|
|
|
|
if($this->rangeEnd > $this->countPages()) {
|
|
$this->rangeStart -= $this->rangeEnd-$this->countPages();
|
|
$this->rangeEnd = $this->countPages();
|
|
}
|
|
|
|
return range($this->rangeStart,$this->rangeEnd);
|
|
|
|
}
|
|
|
|
/**
|
|
* Returns the first page of the created range
|
|
*
|
|
* @return int
|
|
*/
|
|
public function rangeStart() {
|
|
return $this->rangeStart;
|
|
}
|
|
|
|
/**
|
|
* Returns the last page of the created range
|
|
*
|
|
* @return int
|
|
*/
|
|
public function rangeEnd() {
|
|
return $this->rangeEnd;
|
|
}
|
|
|
|
/**
|
|
* Returns the most important pagination data into a readable array
|
|
*
|
|
* @return array
|
|
*/
|
|
public function toArray() {
|
|
return array(
|
|
'page' => $this->page(),
|
|
'pages' => $this->pages(),
|
|
'items' => $this->countItems(),
|
|
);
|
|
}
|
|
|
|
} |