├── src
├── Languages
│ ├── en
│ │ └── pagination.php
│ ├── es
│ │ └── pagination.php
│ └── pt-br
│ │ └── pagination.php
├── Views
│ ├── head.php
│ ├── header.php
│ ├── foundation-short.php
│ ├── w3-short.php
│ ├── semantic-ui-short.php
│ ├── bootstrap-short.php
│ ├── bulma-short.php
│ ├── pagination-short.php
│ ├── tailwind-short.php
│ ├── materialize-short.php
│ ├── primer-short.php
│ ├── foundation.php
│ ├── semantic-ui.php
│ ├── w3.php
│ ├── pagination.php
│ ├── bootstrap.php
│ ├── materialize.php
│ ├── bulma.php
│ ├── primer.php
│ └── tailwind.php
└── Pager.php
├── README.md
├── LICENSE
├── .phpstorm.meta.php
└── composer.json
/src/Languages/en/pagination.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | return [
11 | 'first' => 'First',
12 | 'last' => 'Last',
13 | 'next' => 'Next',
14 | 'previous' => 'Previous',
15 | ];
16 |
--------------------------------------------------------------------------------
/src/Languages/es/pagination.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | return [
11 | 'first' => 'Primera',
12 | 'last' => 'Última',
13 | 'next' => 'Siguiente',
14 | 'previous' => 'Anterior',
15 | ];
16 |
--------------------------------------------------------------------------------
/src/Languages/pt-br/pagination.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | return [
11 | 'first' => 'Primeira',
12 | 'last' => 'Última',
13 | 'next' => 'Próxima',
14 | 'previous' => 'Anterior',
15 | ];
16 |
--------------------------------------------------------------------------------
/src/Views/head.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | ?>
14 |
15 | getPreviousPage()) : ?>
16 |
17 |
18 |
19 | getNextPage()) : ?>
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/Views/header.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * HTTP Header Link.
12 | *
13 | * @see https://tools.ietf.org/html/rfc5988
14 | *
15 | * @var Framework\Pagination\Pager $pager
16 | */
17 | $links = '';
18 |
19 | if ($pager->getPreviousPage()) {
20 | $links .= '<' . $pager->getFirstPageUrl() . '>; rel="first",';
21 | $links .= '<' . $pager->getPreviousPageUrl() . '>; rel="prev"';
22 | }
23 |
24 | if ($pager->getNextPage()) {
25 | if ($links !== '') {
26 | $links .= ',';
27 | }
28 | $links .= '<' . $pager->getNextPageUrl() . '>; rel="next",';
29 | $links .= '<' . $pager->getLastPageUrl() . '>; rel="last"';
30 | }
31 |
32 | echo $links;
33 |
--------------------------------------------------------------------------------
/src/Views/foundation-short.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | $language = $pager->getLanguage();
14 | ?>
15 |
32 |
--------------------------------------------------------------------------------
/src/Views/w3-short.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | $language = $pager->getLanguage();
14 | ?>
15 |
30 |
--------------------------------------------------------------------------------
/src/Views/semantic-ui-short.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | $language = $pager->getLanguage();
14 | ?>
15 |
16 |
29 |
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Aplus Framework Pagination Library
4 |
5 | - [Home](https://aplus-framework.com/packages/pagination)
6 | - [User Guide](https://docs.aplus-framework.com/guides/libraries/pagination/index.html)
7 | - [API Documentation](https://docs.aplus-framework.com/packages/pagination.html)
8 |
9 | [](https://github.com/aplus-framework/pagination/actions/workflows/tests.yml)
10 | [](https://coveralls.io/github/aplus-framework/pagination?branch=master)
11 | [](https://packagist.org/packages/aplus/pagination)
12 | [](https://aplus-framework.com/sponsor)
13 |
--------------------------------------------------------------------------------
/src/Views/bootstrap-short.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | $language = $pager->getLanguage();
14 | ?>
15 |
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Natan Felles
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/Views/bulma-short.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | $language = $pager->getLanguage();
14 | ?>
15 |
34 |
--------------------------------------------------------------------------------
/src/Views/pagination-short.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | $language = $pager->getLanguage();
14 | ?>
15 |
33 |
--------------------------------------------------------------------------------
/src/Views/tailwind-short.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | $language = $pager->getLanguage();
14 | ?>
15 |
28 |
--------------------------------------------------------------------------------
/src/Views/materialize-short.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | $language = $pager->getLanguage();
14 | ?>
15 |
34 |
--------------------------------------------------------------------------------
/src/Views/primer-short.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | $language = $pager->getLanguage();
14 | ?>
15 |
16 |
37 |
38 |
--------------------------------------------------------------------------------
/.phpstorm.meta.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | namespace PHPSTORM_META;
11 |
12 | registerArgumentsSet(
13 | 'views',
14 | 'head',
15 | 'header',
16 | 'pager',
17 | 'pagination',
18 | 'pagination-short',
19 | 'bootstrap',
20 | 'bootstrap-short',
21 | 'bootstrap5',
22 | 'bootstrap5-short',
23 | 'bulma',
24 | 'bulma-short',
25 | 'bulma1',
26 | 'bulma1-short',
27 | 'foundation',
28 | 'foundation-short',
29 | 'foundation6',
30 | 'foundation6-short',
31 | 'materialize',
32 | 'materialize-short',
33 | 'materialize1',
34 | 'materialize1-short',
35 | 'primer',
36 | 'primer-short',
37 | 'primer20',
38 | 'primer20-short',
39 | 'semantic-ui',
40 | 'semantic-ui-short',
41 | 'semantic-ui2',
42 | 'semantic-ui2-short',
43 | 'tailwind',
44 | 'tailwind-short',
45 | 'tailwind3',
46 | 'tailwind3-short',
47 | 'w3',
48 | 'w3-short',
49 | 'w34',
50 | 'w34-short',
51 | );
52 | expectedArguments(
53 | \Framework\Pagination\Pager::getView(),
54 | 0,
55 | argumentsSet('views')
56 | );
57 | expectedArguments(
58 | \Framework\Pagination\Pager::render(),
59 | 0,
60 | argumentsSet('views')
61 | );
62 | expectedArguments(
63 | \Framework\Pagination\Pager::setDefaultView(),
64 | 0,
65 | argumentsSet('views')
66 | );
67 | expectedArguments(
68 | \Framework\Pagination\Pager::setView(),
69 | 0,
70 | argumentsSet('views')
71 | );
72 |
--------------------------------------------------------------------------------
/src/Views/foundation.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | $language = $pager->getLanguage();
14 | ?>
15 |
62 |
--------------------------------------------------------------------------------
/src/Views/semantic-ui.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | $language = $pager->getLanguage();
14 | ?>
15 |
16 |
51 |
52 |
--------------------------------------------------------------------------------
/src/Views/w3.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | $language = $pager->getLanguage();
14 | ?>
15 |
52 |
--------------------------------------------------------------------------------
/src/Views/pagination.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | $language = $pager->getLanguage();
14 | ?>
15 |
64 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aplus/pagination",
3 | "description": "Aplus Framework Pagination Library",
4 | "license": "MIT",
5 | "type": "library",
6 | "keywords": [
7 | "pager",
8 | "pagination",
9 | "bootstrap",
10 | "bulma",
11 | "semantic-ui",
12 | "tailwind",
13 | "foundation"
14 | ],
15 | "authors": [
16 | {
17 | "name": "Natan Felles",
18 | "email": "natanfelles@gmail.com",
19 | "homepage": "https://natanfelles.github.io"
20 | }
21 | ],
22 | "homepage": "https://aplus-framework.com/packages/pagination",
23 | "support": {
24 | "email": "support@aplus-framework.com",
25 | "issues": "https://github.com/aplus-framework/pagination/issues",
26 | "forum": "https://aplus-framework.com/forum",
27 | "source": "https://github.com/aplus-framework/pagination",
28 | "docs": "https://docs.aplus-framework.com/guides/libraries/pagination/"
29 | },
30 | "funding": [
31 | {
32 | "type": "Aplus Sponsor",
33 | "url": "https://aplus-framework.com/sponsor"
34 | }
35 | ],
36 | "require": {
37 | "php": ">=8.3",
38 | "ext-json": "*",
39 | "aplus/helpers": "^4.0",
40 | "aplus/http": "^6.0",
41 | "aplus/language": "^4.0"
42 | },
43 | "require-dev": {
44 | "ext-xdebug": "*",
45 | "aplus/coding-standard": "^2.8",
46 | "ergebnis/composer-normalize": "^2.25",
47 | "jetbrains/phpstorm-attributes": "^1.0",
48 | "phpmd/phpmd": "^2.13",
49 | "phpstan/phpstan": "^1.5",
50 | "phpunit/phpunit": "^10.5"
51 | },
52 | "minimum-stability": "dev",
53 | "prefer-stable": true,
54 | "autoload": {
55 | "psr-4": {
56 | "Framework\\Pagination\\": "src/"
57 | }
58 | },
59 | "autoload-dev": {
60 | "psr-4": {
61 | "Tests\\Pagination\\": "tests/"
62 | }
63 | },
64 | "config": {
65 | "allow-plugins": {
66 | "ergebnis/composer-normalize": true
67 | },
68 | "optimize-autoloader": true,
69 | "preferred-install": "dist",
70 | "sort-packages": true
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/Views/bootstrap.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | $language = $pager->getLanguage();
14 | ?>
15 |
64 |
--------------------------------------------------------------------------------
/src/Views/materialize.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | $language = $pager->getLanguage();
14 | ?>
15 |
68 |
69 |
--------------------------------------------------------------------------------
/src/Views/bulma.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | $language = $pager->getLanguage();
14 | ?>
15 |
66 |
--------------------------------------------------------------------------------
/src/Views/primer.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | $language = $pager->getLanguage();
14 | ?>
15 |
16 |
88 |
89 |
--------------------------------------------------------------------------------
/src/Views/tailwind.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | /**
11 | * @var Framework\Pagination\Pager $pager
12 | */
13 | $language = $pager->getLanguage();
14 | $hasFirst = $pager->getCurrentPage() - $pager->getSurround() > 1;
15 | $hasLast = $pager->getLastPage()
16 | && $pager->getCurrentPage() + $pager->getSurround() < $pager->getLastPage();
17 | $hasPrev = $pager->getPreviousPage();
18 | ?>
19 |
79 |
80 |
--------------------------------------------------------------------------------
/src/Pager.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 | namespace Framework\Pagination;
11 |
12 | use Framework\Helpers\Isolation;
13 | use Framework\HTTP\URL;
14 | use Framework\Language\Language;
15 | use InvalidArgumentException;
16 | use JetBrains\PhpStorm\ArrayShape;
17 | use JetBrains\PhpStorm\Pure;
18 | use JsonSerializable;
19 | use LogicException;
20 | use Stringable;
21 |
22 | /**
23 | * Class Pager.
24 | *
25 | * @package pagination
26 | */
27 | class Pager implements JsonSerializable, Stringable
28 | {
29 | protected int $currentPage;
30 | protected ?int $previousPage = null;
31 | protected ?int $nextPage = null;
32 | protected int $lastPage;
33 | protected int $itemsPerPage;
34 | protected int $totalItems;
35 | protected int $surround = 2;
36 | /**
37 | * @var array
38 | */
39 | protected array $views = [
40 | // HTML Head
41 | 'head' => __DIR__ . '/Views/head.php',
42 | // HTTP Header
43 | 'header' => __DIR__ . '/Views/header.php',
44 | // HTML Previous and Next
45 | 'pager' => __DIR__ . '/Views/pagination-short.php',
46 | // HTML Full
47 | 'pagination' => __DIR__ . '/Views/pagination.php',
48 | 'pagination-short' => __DIR__ . '/Views/pagination-short.php',
49 | // Bootstrap 5
50 | 'bootstrap' => __DIR__ . '/Views/bootstrap.php',
51 | 'bootstrap-short' => __DIR__ . '/Views/bootstrap-short.php',
52 | 'bootstrap5' => __DIR__ . '/Views/bootstrap.php',
53 | 'bootstrap5-short' => __DIR__ . '/Views/bootstrap-short.php',
54 | // Bulma 1
55 | 'bulma' => __DIR__ . '/Views/bulma.php',
56 | 'bulma-short' => __DIR__ . '/Views/bulma-short.php',
57 | 'bulma1' => __DIR__ . '/Views/bulma.php',
58 | 'bulma1-short' => __DIR__ . '/Views/bulma-short.php',
59 | // Foundation 6
60 | 'foundation' => __DIR__ . '/Views/foundation.php',
61 | 'foundation-short' => __DIR__ . '/Views/foundation-short.php',
62 | 'foundation6' => __DIR__ . '/Views/foundation.php',
63 | 'foundation6-short' => __DIR__ . '/Views/foundation-short.php',
64 | // Materialize 1
65 | 'materialize' => __DIR__ . '/Views/materialize.php',
66 | 'materialize-short' => __DIR__ . '/Views/materialize-short.php',
67 | 'materialize1' => __DIR__ . '/Views/materialize.php',
68 | 'materialize1-short' => __DIR__ . '/Views/materialize-short.php',
69 | // Primer 20
70 | 'primer' => __DIR__ . '/Views/primer.php',
71 | 'primer-short' => __DIR__ . '/Views/primer-short.php',
72 | 'primer20' => __DIR__ . '/Views/primer.php',
73 | 'primer20-short' => __DIR__ . '/Views/primer-short.php',
74 | // Semantic UI 2
75 | 'semantic-ui' => __DIR__ . '/Views/semantic-ui.php',
76 | 'semantic-ui-short' => __DIR__ . '/Views/semantic-ui-short.php',
77 | 'semantic-ui2' => __DIR__ . '/Views/semantic-ui.php',
78 | 'semantic-ui2-short' => __DIR__ . '/Views/semantic-ui-short.php',
79 | // Tailwind CSS 3
80 | 'tailwind' => __DIR__ . '/Views/tailwind.php',
81 | 'tailwind-short' => __DIR__ . '/Views/tailwind-short.php',
82 | 'tailwind3' => __DIR__ . '/Views/tailwind.php',
83 | 'tailwind3-short' => __DIR__ . '/Views/tailwind-short.php',
84 | // W3.CSS 4
85 | 'w3' => __DIR__ . '/Views/w3.php',
86 | 'w3-short' => __DIR__ . '/Views/w3-short.php',
87 | 'w34' => __DIR__ . '/Views/w3.php',
88 | 'w34-short' => __DIR__ . '/Views/w3-short.php',
89 | ];
90 | protected string $defaultView = 'pagination';
91 | protected URL $url;
92 | protected string $oldUrl;
93 | protected string $query = 'page';
94 | protected Language $language;
95 |
96 | /**
97 | * Pager constructor.
98 | *
99 | * @param int|string $currentPage
100 | * @param int|string $itemsPerPage
101 | * @param int $totalItems
102 | * @param Language|null $language Language instance
103 | * @param string|null $url
104 | */
105 | public function __construct(
106 | int | string $currentPage,
107 | int | string $itemsPerPage,
108 | int $totalItems,
109 | ?Language $language = null,
110 | ?string $url = null
111 | ) {
112 | if ($language) {
113 | $this->setLanguage($language);
114 | }
115 | $this->setCurrentPage(static::sanitize($currentPage))
116 | ->setItemsPerPage(static::sanitize($itemsPerPage))
117 | ->setTotalItems($totalItems);
118 | $lastPage = (int) \ceil($this->getTotalItems() / $this->getItemsPerPage());
119 | $this->setLastPage(static::sanitize($lastPage));
120 | if ($this->getCurrentPage() > 1) {
121 | if ($this->getCurrentPage() - 1 <= $this->getLastPage()) {
122 | $this->setPreviousPage($this->getCurrentPage() - 1);
123 | } elseif ($this->getLastPage() > 1) {
124 | $this->setPreviousPage($this->getLastPage());
125 | }
126 | }
127 | if ($this->getCurrentPage() < $this->getLastPage()) {
128 | $this->setNextPage($this->getCurrentPage() + 1);
129 | }
130 | isset($url) ? $this->setUrl($url) : $this->prepareUrl();
131 | }
132 |
133 | public function __toString() : string
134 | {
135 | return $this->render();
136 | }
137 |
138 | /**
139 | * @since 3.5
140 | *
141 | * @return int
142 | */
143 | public function getItemsPerPage() : int
144 | {
145 | return $this->itemsPerPage;
146 | }
147 |
148 | /**
149 | * @since 3.5
150 | *
151 | * @param int $itemsPerPage
152 | *
153 | * @return static
154 | */
155 | protected function setItemsPerPage(int $itemsPerPage) : static
156 | {
157 | $this->itemsPerPage = $itemsPerPage;
158 | return $this;
159 | }
160 |
161 | /**
162 | * @since 3.5
163 | *
164 | * @return int
165 | */
166 | public function getTotalItems() : int
167 | {
168 | return $this->totalItems;
169 | }
170 |
171 | /**
172 | * @since 3.5
173 | *
174 | * @param int $totalItems
175 | *
176 | * @return static
177 | */
178 | protected function setTotalItems(int $totalItems) : static
179 | {
180 | $this->totalItems = $totalItems;
181 | return $this;
182 | }
183 |
184 | /**
185 | * @param Language|null $language
186 | *
187 | * @return static
188 | */
189 | public function setLanguage(?Language $language = null) : static
190 | {
191 | $this->language = $language ?? new Language();
192 | $this->language->addDirectory(__DIR__ . '/Languages');
193 | return $this;
194 | }
195 |
196 | /**
197 | * @return Language
198 | */
199 | public function getLanguage() : Language
200 | {
201 | if (!isset($this->language)) {
202 | $this->setLanguage();
203 | }
204 | return $this->language;
205 | }
206 |
207 | /**
208 | * @param string $name
209 | * @param string $filepath
210 | *
211 | * @return static
212 | */
213 | public function setView(string $name, string $filepath) : static
214 | {
215 | if (!\is_file($filepath)) {
216 | throw new InvalidArgumentException('Invalid Pager view filepath: ' . $filepath);
217 | }
218 | $this->views[$name] = $filepath;
219 | return $this;
220 | }
221 |
222 | /**
223 | * Get a view filepath.
224 | *
225 | * @param string $name The view name. Default names are: head, header, pager and pagination
226 | *
227 | * @return string
228 | */
229 | public function getView(string $name) : string
230 | {
231 | if (empty($this->views[$name])) {
232 | throw new InvalidArgumentException('Pager view not found: ' . $name);
233 | }
234 | return $this->views[$name];
235 | }
236 |
237 | /**
238 | * @return array
239 | */
240 | #[Pure]
241 | public function getViews() : array
242 | {
243 | return $this->views;
244 | }
245 |
246 | /**
247 | * @return int
248 | */
249 | #[Pure]
250 | public function getSurround() : int
251 | {
252 | return $this->surround;
253 | }
254 |
255 | /**
256 | * @param int $surround
257 | *
258 | * @return static
259 | */
260 | public function setSurround(int $surround) : static
261 | {
262 | $this->surround = \max($surround, 0);
263 | return $this;
264 | }
265 |
266 | /**
267 | * @param string $query
268 | *
269 | * @return static
270 | */
271 | public function setQuery(string $query = 'page') : static
272 | {
273 | $this->query = $query;
274 | return $this;
275 | }
276 |
277 | #[Pure]
278 | public function getQuery() : string
279 | {
280 | return $this->query;
281 | }
282 |
283 | /**
284 | * @param array|null $allowed List of queries, an empty array
285 | * to allow only the default or null to allow all
286 | *
287 | * @return static
288 | */
289 | public function setAllowedQueries(?array $allowed) : static
290 | {
291 | $this->setUrl($this->oldUrl, $allowed);
292 | return $this;
293 | }
294 |
295 | protected function prepareUrl() : static
296 | {
297 | $scheme = ((isset($_SERVER['REQUEST_SCHEME']) && $_SERVER['REQUEST_SCHEME'] === 'https')
298 | || (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on'))
299 | ? 'https'
300 | : 'http';
301 | $this->setUrl($scheme . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
302 | return $this;
303 | }
304 |
305 | /**
306 | * @param URL|string $currentPageUrl
307 | * @param array|null $allowedQueries List of queries, an empty array
308 | * to allow only the default or null to allow all
309 | *
310 | * @return static
311 | */
312 | public function setUrl(URL | string $currentPageUrl, ?array $allowedQueries = null) : static
313 | {
314 | $currentPageUrl = $currentPageUrl instanceof URL
315 | ? clone $currentPageUrl
316 | : new URL($currentPageUrl);
317 | $this->oldUrl = $currentPageUrl->toString();
318 | if ($allowedQueries !== null) {
319 | $allowedQueries[] = $this->getQuery();
320 | }
321 | $currentPageUrl->setQuery(
322 | $currentPageUrl->getQuery() ?? '',
323 | $allowedQueries ?? []
324 | );
325 | $this->url = $currentPageUrl;
326 | return $this;
327 | }
328 |
329 | public function getUrl() : URL
330 | {
331 | return $this->url;
332 | }
333 |
334 | public function getPageUrl(?int $page) : ?string
335 | {
336 | if ($page === null || $page === 0) {
337 | return null;
338 | }
339 | return $this->url->addQuery($this->getQuery(), $page)->toString();
340 | }
341 |
342 | public function getCurrentPage() : int
343 | {
344 | return $this->currentPage;
345 | }
346 |
347 | /**
348 | * @since 3.5
349 | *
350 | * @param int $currentPage
351 | *
352 | * @return static
353 | */
354 | protected function setCurrentPage(int $currentPage) : static
355 | {
356 | $this->currentPage = $currentPage;
357 | return $this;
358 | }
359 |
360 | public function getCurrentPageUrl() : string
361 | {
362 | return $this->getPageUrl($this->currentPage);
363 | }
364 |
365 | #[Pure]
366 | public function getFirstPage() : int
367 | {
368 | return 1;
369 | }
370 |
371 | public function getFirstPageUrl() : string
372 | {
373 | return $this->getPageUrl($this->getFirstPage());
374 | }
375 |
376 | #[Pure]
377 | public function getLastPage() : int
378 | {
379 | return $this->lastPage;
380 | }
381 |
382 | /**
383 | * @since 3.5
384 | *
385 | * @param int $lastPage
386 | *
387 | * @return static
388 | */
389 | protected function setLastPage(int $lastPage) : static
390 | {
391 | $this->lastPage = $lastPage;
392 | return $this;
393 | }
394 |
395 | public function getLastPageUrl() : string
396 | {
397 | return $this->getPageUrl($this->getLastPage());
398 | }
399 |
400 | #[Pure]
401 | public function getPreviousPage() : ?int
402 | {
403 | return $this->previousPage;
404 | }
405 |
406 | /**
407 | * @since 3.5
408 | *
409 | * @param int $previousPage
410 | *
411 | * @return static
412 | */
413 | protected function setPreviousPage(int $previousPage) : static
414 | {
415 | $this->previousPage = $previousPage;
416 | return $this;
417 | }
418 |
419 | public function getPreviousPageUrl() : ?string
420 | {
421 | return $this->getPageUrl($this->getPreviousPage());
422 | }
423 |
424 | #[Pure]
425 | public function getNextPage() : ?int
426 | {
427 | return $this->nextPage;
428 | }
429 |
430 | /**
431 | * @since 3.5
432 | *
433 | * @param int $nextPage
434 | *
435 | * @return static
436 | */
437 | protected function setNextPage(int $nextPage) : static
438 | {
439 | $this->nextPage = $nextPage;
440 | return $this;
441 | }
442 |
443 | public function getNextPageUrl() : ?string
444 | {
445 | return $this->getPageUrl($this->getNextPage());
446 | }
447 |
448 | /**
449 | * @return array
450 | */
451 | public function getPreviousPagesUrls() : array
452 | {
453 | $urls = [];
454 | if ($this->currentPage > 1 && $this->currentPage <= $this->lastPage) {
455 | $range = \range($this->currentPage - $this->surround, $this->currentPage - 1);
456 | foreach ($range as $page) {
457 | if ($page < 1) {
458 | continue;
459 | }
460 | $urls[$page] = $this->getPageUrl($page);
461 | }
462 | }
463 | return $urls;
464 | }
465 |
466 | /**
467 | * @return array
468 | */
469 | public function getNextPagesUrls() : array
470 | {
471 | $urls = [];
472 | if ($this->currentPage < $this->lastPage) {
473 | $range = \range($this->currentPage + 1, $this->currentPage + $this->surround);
474 | foreach ($range as $page) {
475 | if ($page > $this->lastPage) {
476 | break;
477 | }
478 | $urls[$page] = $this->getPageUrl($page);
479 | }
480 | }
481 | return $urls;
482 | }
483 |
484 | /**
485 | * @return array
486 | */
487 | #[ArrayShape([
488 | 'self' => 'int',
489 | 'first' => 'int',
490 | 'prev' => 'int|null',
491 | 'next' => 'int|null',
492 | 'last' => 'int',
493 | ])]
494 | #[Pure]
495 | public function get() : array
496 | {
497 | return [
498 | 'self' => $this->getCurrentPage(),
499 | 'first' => $this->getFirstPage(),
500 | 'prev' => $this->getPreviousPage(),
501 | 'next' => $this->getNextPage(),
502 | 'last' => $this->getLastPage(),
503 | ];
504 | }
505 |
506 | /**
507 | * @return array
508 | */
509 | #[ArrayShape([
510 | 'self' => 'string',
511 | 'first' => 'string',
512 | 'prev' => 'string|null',
513 | 'next' => 'string|null',
514 | 'last' => 'string',
515 | ])]
516 | public function getWithUrl() : array
517 | {
518 | return [
519 | 'self' => $this->getCurrentPageUrl(),
520 | 'first' => $this->getFirstPageUrl(),
521 | 'prev' => $this->getPreviousPageUrl(),
522 | 'next' => $this->getNextPageUrl(),
523 | 'last' => $this->getLastPageUrl(),
524 | ];
525 | }
526 |
527 | /**
528 | * @param string|null $view
529 | *
530 | * @return string
531 | */
532 | public function render(?string $view = null) : string
533 | {
534 | $filename = $this->getView($view ?? $this->getDefaultView());
535 | \ob_start();
536 | Isolation::require($filename, ['pager' => $this]);
537 | return (string) \ob_get_clean();
538 | }
539 |
540 | public function renderShort() : string
541 | {
542 | $view = $this->getDefaultView();
543 | if (!\str_ends_with($view, '-short')) {
544 | $view .= '-short';
545 | }
546 | return $this->render($view);
547 | }
548 |
549 | public function setDefaultView(string $defaultView) : static
550 | {
551 | if (!\array_key_exists($defaultView, $this->views)) {
552 | throw new LogicException(
553 | 'Default view "' . $defaultView . '" is not a valid value'
554 | );
555 | }
556 | $this->defaultView = $defaultView;
557 | return $this;
558 | }
559 |
560 | #[Pure]
561 | public function getDefaultView() : string
562 | {
563 | return $this->defaultView;
564 | }
565 |
566 | /**
567 | * @return array
568 | */
569 | #[ArrayShape([
570 | 'self' => 'string',
571 | 'first' => 'string',
572 | 'prev' => 'string|null',
573 | 'next' => 'string|null',
574 | 'last' => 'string',
575 | ])]
576 | public function jsonSerialize() : array
577 | {
578 | return $this->getWithUrl();
579 | }
580 |
581 | /**
582 | * Sanitize a number.
583 | *
584 | * @param mixed $number
585 | *
586 | * @return int
587 | */
588 | #[Pure]
589 | public static function sanitize(mixed $number) : int
590 | {
591 | if (!\is_numeric($number)) {
592 | return 1;
593 | }
594 | if ($number < 1) {
595 | return 1;
596 | }
597 | return $number >= \PHP_INT_MAX ? \PHP_INT_MAX : (int) $number;
598 | }
599 | }
600 |
--------------------------------------------------------------------------------