]> git.mxchange.org Git - friendica.git/blob - src/Content/Pager.php
Add rel="tag" to the HTML Purifier allow list in BBCode::convert
[friendica.git] / src / Content / Pager.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2022, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Content;
23
24 use Friendica\Core\L10n;
25 use Friendica\Core\Renderer;
26 use Friendica\Util\Strings;
27
28 /**
29  * The Pager has two very different output, Minimal and Full, see renderMinimal() and renderFull() for more details.
30  */
31 class Pager
32 {
33         /** @var int Default count of items per page */
34         const ITEMS_PER_PAGE = 50;
35
36         /** @var integer */
37         private $page = 1;
38         /** @var integer */
39         protected $itemsPerPage = self::ITEMS_PER_PAGE;
40         /** @var string */
41         protected $baseQueryString = '';
42
43         /** @var L10n */
44         protected $l10n;
45
46         /**
47          * Instantiates a new Pager with the base parameters.
48          *
49          * Guesses the page number from the GET parameter 'page'.
50          *
51          * @param L10n    $l10n
52          * @param string  $queryString  The query string of the current page
53          * @param integer $itemsPerPage An optional number of items per page to override the default value
54          */
55         public function __construct(L10n $l10n, $queryString, $itemsPerPage = 50)
56         {
57                 $this->l10n = $l10n;
58
59                 $this->setQueryString($queryString);
60                 $this->setItemsPerPage($itemsPerPage);
61                 $this->setPage(($_GET['page'] ?? 0) ?: 1);
62         }
63
64         /**
65          * Returns the start offset for a LIMIT clause. Starts at 0.
66          *
67          * @return integer
68          */
69         public function getStart()
70         {
71                 return max(0, ($this->page * $this->itemsPerPage) - $this->itemsPerPage);
72         }
73
74         /**
75          * Returns the number of items per page
76          *
77          * @return integer
78          */
79         public function getItemsPerPage()
80         {
81                 return $this->itemsPerPage;
82         }
83
84         /**
85          * Returns the current page number
86          *
87          * @return int
88          */
89         public function getPage()
90         {
91                 return $this->page;
92         }
93
94         /**
95          * Returns the base query string.
96          *
97          * Warning: this isn't the same value as passed to the constructor.
98          * See setQueryString() for the inventory of transformations
99          *
100          * @see setBaseQuery()
101          * @return string
102          */
103         public function getBaseQueryString()
104         {
105                 return Strings::ensureQueryParameter($this->baseQueryString);
106         }
107
108         /**
109          * Sets the number of items per page, 1 minimum.
110          *
111          * @param integer $itemsPerPage
112          */
113         public function setItemsPerPage($itemsPerPage)
114         {
115                 $this->itemsPerPage = max(1, intval($itemsPerPage));
116         }
117
118         /**
119          * Sets the current page number. Starts at 1.
120          *
121          * @param integer $page
122          */
123         public function setPage($page)
124         {
125                 $this->page = max(1, intval($page));
126         }
127
128         /**
129          * Sets the base query string from a full query string.
130          *
131          * Strips the 'page' parameter
132          *
133          * @param string $queryString
134          */
135         public function setQueryString($queryString)
136         {
137                 $stripped = preg_replace('/([&?]page=[0-9]*)/', '', $queryString);
138
139                 $stripped = trim($stripped, '/');
140
141                 $this->baseQueryString = $stripped;
142         }
143
144         /**
145          * Minimal pager (newer/older)
146          *
147          * This mode is intended for reverse chronological pages and presents only two links, newer (previous) and older (next).
148          * The itemCount is the number of displayed items. If no items are displayed, the older button is disabled.
149          *
150          * Example usage:
151          *
152          * $pager = new Pager($a->query_string);
153          *
154          * $params = ['order' => ['sort_field' => true], 'limit' => [$pager->getStart(), $pager->getItemsPerPage()]];
155          * $items = DBA::toArray(DBA::select($table, $fields, $condition, $params));
156          *
157          * $html = $pager->renderMinimal(count($items));
158          *
159          * @param int $itemCount The number of displayed items on the page
160          * @return string HTML string of the pager
161          * @throws \Exception
162          */
163         public function renderMinimal(int $itemCount)
164         {
165                 $displayedItemCount = max(0, intval($itemCount));
166
167                 $data = [
168                         'class' => 'pager',
169                         'prev'  => [
170                                 'url'   => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . ($this->getPage() - 1)),
171                                 'text'  => $this->l10n->t('newer'),
172                                 'class' => 'previous' . ($this->getPage() == 1 ? ' disabled' : '')
173                         ],
174                         'next'  => [
175                                 'url'   => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . ($this->getPage() + 1)),
176                                 'text'  => $this->l10n->t('older'),
177                                 'class' =>  'next' . ($displayedItemCount < $this->getItemsPerPage() ? ' disabled' : '')
178                         ]
179                 ];
180
181                 $tpl = Renderer::getMarkupTemplate('paginate.tpl');
182                 return Renderer::replaceMacros($tpl, ['pager' => $data]);
183         }
184
185         /**
186          * Full pager (first / prev / 1 / 2 / ... / 14 / 15 / next / last)
187          *
188          * This mode presents page numbers as well as first, previous, next and last links.
189          * The itemCount is the total number of items including those not displayed.
190          *
191          * Example usage:
192          *
193          * $total = DBA::count($table, $condition);
194          *
195          * $pager = new Pager($a->query_string, $total);
196          *
197          * $params = ['limit' => [$pager->getStart(), $pager->getItemsPerPage()]];
198          * $items = DBA::toArray(DBA::select($table, $fields, $condition, $params));
199          *
200          * $html = $pager->renderFull();
201          *
202          * @param integer $itemCount The total number of items including those note displayed on the page
203          * @return string HTML string of the pager
204          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
205          */
206         public function renderFull($itemCount)
207         {
208                 $totalItemCount = max(0, intval($itemCount));
209
210                 $data = [];
211
212                 $data['class'] = 'pagination';
213                 if ($totalItemCount > $this->getItemsPerPage()) {
214                         $data['first'] = [
215                                 'url'   => Strings::ensureQueryParameter($this->baseQueryString . '&page=1'),
216                                 'text'  => $this->l10n->t('first'),
217                                 'class' => $this->getPage() == 1 ? 'disabled' : ''
218                         ];
219                         $data['prev'] = [
220                                 'url'   => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . ($this->getPage() - 1)),
221                                 'text'  => $this->l10n->t('prev'),
222                                 'class' => $this->getPage() == 1 ? 'disabled' : ''
223                         ];
224
225                         $numpages = $totalItemCount / $this->getItemsPerPage();
226
227                         $numstart = 1;
228                         $numstop = $numpages;
229
230                         // Limit the number of displayed page number buttons.
231                         if ($numpages > 8) {
232                                 $numstart = (($this->getPage() > 4) ? ($this->getPage() - 4) : 1);
233                                 $numstop = (($this->getPage() > ($numpages - 7)) ? $numpages : ($numstart + 8));
234                         }
235
236                         $pages = [];
237
238                         for ($i = $numstart; $i <= $numstop; $i++) {
239                                 if ($i == $this->getPage()) {
240                                         $pages[$i] = [
241                                                 'url'   => '#',
242                                                 'text'  => $i,
243                                                 'class' => 'current active'
244                                         ];
245                                 } else {
246                                         $pages[$i] = [
247                                                 'url'   => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . $i),
248                                                 'text'  => $i,
249                                                 'class' => 'n'
250                                         ];
251                                 }
252                         }
253
254                         if (($totalItemCount % $this->getItemsPerPage()) != 0) {
255                                 if ($i == $this->getPage()) {
256                                         $pages[$i] = [
257                                                 'url'   => '#',
258                                                 'text'  => $i,
259                                                 'class' => 'current active'
260                                         ];
261                                 } else {
262                                         $pages[$i] = [
263                                                 'url'   => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . $i),
264                                                 'text'  => $i,
265                                                 'class' => 'n'
266                                         ];
267                                 }
268                         }
269
270                         $data['pages'] = $pages;
271
272                         $lastpage = (($numpages > intval($numpages)) ? intval($numpages)+1 : $numpages);
273
274                         $data['next'] = [
275                                 'url'   => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . ($this->getPage() + 1)),
276                                 'text'  => $this->l10n->t('next'),
277                                 'class' => $this->getPage() == $lastpage ? 'disabled' : ''
278                         ];
279                         $data['last'] = [
280                                 'url'   => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . $lastpage),
281                                 'text'  => $this->l10n->t('last'),
282                                 'class' => $this->getPage() == $lastpage ? 'disabled' : ''
283                         ];
284                 }
285
286                 $tpl = Renderer::getMarkupTemplate('paginate.tpl');
287                 return Renderer::replaceMacros($tpl, ['pager' => $data]);
288         }
289 }