Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
65 / 65
100.00% covered (success)
100.00%
10 / 10
CRAP
100.00% covered (success)
100.00%
1 / 1
Range
100.00% covered (success)
100.00%
65 / 65
100.00% covered (success)
100.00%
10 / 10
35
100.00% covered (success)
100.00%
1 / 1
 setSeparator
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setClassOn
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setClassOff
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getSeparator
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getLinkRange
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
4
 getClassOn
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getClassOff
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 createRange
100.00% covered (success)
100.00%
42 / 42
100.00% covered (success)
100.00%
1 / 1
17
 wrapLinks
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
6
 __toString
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <dev@noladev.com>
8 * @copyright  Copyright (c) 2009-2027 NOLA Interactive, LLC.
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Paginator;
16
17/**
18 * Paginator range of links class
19 *
20 * @category   Pop
21 * @package    Pop\Paginator
22 * @author     Nick Sagona, III <dev@noladev.com>
23 * @copyright  Copyright (c) 2009-2027 NOLA Interactive, LLC.
24 * @license    https://www.popphp.org/license     New BSD License
25 * @version    4.1.0
26 */
27class Range extends AbstractPaginator
28{
29
30    /**
31     * Link separator
32     * @var ?string
33     */
34    protected ?string $separator = null;
35
36    /**
37     * Page links property
38     * @var array
39     */
40    protected array $links = [];
41
42    /**
43     * Class 'on' name for page link tags
44     * @var ?string
45     */
46    protected ?string $classOn = null;
47
48    /**
49     * Class 'off' name for page link tags
50     * @var ?string
51     */
52    protected ?string $classOff = null;
53
54    /**
55     * Set the bookend separator
56     *
57     * @param  string $sep
58     * @return Range
59     */
60    public function setSeparator(string $sep): Range
61    {
62        $this->separator = $sep;
63        return $this;
64    }
65
66    /**
67     * Set the class 'on' name
68     *
69     * @param  string $class
70     * @return Range
71     */
72    public function setClassOn(string $class): Range
73    {
74        $this->classOn = $class;
75        return $this;
76    }
77
78    /**
79     * Set the class 'off' name.
80     *
81     * @param  string $class
82     * @return Range
83     */
84    public function setClassOff(string $class): Range
85    {
86        $this->classOff = $class;
87        return $this;
88    }
89
90    /**
91     * Get the bookend separator
92     *
93     * @return string
94     */
95    public function getSeparator(): string
96    {
97        return $this->separator ?? '';
98    }
99
100    /**
101     * Get the page links
102     *
103     * @param  ?int $page
104     * @return array
105     */
106    public function getLinkRange(?int $page = null): array
107    {
108        if ($page === null) {
109            $page = (isset($_GET[$this->queryKey]) && ((int)$_GET[$this->queryKey] > 0)) ? (int)$_GET[$this->queryKey] : 1;
110        }
111        $this->createRange($page);
112
113        return $this->links;
114    }
115
116    /**
117     * Get the class 'on' name
118     *
119     * @return string
120     */
121    public function getClassOn(): string
122    {
123        return $this->classOn ?? '';
124    }
125
126    /**
127     * Get the class 'off' name.
128     *
129     * @return string
130     */
131    public function getClassOff(): string
132    {
133        return $this->classOff ?? '';
134    }
135
136    /**
137     * Create links
138     *
139     * @param  int  $page
140     * @return void
141     */
142    public function createRange(int $page = 1): void
143    {
144        $this->currentPage = $page;
145
146        // Generate the page links.
147        $this->links = [];
148
149        // Preserve any passed GET parameters.
150        $query = null;
151        $uri   = null;
152
153        if (isset($_SERVER['REQUEST_URI'])) {
154            $uri = (!empty($_SERVER['QUERY_STRING'])) ?
155                str_replace('?' . $_SERVER['QUERY_STRING'], '', $_SERVER['REQUEST_URI']) :
156                $_SERVER['REQUEST_URI'];
157            $uri = htmlspecialchars($uri, ENT_QUOTES);
158
159            if (count($_GET) > 0) {
160                $get = $_GET;
161                if (isset($get[$this->queryKey])) {
162                    unset($get[$this->queryKey]);
163                }
164                $query = '&' . http_build_query($get);
165            }
166        }
167
168        // Calculate page range
169        $pageRange = $this->calculateRange($page);
170
171        for ($i = $pageRange['start']; $i <= $pageRange['end']; $i++) {
172            $newLink  = null;
173            $prevLink = null;
174            $nextLink = null;
175            $classOff = ($this->classOff !== null) ? " class=\"{$this->classOff}\"" : null;
176            $classOn  = ($this->classOn !== null) ? " class=\"{$this->classOn}\"" : null;
177
178            $newLink = ($i == $page) ? "<span{$classOff}>{$i}</span>" : "<a{$classOn} href=\"" . $uri . "?" .
179                $this->queryKey . "={$i}{$query}\">{$i}</a>";
180
181            if (($i == $pageRange['start']) && ($pageRange['prev'])) {
182                if ($this->bookends['start'] !== null) {
183                    $startLink = "<a{$classOn} href=\"" . $uri . "?" . $this->queryKey . "=1" . "{$query}\">" .
184                        $this->bookends['start'] . "</a>";
185                    $this->links[] = $startLink;
186                }
187                if ($this->bookends['previous'] !== null) {
188                    $prevLink  = "<a{$classOn} href=\"" . $uri . "?" . $this->queryKey . "=" . ($i - 1) . "{$query}\">" .
189                        $this->bookends['previous'] . "</a>";
190                    $this->links[] = $prevLink;
191                }
192            }
193
194            $this->links[] = $newLink;
195
196            if (($i == $pageRange['end']) && ($pageRange['next'])) {
197                if ($this->bookends['next'] !== null) {
198                    $nextLink = "<a{$classOn} href=\"" . $uri . "?" . $this->queryKey . "=" . ($i + 1) . "{$query}\">" .
199                        $this->bookends['next'] . "</a>";
200                    $this->links[] = $nextLink;
201                }
202                if ($this->bookends['end'] !== null) {
203                    $endLink  = "<a{$classOn} href=\"" . $uri . "?" . $this->queryKey . "=" . $this->numberOfPages .
204                        "{$query}\">" . $this->bookends['end'] . "</a>";
205                    $this->links[] = $endLink;
206                }
207            }
208        }
209    }
210
211    /**
212     * Wrap page links in an HTML node
213     *
214     * @param  string  $node
215     * @param  ?string $classOn
216     * @param  ?string $classOff
217     * @return array
218     */
219    public function wrapLinks(string $node, ?string $classOn = null, ?string $classOff = null): array
220    {
221        if (empty($this->links)) {
222            $this->getLinkRange();
223        }
224        $classOff = ($classOff !== null) ? " class=\"{$classOff}\"" : null;
225        $classOn  = ($classOn !== null) ? " class=\"{$classOn}\"" : null;
226
227        foreach ($this->links as $i => $link) {
228            $this->links[$i] = '<' . $node . ((str_contains($link, 'span')) ? $classOff : $classOn) . '>' . $link . '</' . $node . '>';
229        }
230
231        return $this->links;
232    }
233
234    /**
235     * Output the rendered page links
236     *
237     * @return string
238     */
239    public function __toString(): string
240    {
241        if (empty($this->links)) {
242            $this->getLinkRange();
243        }
244        return implode((string)$this->separator, $this->links) . PHP_EOL;
245    }
246
247}