Passed
Pull Request — master (#49)
by
unknown
13:21
created

OffsetPagination::renderButtons()   B

Complexity

Conditions 9
Paths 20

Size

Total Lines 29
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 18
c 1
b 0
f 0
dl 0
loc 29
rs 8.0555
cc 9
nc 20
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace App\Widget;
6
7
use Closure;
8
use Yiisoft\Data\Paginator\OffsetPaginator as Paginator;
9
use Yiisoft\Yii\Bootstrap4\Html;
10
use Yiisoft\Yii\Bootstrap4\Widget;
11
12
class OffsetPagination extends Widget
13
{
14
    private array $options = [];
15
16
    private ?Closure $urlGenerator = null;
17
    /**
18
     * @var Paginator
19
     */
20
    private Paginator $paginator;
21
    private int $pagesCount;
22
    private int $currentPage;
23
    private array $pages;
24
    private bool $prepared;
25
26
27
    public function paginator(?Paginator $paginator): self
28
    {
29
        $this->paginator = $paginator;
30
        $this->prepared = false;
31
        return $this;
32
    }
33
34
    public function urlGenerator(Closure $generator): self
35
    {
36
        $this->urlGenerator = $generator;
37
        return $this;
38
    }
39
40
    public function isRequired(): bool
41
    {
42
        return !isset($this->paginator) ? false : $this->paginator->isRequired();
43
    }
44
45
    /**
46
     * The HTML attributes for the widget container tag. The following special options are recognized.
47
     *
48
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
49
     */
50
    public function options(array $value): self
51
    {
52
        $this->options = $value;
53
54
        return $this;
55
    }
56
57
    protected function run(): string
58
    {
59
        if (!isset($this->options['id'])) {
60
            $this->options['id'] = "{$this->getId()}-post-card";
61
        }
62
63
        $this->initOptions();
64
        $this->prepareButtons();
65
66
        $this->registerPlugin('offset-pagination', $this->options);
67
68
        return "\n" . Html::beginTag('nav', $this->options)
69
            . "\n" . Html::beginTag('ul', ['class' => 'pagination'])
70
            . "\n" . $this->renderButtons()
71
            . "\n" . Html::endTag('ul')
72
            . "\n" . Html::endTag('nav')
73
            . "\n";
74
    }
75
76
    protected function prepareButtons(): void
77
    {
78
        if ($this->prepared) {
79
            return;
80
        }
81
        $this->pagesCount = $this->paginator->getTotalPages();
82
        $this->currentPage = $this->paginator->getCurrentPage();
83
        if ($this->pagesCount > 9) {
84
            if ($this->currentPage <= 4) {
85
                $this->pages = [...range(1, 5), null, ...range($this->pagesCount - 2, $this->pagesCount)];
86
            } elseif ($this->pagesCount - $this->currentPage <= 4) {
87
                $this->pages = [1, 2, null, ...range($this->pagesCount - 5, $this->pagesCount)];
88
            } else {
89
                $this->pages = [
90
                    1,
91
                    2,
92
                    null,
93
                    $this->currentPage - 1,
94
                    $this->currentPage,
95
                    $this->currentPage + 1,
96
                    null,
97
                    $this->pagesCount - 1,
98
                    $this->pagesCount,
99
                ];
100
            }
101
        } else {
102
            $this->pages = range(1, $this->pagesCount);
103
        }
104
        $this->prepared = true;
105
    }
106
107
    protected function renderButtons(): string
108
    {
109
        $result = '';
110
111
        // `Previous` page
112
        $prevUrl = $this->paginator->isOnFirstPage() ? null : $this->getPageLink($this->currentPage - 1);
113
        $result .= Html::beginTag('li', ['class' => $prevUrl === null ? 'page-item disabled' : 'page-item']);
114
        $result .= Html::a('Previous', $prevUrl, ['class' => 'page-link']);
115
        $result .= Html::endTag('li');
116
117
        // Numeric buttons
118
        foreach ($this->pages as $page) {
119
            $isDisabled = $this->currentPage === $page || $page === null;
120
            $result .= Html::beginTag('li', ['class' => $isDisabled ? 'page-item disabled' : 'page-item']);
121
            if ($page === null) {
122
                $result .= Html::tag('span', '…', ['class' => 'page-link']);
123
            } else {
124
                $result .= Html::a((string)$page, $this->getPageLink($page), ['class' => 'page-link']);
125
            }
126
            $result .= Html::endTag('li');
127
        }
128
129
        // `Next` page
130
        $nextUrl = $this->paginator->isOnLastPage() ? null : $this->getPageLink($this->currentPage + 1);
131
        $result .= Html::beginTag('li', ['class' => $nextUrl === null ? 'page-item disabled' : 'page-item']);
132
        $result .= Html::a('Next', $nextUrl, ['class' => 'page-link']);
133
        $result .= Html::endTag('li');
134
135
        return $result;
136
    }
137
138
    protected function getPageLink(int $page): ?string
139
    {
140
        return $this->urlGenerator === null ? null : (string)($this->urlGenerator)($page);
141
    }
142
143
    protected function initOptions(): void
144
    {
145
        Html::addCssClass($this->options, [
146
            'aria-label' => 'Page navigation',
147
        ]);
148
    }
149
}
150