paginator.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. <?php namespace System;
  2. class Paginator {
  3. /**
  4. * The results for the current page.
  5. *
  6. * @var array
  7. */
  8. public $results;
  9. /**
  10. * The total number of results.
  11. *
  12. * @var int
  13. */
  14. public $total;
  15. /**
  16. * The current page.
  17. *
  18. * @var int
  19. */
  20. public $page;
  21. /**
  22. * The number of items per page.
  23. *
  24. * @var int
  25. */
  26. public $per_page;
  27. /**
  28. * The last page number.
  29. *
  30. * @var int
  31. */
  32. public $last_page;
  33. /**
  34. * Create a new Paginator instance.
  35. *
  36. * @param array $results
  37. * @param int $total
  38. * @param int $per_page
  39. * @return void
  40. */
  41. public function __construct($results, $total, $per_page)
  42. {
  43. $this->page = static::page($total, $per_page);
  44. $this->last_page = ceil($total / $per_page);
  45. $this->per_page = $per_page;
  46. $this->results = $results;
  47. $this->total = $total;
  48. }
  49. /**
  50. * Get the current page from the request query string.
  51. *
  52. * The page will be validated and adjusted if it is less than one or greater than the last page.
  53. *
  54. * @param int $total
  55. * @param int $per_page
  56. * @return int
  57. */
  58. public static function page($total, $per_page)
  59. {
  60. $page = Input::get('page', 1);
  61. if (is_numeric($page) and $page > $last_page = ceil($total / $per_page))
  62. {
  63. return $last_page;
  64. }
  65. return (filter_var($page, FILTER_VALIDATE_INT) === false or $page < 1) ? 1 : $page;
  66. }
  67. /**
  68. * Create the HTML pagination links.
  69. *
  70. * @param int $adjacent
  71. * @return string
  72. */
  73. public function links($adjacent = 3)
  74. {
  75. return ($this->last_page > 1) ? '<div class="pagination">'.$this->previous().$this->numbers($adjacent).$this->next() : '';
  76. }
  77. /**
  78. * Generate the HTML numeric page links.
  79. *
  80. * If there are not enough pages to make it worth sliding, all of the pages will be listed.
  81. *
  82. * @param int $adjacent
  83. * @return string
  84. */
  85. private function numbers($adjacent = 3)
  86. {
  87. // "7" is added to the adjacent range to account for the seven constant elements
  88. // in a slider: the first and last two links, the current page, and the two "..." strings.
  89. return ($this->last_page < 7 + ($adjacent * 2)) ? $this->range(1, $this->last_page) : $this->slider($adjacent);
  90. }
  91. /**
  92. * Build sliding list of HTML numeric page links.
  93. *
  94. * @param int $adjacent
  95. * @return string
  96. */
  97. private function slider($adjacent)
  98. {
  99. if ($this->page <= $adjacent * 2)
  100. {
  101. return $this->range(1, 4 + ($adjacent * 2)).$this->ending();
  102. }
  103. elseif ($this->page >= $this->last_page - ($adjacent * 2))
  104. {
  105. return $this->beginning().$this->range($this->last_page - 2 - ($adjacent * 2), $this->last_page);
  106. }
  107. return $this->beginning().$this->range($this->page - $adjacent, $this->page + $adjacent).$this->ending();
  108. }
  109. /**
  110. * Generate the "previous" HTML link.
  111. *
  112. * @return string
  113. */
  114. public function previous()
  115. {
  116. $text = Lang::line('pagination.previous')->get();
  117. if ($this->page > 1)
  118. {
  119. return HTML::link(Request::uri().'?page='.($this->page - 1), $text, array('class' => 'prev_page')).' ';
  120. }
  121. return "<span class=\"disabled prev_page\">$text</span> ";
  122. }
  123. /**
  124. * Generate the "next" HTML link.
  125. *
  126. * @return string
  127. */
  128. public function next()
  129. {
  130. $text = Lang::line('pagination.next')->get();
  131. if ($this->page < $this->last_page)
  132. {
  133. return HTML::link(Request::uri().'?page='.($this->page + 1), $text, array('class' => 'next_page'));
  134. }
  135. return "<span class=\"disabled next_page\">$text</span>";
  136. }
  137. /**
  138. * Build the first two page links for a sliding page range.
  139. *
  140. * @return string
  141. */
  142. private function beginning()
  143. {
  144. return $this->range(1, 2).'<span class="dots">...</span> ';
  145. }
  146. /**
  147. * Build the last two page links for a sliding page range.
  148. *
  149. * @return string
  150. */
  151. private function ending()
  152. {
  153. return '<span class="dots">...</span> '.$this->range($this->last_page - 1, $this->last_page);
  154. }
  155. /**
  156. * Build a range of page links.
  157. *
  158. * For the current page, an HTML span element will be generated instead of a link.
  159. *
  160. * @param int $start
  161. * @param int $end
  162. * @return string
  163. */
  164. private function range($start, $end)
  165. {
  166. $pages = '';
  167. for ($i = $start; $i <= $end; $i++)
  168. {
  169. $pages .= ($this->page == $i) ? "<span class=\"current\">$i</span> " : HTML::link(Request::uri().'?page='.$i, $i).' ';
  170. }
  171. return $pages;
  172. }
  173. }