Completed
Push — master ( 3a917b...8faa80 )
by Alexander
15s queued 12s
created

OffsetPagination   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 136
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 25
eloc 71
dl 0
loc 136
rs 10
c 1
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A isRequired() 0 3 2
A initOptions() 0 4 1
A run() 0 20 3
A getPageLink() 0 3 2
A options() 0 5 1
B renderButtons() 0 29 9
A urlGenerator() 0 4 1
A prepareButtons() 0 29 5
A paginator() 0 5 1
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
    private ?Paginator $paginator = null;
18
    private int $pagesCount;
19
    private int $currentPage;
20
    private array $pages;
21
    private bool $prepared;
22
23
24
    public function paginator(?Paginator $paginator): self
25
    {
26
        $this->paginator = $paginator;
27
        $this->prepared = false;
28
        return $this;
29
    }
30
31
    public function urlGenerator(Closure $generator): self
32
    {
33
        $this->urlGenerator = $generator;
34
        return $this;
35
    }
36
37
    public function isRequired(): bool
38
    {
39
        return $this->paginator === null ? false : $this->paginator->isRequired();
40
    }
41
42
    /**
43
     * The HTML attributes for the widget container tag. The following special options are recognized.
44
     *
45
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
46
     */
47
    public function options(array $value): self
48
    {
49
        $this->options = $value;
50
51
        return $this;
52
    }
53
54
    protected function run(): string
55
    {
56
        if ($this->paginator === null) {
57
            return '';
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 implode("\n", [
69
            Html::beginTag('nav', $this->options),
70
            Html::beginTag('ul', ['class' => 'pagination']),
71
            $this->renderButtons(),
72
            Html::endTag('ul'),
73
            Html::endTag('nav'),
74
        ]);
75
    }
76
77
    protected function prepareButtons(): void
78
    {
79
        if ($this->prepared) {
80
            return;
81
        }
82
        $this->pagesCount = $this->paginator->getTotalPages();
0 ignored issues
show
Bug introduced by
The method getTotalPages() does not exist on null. ( Ignorable by Annotation )

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

82
        /** @scrutinizer ignore-call */ 
83
        $this->pagesCount = $this->paginator->getTotalPages();

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...
83
        $this->currentPage = $this->paginator->getCurrentPage();
84
        if ($this->pagesCount > 9) {
85
            if ($this->currentPage <= 4) {
86
                $this->pages = [...range(1, 5), null, ...range($this->pagesCount - 2, $this->pagesCount)];
87
            } elseif ($this->pagesCount - $this->currentPage <= 4) {
88
                $this->pages = [1, 2, null, ...range($this->pagesCount - 5, $this->pagesCount)];
89
            } else {
90
                $this->pages = [
91
                    1,
92
                    2,
93
                    null,
94
                    $this->currentPage - 1,
95
                    $this->currentPage,
96
                    $this->currentPage + 1,
97
                    null,
98
                    $this->pagesCount - 1,
99
                    $this->pagesCount,
100
                ];
101
            }
102
        } else {
103
            $this->pages = range(1, $this->pagesCount);
104
        }
105
        $this->prepared = true;
106
    }
107
108
    protected function renderButtons(): string
109
    {
110
        $result = '';
111
112
        // `Previous` page
113
        $prevUrl = $this->paginator->isOnFirstPage() ? null : $this->getPageLink($this->currentPage - 1);
114
        $result .= Html::beginTag('li', ['class' => $prevUrl === null ? 'page-item disabled' : 'page-item']);
115
        $result .= Html::a('Previous', $prevUrl, ['class' => 'page-link']);
116
        $result .= Html::endTag('li');
117
118
        // Numeric buttons
119
        foreach ($this->pages as $page) {
120
            $isDisabled = $this->currentPage === $page || $page === null;
121
            $result .= Html::beginTag('li', ['class' => $isDisabled ? 'page-item disabled' : 'page-item']);
122
            if ($page === null) {
123
                $result .= Html::tag('span', '…', ['class' => 'page-link']);
124
            } else {
125
                $result .= Html::a((string)$page, $this->getPageLink($page), ['class' => 'page-link']);
126
            }
127
            $result .= Html::endTag('li');
128
        }
129
130
        // `Next` page
131
        $nextUrl = $this->paginator->isOnLastPage() ? null : $this->getPageLink($this->currentPage + 1);
132
        $result .= Html::beginTag('li', ['class' => $nextUrl === null ? 'page-item disabled' : 'page-item']);
133
        $result .= Html::a('Next', $nextUrl, ['class' => 'page-link']);
134
        $result .= Html::endTag('li');
135
136
        return $result;
137
    }
138
139
    protected function getPageLink(int $page): ?string
140
    {
141
        return $this->urlGenerator === null ? null : (string)($this->urlGenerator)($page);
142
    }
143
144
    protected function initOptions(): void
145
    {
146
        Html::addCssClass($this->options, [
147
            'aria-label' => 'Page navigation',
148
        ]);
149
    }
150
}
151