Paginator.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. <?php
  2. /**
  3. * This file is part of the Nette Framework (https://nette.org)
  4. * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  5. */
  6. declare(strict_types=1);
  7. namespace Nette\Utils;
  8. use Nette;
  9. /**
  10. * Paginating math.
  11. *
  12. * @property int $page
  13. * @property-read int $firstPage
  14. * @property-read int|null $lastPage
  15. * @property-read int $firstItemOnPage
  16. * @property-read int $lastItemOnPage
  17. * @property int $base
  18. * @property-read bool $first
  19. * @property-read bool $last
  20. * @property-read int|null $pageCount
  21. * @property int $itemsPerPage
  22. * @property int|null $itemCount
  23. * @property-read int $offset
  24. * @property-read int|null $countdownOffset
  25. * @property-read int $length
  26. */
  27. class Paginator
  28. {
  29. use Nette\SmartObject;
  30. /** @var int */
  31. private $base = 1;
  32. /** @var int */
  33. private $itemsPerPage = 1;
  34. /** @var int */
  35. private $page = 1;
  36. /** @var int|null */
  37. private $itemCount;
  38. /**
  39. * Sets current page number.
  40. * @return static
  41. */
  42. public function setPage(int $page)
  43. {
  44. $this->page = $page;
  45. return $this;
  46. }
  47. /**
  48. * Returns current page number.
  49. */
  50. public function getPage(): int
  51. {
  52. return $this->base + $this->getPageIndex();
  53. }
  54. /**
  55. * Returns first page number.
  56. */
  57. public function getFirstPage(): int
  58. {
  59. return $this->base;
  60. }
  61. /**
  62. * Returns last page number.
  63. */
  64. public function getLastPage(): ?int
  65. {
  66. return $this->itemCount === null
  67. ? null
  68. : $this->base + max(0, $this->getPageCount() - 1);
  69. }
  70. /**
  71. * Returns the sequence number of the first element on the page
  72. */
  73. public function getFirstItemOnPage(): int
  74. {
  75. return $this->itemCount !== 0
  76. ? $this->offset + 1
  77. : 0;
  78. }
  79. /**
  80. * Returns the sequence number of the last element on the page
  81. */
  82. public function getLastItemOnPage(): int
  83. {
  84. return $this->offset + $this->length;
  85. }
  86. /**
  87. * Sets first page (base) number.
  88. * @return static
  89. */
  90. public function setBase(int $base)
  91. {
  92. $this->base = $base;
  93. return $this;
  94. }
  95. /**
  96. * Returns first page (base) number.
  97. */
  98. public function getBase(): int
  99. {
  100. return $this->base;
  101. }
  102. /**
  103. * Returns zero-based page number.
  104. */
  105. protected function getPageIndex(): int
  106. {
  107. $index = max(0, $this->page - $this->base);
  108. return $this->itemCount === null
  109. ? $index
  110. : min($index, max(0, $this->getPageCount() - 1));
  111. }
  112. /**
  113. * Is the current page the first one?
  114. */
  115. public function isFirst(): bool
  116. {
  117. return $this->getPageIndex() === 0;
  118. }
  119. /**
  120. * Is the current page the last one?
  121. */
  122. public function isLast(): bool
  123. {
  124. return $this->itemCount === null
  125. ? false
  126. : $this->getPageIndex() >= $this->getPageCount() - 1;
  127. }
  128. /**
  129. * Returns the total number of pages.
  130. */
  131. public function getPageCount(): ?int
  132. {
  133. return $this->itemCount === null
  134. ? null
  135. : (int) ceil($this->itemCount / $this->itemsPerPage);
  136. }
  137. /**
  138. * Sets the number of items to display on a single page.
  139. * @return static
  140. */
  141. public function setItemsPerPage(int $itemsPerPage)
  142. {
  143. $this->itemsPerPage = max(1, $itemsPerPage);
  144. return $this;
  145. }
  146. /**
  147. * Returns the number of items to display on a single page.
  148. */
  149. public function getItemsPerPage(): int
  150. {
  151. return $this->itemsPerPage;
  152. }
  153. /**
  154. * Sets the total number of items.
  155. * @return static
  156. */
  157. public function setItemCount(?int $itemCount = null)
  158. {
  159. $this->itemCount = $itemCount === null ? null : max(0, $itemCount);
  160. return $this;
  161. }
  162. /**
  163. * Returns the total number of items.
  164. */
  165. public function getItemCount(): ?int
  166. {
  167. return $this->itemCount;
  168. }
  169. /**
  170. * Returns the absolute index of the first item on current page.
  171. */
  172. public function getOffset(): int
  173. {
  174. return $this->getPageIndex() * $this->itemsPerPage;
  175. }
  176. /**
  177. * Returns the absolute index of the first item on current page in countdown paging.
  178. */
  179. public function getCountdownOffset(): ?int
  180. {
  181. return $this->itemCount === null
  182. ? null
  183. : max(0, $this->itemCount - ($this->getPageIndex() + 1) * $this->itemsPerPage);
  184. }
  185. /**
  186. * Returns the number of items on current page.
  187. */
  188. public function getLength(): int
  189. {
  190. return $this->itemCount === null
  191. ? $this->itemsPerPage
  192. : min($this->itemsPerPage, $this->itemCount - $this->getPageIndex() * $this->itemsPerPage);
  193. }
  194. }