1 | <?php |
||||||
2 | |||||||
3 | declare(strict_types=1); |
||||||
4 | |||||||
5 | namespace Yiisoft\Yii\DataView; |
||||||
6 | |||||||
7 | use InvalidArgumentException; |
||||||
8 | use Yiisoft\Data\Paginator\OffsetPaginator; |
||||||
9 | use Yiisoft\Definitions\Exception\CircularReferenceException; |
||||||
10 | use Yiisoft\Definitions\Exception\InvalidConfigException; |
||||||
11 | use Yiisoft\Definitions\Exception\NotInstantiableException; |
||||||
12 | use Yiisoft\Factory\NotFoundException; |
||||||
13 | use Yiisoft\Html\Tag\Nav; |
||||||
14 | use Yiisoft\Yii\Widgets\Menu; |
||||||
15 | |||||||
16 | use function array_filter; |
||||||
17 | use function array_key_exists; |
||||||
18 | use function array_merge; |
||||||
19 | use function max; |
||||||
20 | use function min; |
||||||
21 | |||||||
22 | final class OffsetPagination extends BasePagination |
||||||
23 | { |
||||||
24 | private bool $disabledFirstPage = false; |
||||||
25 | private bool $disabledLastPage = false; |
||||||
26 | private bool $disabledPageNavLink = false; |
||||||
27 | private string $iconFirstPage = ''; |
||||||
28 | private string $iconClassFirstPage = ''; |
||||||
29 | private string $iconClassLastPage = ''; |
||||||
30 | private string $iconLastPage = ''; |
||||||
31 | private string $labelFirstPage = ''; |
||||||
32 | private string $labelLastPage = ''; |
||||||
33 | private int $maxNavLinkCount = 10; |
||||||
34 | |||||||
35 | /** |
||||||
36 | * Return a new instance with disabled first page. |
||||||
37 | */ |
||||||
38 | 1 | public function disabledFirstPage(bool $value): self |
|||||
39 | { |
||||||
40 | 1 | $new = clone $this; |
|||||
41 | 1 | $new->disabledFirstPage = $value; |
|||||
42 | |||||||
43 | 1 | return $new; |
|||||
44 | } |
||||||
45 | |||||||
46 | /** |
||||||
47 | * Return a new instance with disabled last page. |
||||||
48 | */ |
||||||
49 | 1 | public function disabledLastPage(bool $value): self |
|||||
50 | { |
||||||
51 | 1 | $new = clone $this; |
|||||
52 | 1 | $new->disabledLastPage = $value; |
|||||
53 | |||||||
54 | 1 | return $new; |
|||||
55 | } |
||||||
56 | |||||||
57 | /** |
||||||
58 | * Return a new instance with disabled page nav link. |
||||||
59 | * |
||||||
60 | * @param bool $value Disabled page nav link. |
||||||
61 | */ |
||||||
62 | 1 | public function disabledPageNavLink(bool $value): self |
|||||
63 | { |
||||||
64 | 1 | $new = clone $this; |
|||||
65 | 1 | $new->disabledPageNavLink = $value; |
|||||
66 | |||||||
67 | 1 | return $new; |
|||||
68 | } |
||||||
69 | |||||||
70 | /** |
||||||
71 | * Returns a new instance with the icon class for icon attributes `<i>` for link first page. |
||||||
72 | * |
||||||
73 | * @param string $value The icon class. |
||||||
74 | */ |
||||||
75 | 2 | public function iconClassFirstPage(string $value): self |
|||||
76 | { |
||||||
77 | 2 | $new = clone $this; |
|||||
78 | 2 | $new->iconClassFirstPage = $value; |
|||||
79 | 2 | $new->labelFirstPage = ''; |
|||||
80 | |||||||
81 | 2 | return $new; |
|||||
82 | } |
||||||
83 | |||||||
84 | /** |
||||||
85 | * Returns a new instance with the icon class for icon attributes `<i>` for link last page. |
||||||
86 | * |
||||||
87 | * @param string $value The icon class. |
||||||
88 | */ |
||||||
89 | 2 | public function iconClassLastPage(string $value): self |
|||||
90 | { |
||||||
91 | 2 | $new = clone $this; |
|||||
92 | 2 | $new->iconClassLastPage = $value; |
|||||
93 | 2 | $new->labelLastPage = ''; |
|||||
94 | |||||||
95 | 2 | return $new; |
|||||
96 | } |
||||||
97 | |||||||
98 | /** |
||||||
99 | * Return a new instance with icon first page. |
||||||
100 | * |
||||||
101 | * @param string $value The icon first page. |
||||||
102 | */ |
||||||
103 | 2 | public function iconFirstPage(string $value): self |
|||||
104 | { |
||||||
105 | 2 | $new = clone $this; |
|||||
106 | 2 | $new->iconFirstPage = $value; |
|||||
107 | 2 | $new->labelFirstPage = ''; |
|||||
108 | |||||||
109 | 2 | return $new; |
|||||
110 | } |
||||||
111 | |||||||
112 | /** |
||||||
113 | * Return a new instance with icon last page. |
||||||
114 | * |
||||||
115 | * @param string $value The icon last page. |
||||||
116 | */ |
||||||
117 | 2 | public function iconLastPage(string $value): self |
|||||
118 | { |
||||||
119 | 2 | $new = clone $this; |
|||||
120 | 2 | $new->iconLastPage = $value; |
|||||
121 | 2 | $new->labelLastPage = ''; |
|||||
122 | |||||||
123 | 2 | return $new; |
|||||
124 | } |
||||||
125 | |||||||
126 | /** |
||||||
127 | * Return a new instance with label for first page. |
||||||
128 | * |
||||||
129 | * @param string $value The label for first page. |
||||||
130 | */ |
||||||
131 | 2 | public function labelFirstPage(string $value = ''): self |
|||||
132 | { |
||||||
133 | 2 | $new = clone $this; |
|||||
134 | 2 | $new->labelFirstPage = $value; |
|||||
135 | |||||||
136 | 2 | return $new; |
|||||
137 | } |
||||||
138 | |||||||
139 | /** |
||||||
140 | * Return a new instance with label for last page. |
||||||
141 | * |
||||||
142 | * @param string $value The label for last page. |
||||||
143 | */ |
||||||
144 | 2 | public function labelLastPage(string $value = ''): self |
|||||
145 | { |
||||||
146 | 2 | $new = clone $this; |
|||||
147 | 2 | $new->labelLastPage = $value; |
|||||
148 | |||||||
149 | 2 | return $new; |
|||||
150 | } |
||||||
151 | |||||||
152 | /** |
||||||
153 | * Return a new instance with max nav link count. |
||||||
154 | * |
||||||
155 | * @param int $value Max nav link count. |
||||||
156 | */ |
||||||
157 | 1 | public function maxNavLinkCount(int $value): self |
|||||
158 | { |
||||||
159 | 1 | $new = clone $this; |
|||||
160 | 1 | $new->maxNavLinkCount = $value; |
|||||
161 | |||||||
162 | 1 | return $new; |
|||||
163 | } |
||||||
164 | |||||||
165 | /** |
||||||
166 | * @psalm-return array<int, int> |
||||||
167 | */ |
||||||
168 | 15 | protected function getPageRange(int $currentPage, int $totalPages): array |
|||||
169 | { |
||||||
170 | 15 | $beginPage = max(1, $currentPage - (int) ($this->maxNavLinkCount / 2)); |
|||||
171 | |||||||
172 | 15 | if (($endPage = $beginPage + $this->maxNavLinkCount - 1) >= $totalPages) { |
|||||
173 | 15 | $endPage = $totalPages; |
|||||
174 | 15 | $beginPage = max(1, $endPage - $this->maxNavLinkCount + 1); |
|||||
175 | } |
||||||
176 | |||||||
177 | 15 | if ($totalPages !== 0 && $currentPage > $totalPages) { |
|||||
178 | 1 | throw new InvalidArgumentException('Current page must be less than or equal to total pages.'); |
|||||
179 | } |
||||||
180 | |||||||
181 | 14 | return [$beginPage, $endPage]; |
|||||
182 | } |
||||||
183 | |||||||
184 | /** |
||||||
185 | * @throws InvalidConfigException |
||||||
186 | * @throws NotFoundException |
||||||
187 | * @throws NotInstantiableException |
||||||
188 | * @throws CircularReferenceException |
||||||
189 | */ |
||||||
190 | 15 | public function render(): string |
|||||
191 | { |
||||||
192 | 15 | $attributes = $this->getAttributes(); |
|||||
193 | |||||||
194 | /** @var OffsetPaginator */ |
||||||
195 | 15 | $paginator = $this->getPaginator(); |
|||||
196 | 15 | $currentPage = $paginator->getCurrentPage(); |
|||||
0 ignored issues
–
show
|
|||||||
197 | 15 | $totalPages = $paginator->getTotalPages(); |
|||||
0 ignored issues
–
show
The method
getTotalPages() does not exist on Yiisoft\Data\Paginator\PaginatorInterface . It seems like you code against a sub-type of Yiisoft\Data\Paginator\PaginatorInterface such as Yiisoft\Data\Paginator\OffsetPaginator .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
198 | 15 | [$beginPage, $endPage] = $this->getPageRange($currentPage, $totalPages); |
|||||
199 | |||||||
200 | 14 | $items = []; |
|||||
201 | |||||||
202 | 14 | if ($this->getHideOnSinglePage() && $endPage < 2) { |
|||||
203 | 2 | return ''; |
|||||
204 | } |
||||||
205 | |||||||
206 | 12 | $items[] = $this->renderFirstsPageNavLink($currentPage); |
|||||
207 | 12 | $items[] = $this->renderPreviousPageNavLink($currentPage); |
|||||
208 | 11 | $items = array_merge($items, $this->renderPageNavLinks($currentPage, $beginPage, $endPage)); |
|||||
209 | 11 | $items[] = $this->renderNextPageNavLink($currentPage, $endPage); |
|||||
210 | 11 | $items[] = $this->renderLastPageNavLink($currentPage, $endPage); |
|||||
211 | |||||||
212 | 11 | if (!array_key_exists('aria-label', $attributes)) { |
|||||
213 | 11 | $attributes['aria-label'] = 'Pagination'; |
|||||
214 | } |
||||||
215 | |||||||
216 | 11 | return |
|||||
217 | 11 | Nav::tag() |
|||||
218 | 11 | ->attributes($attributes) |
|||||
219 | 11 | ->content( |
|||||
220 | 11 | PHP_EOL . |
|||||
221 | 11 | Menu::widget() |
|||||
222 | 11 | ->class($this->getMenuClass()) |
|||||
0 ignored issues
–
show
The method
class() does not exist on Yiisoft\Widget\Widget . It seems like you code against a sub-type of Yiisoft\Widget\Widget such as Yiisoft\Yii\Widgets\Alert or Yiisoft\Yii\Widgets\Menu .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
223 | 11 | ->items(array_filter($items)) |
|||||
224 | 11 | ->itemsContainerClass($this->getMenuItemContainerClass()) |
|||||
225 | 11 | ->linkClass($this->getMenuItemLinkClass()) . |
|||||
226 | 11 | PHP_EOL |
|||||
227 | 11 | ) |
|||||
228 | 11 | ->encode(false) |
|||||
229 | 11 | ->render(); |
|||||
230 | } |
||||||
231 | |||||||
232 | 12 | private function renderFirstsPageNavLink(int $currentPage): array |
|||||
233 | { |
||||||
234 | 12 | $iconContainerAttributes = $this->getIconContainerAttributes(); |
|||||
235 | 12 | $items = []; |
|||||
236 | |||||||
237 | 12 | if (!array_key_exists('aria-hidden', $iconContainerAttributes)) { |
|||||
238 | 12 | $iconContainerAttributes['aria-hidden'] = 'true'; |
|||||
239 | } |
||||||
240 | |||||||
241 | 12 | if ($this->labelFirstPage !== '' || $this->iconFirstPage !== '' || $this->iconClassFirstPage !== '') { |
|||||
242 | 3 | $items = [ |
|||||
243 | 3 | 'disabled' => $currentPage === 1 || $this->disabledFirstPage, |
|||||
244 | 3 | 'icon' => $this->iconFirstPage, |
|||||
245 | 3 | 'iconAttributes' => $this->getIconAttributes(), |
|||||
246 | 3 | 'iconClass' => $this->iconClassFirstPage, |
|||||
247 | 3 | 'iconContainerAttributes' => $iconContainerAttributes, |
|||||
248 | 3 | 'label' => $this->labelFirstPage, |
|||||
249 | 3 | 'link' => $this->createUrl(1), |
|||||
250 | 3 | ]; |
|||||
251 | } |
||||||
252 | |||||||
253 | 12 | return $items; |
|||||
254 | } |
||||||
255 | |||||||
256 | 12 | private function renderPreviousPageNavLink(int $currentPage): array |
|||||
257 | { |
||||||
258 | 12 | $iconContainerAttributes = $this->getIconContainerAttributes(); |
|||||
259 | 12 | $items = []; |
|||||
260 | |||||||
261 | 12 | if (!array_key_exists('aria-hidden', $iconContainerAttributes)) { |
|||||
262 | 12 | $iconContainerAttributes['aria-hidden'] = 'true'; |
|||||
263 | } |
||||||
264 | |||||||
265 | if ( |
||||||
266 | 12 | $this->getLabelPreviousPage() !== '' || |
|||||
267 | 2 | $this->getIconPreviousPage() !== '' || |
|||||
268 | 12 | $this->getIconClassPreviousPage() !== '' |
|||||
269 | ) { |
||||||
270 | 11 | $items = [ |
|||||
271 | 11 | 'disabled' => $currentPage === 1 || $this->getDisabledPreviousPage(), |
|||||
272 | 11 | 'icon' => $this->getIconPreviousPage(), |
|||||
273 | 11 | 'iconAttributes' => $this->getIconAttributes(), |
|||||
274 | 11 | 'iconClass' => $this->getIconClassPreviousPage(), |
|||||
275 | 11 | 'iconContainerAttributes' => $iconContainerAttributes, |
|||||
276 | 11 | 'label' => $this->getLabelPreviousPage(), |
|||||
277 | 11 | 'link' => $this->createUrl(max($currentPage - 1, 1)), |
|||||
278 | 11 | ]; |
|||||
279 | } |
||||||
280 | |||||||
281 | 11 | return $items; |
|||||
282 | } |
||||||
283 | |||||||
284 | 11 | private function renderPageNavLinks(int $currentPage, int $beginPage, int $endPage): array |
|||||
285 | { |
||||||
286 | 11 | $items = []; |
|||||
287 | |||||||
288 | do { |
||||||
289 | 11 | $items[] = [ |
|||||
290 | 11 | 'active' => $beginPage === $currentPage, |
|||||
291 | 11 | 'disabled' => $this->disabledPageNavLink && $beginPage === $currentPage, |
|||||
292 | 11 | 'label' => (string) $beginPage, |
|||||
293 | 11 | 'link' => $this->createUrl($beginPage), |
|||||
294 | 11 | ]; |
|||||
295 | 11 | } while (++$beginPage <= $endPage); |
|||||
296 | |||||||
297 | 11 | return $items; |
|||||
298 | } |
||||||
299 | |||||||
300 | 11 | private function renderNextPageNavLink(int $currentPage, int $pageCount): array |
|||||
301 | { |
||||||
302 | 11 | $iconContainerAttributes = $this->getIconContainerAttributes(); |
|||||
303 | 11 | $items = []; |
|||||
304 | |||||||
305 | 11 | if (!array_key_exists('aria-hidden', $iconContainerAttributes)) { |
|||||
306 | 11 | $iconContainerAttributes['aria-hidden'] = 'true'; |
|||||
307 | } |
||||||
308 | |||||||
309 | if ( |
||||||
310 | 11 | $this->getLabelNextPage() !== '' || |
|||||
311 | 2 | $this->getIconNextPage() !== '' || |
|||||
312 | 11 | $this->getIconClassNextPage() !== '' |
|||||
313 | ) { |
||||||
314 | 10 | $items = [ |
|||||
315 | 10 | 'disabled' => $currentPage === $pageCount || $this->getDisabledNextPage(), |
|||||
316 | 10 | 'icon' => $this->getIconNextPage(), |
|||||
317 | 10 | 'iconAttributes' => $this->getIconAttributes(), |
|||||
318 | 10 | 'iconClass' => $this->getIconClassNextPage(), |
|||||
319 | 10 | 'iconContainerAttributes' => $iconContainerAttributes, |
|||||
320 | 10 | 'label' => $this->getLabelNextPage(), |
|||||
321 | 10 | 'link' => $this->createUrl(min($currentPage + 1, $pageCount)), |
|||||
322 | 10 | ]; |
|||||
323 | } |
||||||
324 | |||||||
325 | 11 | return $items; |
|||||
326 | } |
||||||
327 | |||||||
328 | 11 | private function renderLastPageNavLink(int $currentPage, int $pageCount): array |
|||||
329 | { |
||||||
330 | 11 | $iconContainerAttributes = $this->getIconContainerAttributes(); |
|||||
331 | 11 | $items = []; |
|||||
332 | |||||||
333 | 11 | if (!array_key_exists('aria-hidden', $iconContainerAttributes)) { |
|||||
334 | 11 | $iconContainerAttributes['aria-hidden'] = 'true'; |
|||||
335 | } |
||||||
336 | |||||||
337 | 11 | if ($this->labelLastPage !== '' || $this->iconLastPage !== '' || $this->iconClassLastPage !== '') { |
|||||
338 | 3 | $items = [ |
|||||
339 | 3 | 'disabled' => $currentPage === $pageCount || $this->disabledLastPage, |
|||||
340 | 3 | 'icon' => $this->iconLastPage, |
|||||
341 | 3 | 'iconAttributes' => $this->getIconAttributes(), |
|||||
342 | 3 | 'iconClass' => $this->iconClassLastPage, |
|||||
343 | 3 | 'iconContainerAttributes' => $iconContainerAttributes, |
|||||
344 | 3 | 'label' => $this->labelLastPage, |
|||||
345 | 3 | 'link' => $this->createUrl($pageCount), |
|||||
346 | 3 | ]; |
|||||
347 | } |
||||||
348 | |||||||
349 | 11 | return $items; |
|||||
350 | } |
||||||
351 | } |
||||||
352 |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.