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