Issues (13)

src/OffsetPagination.php (3 issues)

Labels
Severity
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
The method getCurrentPage() does not exist on Yiisoft\Data\Paginator\PaginatorInterface. Did you maybe mean getCurrentPageSize()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

196
        /** @scrutinizer ignore-call */ 
197
        $currentPage = $paginator->getCurrentPage();

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.

Loading history...
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 ignore-call  annotation

197
        /** @scrutinizer ignore-call */ 
198
        $totalPages = $paginator->getTotalPages();
Loading history...
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 ignore-call  annotation

222
                        ->/** @scrutinizer ignore-call */ class($this->getMenuClass())
Loading history...
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