Completed
Push — 2.1 ( 21da0e...a39d12 )
by
unknown
10: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 17
    public function init()
141
    {
142 17
        parent::init();
143
144 17
        if ($this->pagination === null) {
145
            throw new InvalidConfigException('The "pagination" property must be set.');
146
        }
147 17
    }
148
149
    /**
150
     * Executes the widget.
151
     * This overrides the parent implementation by displaying the generated page buttons.
152
     * @return string the result of widget execution to be outputted.
153
     */
154 17
    public function run()
155
    {
156 17
        if ($this->registerLinkTags) {
157
            $this->registerLinkTags();
158
        }
159 17
        return $this->renderPageButtons();
160
    }
161
162
    /**
163
     * Registers relational link tags in the html header for prev, next, first and last page.
164
     * These links are generated using [[\yii\data\Pagination::getLinks()]].
165
     * @see http://www.w3.org/TR/html401/struct/links.html#h-12.1.2
166
     */
167
    protected function registerLinkTags()
168
    {
169
        $view = $this->getView();
170
        foreach ($this->pagination->getLinks() as $rel => $href) {
171
            $view->registerLinkTag(['rel' => $rel, 'href' => $href], $rel);
172
        }
173
    }
174
175
    /**
176
     * Renders the page buttons.
177
     * @return string the rendering result
178
     */
179 17
    protected function renderPageButtons()
180
    {
181 17
        $pageCount = $this->pagination->getPageCount();
182 17
        if ($pageCount < 2 && $this->hideOnSinglePage) {
183 10
            return '';
184
        }
185
186 7
        $buttons = [];
187 7
        $currentPage = $this->pagination->getPage();
188
189
        // first page
190 7
        $firstPageLabel = $this->firstPageLabel === true ? '1' : $this->firstPageLabel;
191 7
        if ($firstPageLabel !== false) {
192 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 190 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...
193
        }
194
195
        // prev page
196 7
        if ($this->prevPageLabel !== false) {
197 7
            if (($page = $currentPage - 1) < 0) {
198 2
                $page = 0;
199
            }
200 7
            $buttons[] = $this->renderPageButton($this->prevPageLabel, $page, $this->prevPageCssClass, $currentPage <= 0, false);
201
        }
202
203
        // internal pages
204 7
        [$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...
205 7
        for ($i = $beginPage; $i <= $endPage; ++$i) {
206 7
            $buttons[] = $this->renderPageButton($i + 1, $i, null, $this->disableCurrentPageButton && $i == $currentPage, $i == $currentPage);
207
        }
208
209
        // next page
210 7
        if ($this->nextPageLabel !== false) {
211 7
            if (($page = $currentPage + 1) >= $pageCount - 1) {
212
                $page = $pageCount - 1;
213
            }
214 7
            $buttons[] = $this->renderPageButton($this->nextPageLabel, $page, $this->nextPageCssClass, $currentPage >= $pageCount - 1, false);
215
        }
216
217
        // last page
218 7
        $lastPageLabel = $this->lastPageLabel === true ? $pageCount : $this->lastPageLabel;
219 7
        if ($lastPageLabel !== false) {
220 1
            $buttons[] = $this->renderPageButton($lastPageLabel, $pageCount - 1, $this->lastPageCssClass, $currentPage >= $pageCount - 1, false);
221
        }
222
223 7
        $options = $this->options;
224 7
        $tag = ArrayHelper::remove($options, 'tag', 'ul');
225 7
        return Html::tag($tag, implode("\n", $buttons), $options);
226
    }
227
228
    /**
229
     * Renders a page button.
230
     * You may override this method to customize the generation of page buttons.
231
     * @param string $label the text label for the button
232
     * @param int $page the page number
233
     * @param string $class the CSS class for the page button.
234
     * @param bool $disabled whether this page button is disabled
235
     * @param bool $active whether this page button is active
236
     * @return string the rendering result
237
     */
238 7
    protected function renderPageButton($label, $page, $class, $disabled, $active)
239
    {
240 7
        $options = $this->linkContainerOptions;
241 7
        $linkWrapTag = ArrayHelper::remove($options, 'tag', 'li');
242 7
        Html::addCssClass($options, empty($class) ? $this->pageCssClass : $class);
243
244 7
        if ($active) {
245 7
            Html::addCssClass($options, $this->activePageCssClass);
246
        }
247 7
        if ($disabled) {
248 3
            Html::addCssClass($options, $this->disabledPageCssClass);
249 3
            $disabledItemOptions = $this->disabledListItemSubTagOptions;
250 3
            $tag = ArrayHelper::remove($disabledItemOptions, 'tag', 'span');
251
252 3
            return Html::tag($linkWrapTag, Html::tag($tag, $label, $disabledItemOptions), $options);
253
        }
254 7
        $linkOptions = $this->linkOptions;
255 7
        $linkOptions['data-page'] = $page;
256
257 7
        return Html::tag($linkWrapTag, Html::a($label, $this->pagination->createUrl($page), $linkOptions), $options);
258
    }
259
260
    /**
261
     * @return array the begin and end pages that need to be displayed.
262
     */
263 7
    protected function getPageRange()
264
    {
265 7
        $currentPage = $this->pagination->getPage();
266 7
        $pageCount = $this->pagination->getPageCount();
267
268 7
        $beginPage = max(0, $currentPage - (int) ($this->maxButtonCount / 2));
269 7
        if (($endPage = $beginPage + $this->maxButtonCount - 1) >= $pageCount) {
270
            $endPage = $pageCount - 1;
271
            $beginPage = max(0, $endPage - $this->maxButtonCount + 1);
272
        }
273
274 7
        return [$beginPage, $endPage];
275
    }
276
}
277