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