Completed
Push — 2.1-master-merge ( 240673 )
by Alexander
13:45
created

LinkPager::getPageRange()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2.0625

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 13
ccs 6
cts 8
cp 0.75
rs 9.4285
cc 2
eloc 8
nc 2
nop 0
crap 2.0625
1
<?php
2
/**
3
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii\widgets;
9
10
use Yii;
11
use yii\base\InvalidConfigException;
12
use yii\base\Widget;
13
use yii\data\Pagination;
14
use yii\helpers\ArrayHelper;
15
use yii\helpers\Html;
16
17
/**
18
 * LinkPager displays a list of hyperlinks that lead to different pages of target.
19
 *
20
 * LinkPager works with a [[Pagination]] object which specifies the total number
21
 * of pages and the current page number.
22
 *
23
 * Note that LinkPager only generates the necessary HTML markups. In order for it
24
 * to look like a real pager, you should provide some CSS styles for it.
25
 * With the default configuration, LinkPager should look good using Twitter Bootstrap CSS framework.
26
 *
27
 * For more details and usage information on LinkPager, see the [guide article on pagination](guide:output-pagination).
28
 *
29
 * @author Qiang Xue <[email protected]>
30
 * @since 2.0
31
 */
32
class LinkPager extends Widget
33
{
34
    /**
35
     * @var Pagination the pagination object that this pager is associated with.
36
     * You must set this property in order to make LinkPager work.
37
     */
38
    public $pagination;
39
    /**
40
     * @var array HTML attributes for the pager container tag.
41
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
42
     */
43
    public $options = ['class' => 'pagination'];
44
    /**
45
     * @var array HTML attributes which will be applied to all link containers
46
     * @since 2.0.13
47
     */
48
    public $linkContainerOptions = [];
49
    /**
50
     * @var array HTML attributes for the link in a pager container tag.
51
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
52
     */
53
    public $linkOptions = [];
54
    /**
55
     * @var string the CSS class for the each page button.
56
     * @since 2.0.7
57
     */
58
    public $pageCssClass;
59
    /**
60
     * @var string the CSS class for the "first" page button.
61
     */
62
    public $firstPageCssClass = 'first';
63
    /**
64
     * @var string the CSS class for the "last" page button.
65
     */
66
    public $lastPageCssClass = 'last';
67
    /**
68
     * @var string the CSS class for the "previous" page button.
69
     */
70
    public $prevPageCssClass = 'prev';
71
    /**
72
     * @var string the CSS class for the "next" page button.
73
     */
74
    public $nextPageCssClass = 'next';
75
    /**
76
     * @var string the CSS class for the active (currently selected) page button.
77
     */
78
    public $activePageCssClass = 'active';
79
    /**
80
     * @var string the CSS class for the disabled page buttons.
81
     */
82
    public $disabledPageCssClass = 'disabled';
83
    /**
84
     * @var array the options for the disabled tag to be generated inside the disabled list element.
85
     * In order to customize the html tag, please use the tag key.
86
     *
87
     * ```php
88
     * $disabledListItemSubTagOptions = ['tag' => 'div', 'class' => 'disabled-div'];
89
     * ```
90
     * @since 2.0.11
91
     */
92
    public $disabledListItemSubTagOptions = [];
93
    /**
94
     * @var int maximum number of page buttons that can be displayed. Defaults to 10.
95
     */
96
    public $maxButtonCount = 10;
97
    /**
98
     * @var string|bool the label for the "next" page button. Note that this will NOT be HTML-encoded.
99
     * If this property is false, the "next" page button will not be displayed.
100
     */
101
    public $nextPageLabel = '&raquo;';
102
    /**
103
     * @var string|bool the text label for the previous page button. Note that this will NOT be HTML-encoded.
104
     * If this property is false, the "previous" page button will not be displayed.
105
     */
106
    public $prevPageLabel = '&laquo;';
107
    /**
108
     * @var string|bool the text label for the "first" page button. Note that this will NOT be HTML-encoded.
109
     * If it's specified as true, page number will be used as label.
110
     * Default is false that means the "first" page button will not be displayed.
111
     */
112
    public $firstPageLabel = false;
113
    /**
114
     * @var string|bool the text label for the "last" page button. Note that this will NOT be HTML-encoded.
115
     * If it's specified as true, page number will be used as label.
116
     * Default is false that means the "last" page button will not be displayed.
117
     */
118
    public $lastPageLabel = false;
119
    /**
120
     * @var bool whether to register link tags in the HTML header for prev, next, first and last page.
121
     * Defaults to `false` to avoid conflicts when multiple pagers are used on one page.
122
     * @see http://www.w3.org/TR/html401/struct/links.html#h-12.1.2
123
     * @see registerLinkTags()
124
     */
125
    public $registerLinkTags = false;
126
    /**
127
     * @var bool Hide widget when only one page exist.
128
     */
129
    public $hideOnSinglePage = true;
130
    /**
131
     * @var bool whether to render current page button as disabled.
132
     * @since 2.0.12
133
     */
134
    public $disableCurrentPageButton = false;
135
136
137
    /**
138
     * Initializes the pager.
139
     */
140 15
    public function init()
141
    {
142 15
        if ($this->pagination === null) {
143
            throw new InvalidConfigException('The "pagination" property must be set.');
144
        }
145 15
    }
146
147
    /**
148
     * Executes the widget.
149
     * This overrides the parent implementation by displaying the generated page buttons.
150
     * @return string the result of widget execution to be outputted.
151
     */
152 15
    public function run()
153
    {
154 15
        if ($this->registerLinkTags) {
155
            $this->registerLinkTags();
156
        }
157 15
        return $this->renderPageButtons();
158
    }
159
160
    /**
161
     * Registers relational link tags in the html header for prev, next, first and last page.
162
     * These links are generated using [[\yii\data\Pagination::getLinks()]].
163
     * @see http://www.w3.org/TR/html401/struct/links.html#h-12.1.2
164
     */
165
    protected function registerLinkTags()
166
    {
167
        $view = $this->getView();
168
        foreach ($this->pagination->getLinks() as $rel => $href) {
169
            $view->registerLinkTag(['rel' => $rel, 'href' => $href], $rel);
170
        }
171
    }
172
173
    /**
174
     * Renders the page buttons.
175
     * @return string the rendering result
176
     */
177 15
    protected function renderPageButtons()
178
    {
179 15
        $pageCount = $this->pagination->getPageCount();
180 15
        if ($pageCount < 2 && $this->hideOnSinglePage) {
181 9
            return '';
182
        }
183
184 6
        $buttons = [];
185 6
        $currentPage = $this->pagination->getPage();
186
187
        // first page
188 6
        $firstPageLabel = $this->firstPageLabel === true ? '1' : $this->firstPageLabel;
189 6
        if ($firstPageLabel !== false) {
190 1
            $buttons[] = $this->renderPageButton($firstPageLabel, 0, $this->firstPageCssClass, $currentPage <= 0, false);
0 ignored issues
show
Bug introduced by
It seems like $firstPageLabel defined by $this->firstPageLabel ==...: $this->firstPageLabel on line 188 can also be of type boolean; however, yii\widgets\LinkPager::renderPageButton() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
191
        }
192
193
        // prev page
194 6
        if ($this->prevPageLabel !== false) {
195 6
            if (($page = $currentPage - 1) < 0) {
196 2
                $page = 0;
197
            }
198 6
            $buttons[] = $this->renderPageButton($this->prevPageLabel, $page, $this->prevPageCssClass, $currentPage <= 0, false);
199
        }
200
201
        // internal pages
202 6
        [$beginPage, $endPage] = $this->getPageRange();
0 ignored issues
show
Bug introduced by
The variable $beginPage does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $endPage does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
203 6
        for ($i = $beginPage; $i <= $endPage; ++$i) {
204 6
            $buttons[] = $this->renderPageButton($i + 1, $i, null, $this->disableCurrentPageButton && $i == $currentPage, $i == $currentPage);
205
        }
206
207
        // next page
208 6
        if ($this->nextPageLabel !== false) {
209 6
            if (($page = $currentPage + 1) >= $pageCount - 1) {
210
                $page = $pageCount - 1;
211
            }
212 6
            $buttons[] = $this->renderPageButton($this->nextPageLabel, $page, $this->nextPageCssClass, $currentPage >= $pageCount - 1, false);
213
        }
214
215
        // last page
216 6
        $lastPageLabel = $this->lastPageLabel === true ? $pageCount : $this->lastPageLabel;
217 6
        if ($lastPageLabel !== false) {
218 1
            $buttons[] = $this->renderPageButton($lastPageLabel, $pageCount - 1, $this->lastPageCssClass, $currentPage >= $pageCount - 1, false);
219
        }
220
221 6
        $options = $this->options;
222 6
        $tag = ArrayHelper::remove($options, 'tag', 'ul');
223 6
        return Html::tag($tag, implode("\n", $buttons), $options);
224
    }
225
226
    /**
227
     * Renders a page button.
228
     * You may override this method to customize the generation of page buttons.
229
     * @param string $label the text label for the button
230
     * @param int $page the page number
231
     * @param string $class the CSS class for the page button.
232
     * @param bool $disabled whether this page button is disabled
233
     * @param bool $active whether this page button is active
234
     * @return string the rendering result
235
     */
236 6
    protected function renderPageButton($label, $page, $class, $disabled, $active)
237
    {
238 6
        $options = $this->linkContainerOptions;
239 6
        $linkWrapTag = ArrayHelper::remove($options, 'tag', 'li');
240 6
        Html::addCssClass($options, empty($class) ? $this->pageCssClass : $class);
241
242 6
        if ($active) {
243 6
            Html::addCssClass($options, $this->activePageCssClass);
244
        }
245 6
        if ($disabled) {
246 3
            Html::addCssClass($options, $this->disabledPageCssClass);
247 3
            $tag = ArrayHelper::remove($this->disabledListItemSubTagOptions, 'tag', 'span');
248
249 3
            return Html::tag($linkWrapTag, Html::tag($tag, $label, $this->disabledListItemSubTagOptions), $options);
250
        }
251 6
        $linkOptions = $this->linkOptions;
252 6
        $linkOptions['data-page'] = $page;
253
254 6
        return Html::tag($linkWrapTag, Html::a($label, $this->pagination->createUrl($page), $linkOptions), $options);
255
    }
256
257
    /**
258
     * @return array the begin and end pages that need to be displayed.
259
     */
260 6
    protected function getPageRange()
261
    {
262 6
        $currentPage = $this->pagination->getPage();
263 6
        $pageCount = $this->pagination->getPageCount();
264
265 6
        $beginPage = max(0, $currentPage - (int) ($this->maxButtonCount / 2));
266 6
        if (($endPage = $beginPage + $this->maxButtonCount - 1) >= $pageCount) {
267
            $endPage = $pageCount - 1;
268
            $beginPage = max(0, $endPage - $this->maxButtonCount + 1);
269
        }
270
271 6
        return [$beginPage, $endPage];
272
    }
273
}
274