<?php namespace Laravel; class Paginator { /** * The results for the current page. * * @var array */ public $results; /** * The current page. * * @var int */ protected $page; /** * The last page available for the result set. * * @var int */ protected $last; /** * The total number of results. * * @var int */ protected $total; /** * The number of items per page. * * @var int */ protected $per_page; /** * The values that should be appended to the end of the link query strings. * * @var array */ protected $appends; /** * The compiled appendage that will be appended to the links. * * This consists of a sprintf format with a page place-holder and query string. * * @var string */ protected $appendage; /** * The pagination elements that will be generated. * * @var array */ protected $elements = array('first', 'previous', 'status', 'next', 'last'); /** * Create a new Paginator instance. * * @param array $results * @param int $last * @param int $page * @param int $total * @param int $per_page * @return void */ protected function __construct($results, $page, $total, $per_page, $last) { $this->page = $page; $this->last = $last; $this->total = $total; $this->results = $results; $this->per_page = $per_page; } /** * Create a new Paginator instance. * * @param array $results * @param int $total * @param int $per_page * @return Paginator */ public static function make($results, $total, $per_page) { return new static($results, static::page($total, $per_page), $total, $per_page, ceil($total / $per_page)); } /** * Get the current page from the request query string. * * @param int $total * @param int $per_page * @return int */ public static function page($total, $per_page) { $page = Input::get('page', 1); // The page will be validated and adjusted if it is less than one or greater // than the last page. For example, if the current page is not an integer or // less than one, one will be returned. If the current page is greater than // the last page, the last page will be returned. if (is_numeric($page) and $page > $last = ceil($total / $per_page)) { return ($last > 0) ? $last : 1; } return ($page < 1 or filter_var($page, FILTER_VALIDATE_INT) === false) ? 1 : $page; } /** * Create the HTML pagination links. * * @return string */ public function links() { if ($this->last <= 1) return ''; // Each pagination element is created by an element method. This allows // us to keep this class clean and simple, because pagination code can // become a mess. We would rather keep it simple and beautiful. foreach ($this->elements as $element) { $elements[] = $this->$element(Lang::line("pagination.{$element}")->get()); } return '<div class="pagination">'.implode(' ', $elements).'</div>'.PHP_EOL; } /** * Get the "status" pagination element. * * @param string $text * @return string */ protected function status($text) { return str_replace(array(':current', ':last'), array($this->page, $this->last), $text); } /** * Create the "first" pagination element. * * @param string $text * @return string */ protected function first($text) { return $this->backwards(__FUNCTION__, $text, 1); } /** * Create the "previous" pagination element. * * @param string $text * @return string */ protected function previous($text) { return $this->backwards(__FUNCTION__, $text, $this->page - 1); } /** * Create the "next" pagination element. * * @param string $text * @return string */ protected function next($text) { return $this->forwards(__FUNCTION__, $text, $this->page + 1); } /** * Create the "last" pagination element. * * @param string $text * @return string */ protected function last($text) { return $this->forwards(__FUNCTION__, $text, $this->last); } /** * Create a "backwards" paginatino element. * * This function handles the creation of the first and previous elements. * * @param string $element * @param string $text * @param int $last * @return string */ protected function backwards($element, $text, $last) { return $this->element($element, $text, $last, function($page) { return $page <= 1; }); } /** * Create a "forwards" paginatino element. * * This function handles the creation of the next and last elements. * * @param string $element * @param string $text * @param int $last * @return string */ protected function forwards($element, $text, $last) { return $this->element($element, $text, $last, function($page, $last) { return $page >= $last; }); } /** * Create a chronological pagination element. * * @param string $element * @param string $text * @param int $page * @param Closure $disabler * @return string */ protected function element($element, $text, $page, $disabler) { $class = "{$element}_page"; if ($disabler($this->page, $this->last)) { return HTML::span($text, array('class' => "disabled {$class}")); } else { // We will assume the page links should use HTTPS if the current request // is also using HTTPS. Since pagination links automatically point to // the current URI, this makes pretty good sense. list($uri, $secure) = array(URI::get(), Request::secure()); return HTML::link($uri.$this->appendage($element, $page), $text, array('class' => $class), $secure); } } /** * Create the pagination link "appendage" for an element. * * @param string $element * @param int $page * @return string */ protected function appendage($element, $page) { // The appendage string contains the query string, but it also contains a // place-holder for the page number. This will be used to insert the // correct page number based on the element being created. if (is_null($this->appendage)) { $this->appendage = '?page=%s'.http_build_query((array) $this->appends); } return sprintf($this->appendage, $page); } /** * Set the items that should be appended to the link query strings. * * This provides a convenient method of maintaining sort or passing other information * to the route handling pagination. * * @param array $values * @return Paginator */ public function appends($values) { $this->appends = $values; return $this; } /** * Set the elements that should be included when creating the pagination links. * * The available elements are "first", "previous", "status", "next", and "last". * * @param array $elements * @return string */ public function elements($elements) { $this->elements = $elements; return $this; } }