]> git.mxchange.org Git - friendica.git/blob - src/Content/Pager.php
Merge pull request #8297 from MrPetovan/task/8285-api-events
[friendica.git] / src / Content / Pager.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2020, Friendica
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 integer */
34         private $page = 1;
35         /** @var integer */
36         protected $itemsPerPage = 50;
37         /** @var string */
38         protected $baseQueryString = '';
39
40         /** @var L10n */
41         protected $l10n;
42
43         /**
44          * Instantiates a new Pager with the base parameters.
45          *
46          * Guesses the page number from the GET parameter 'page'.
47          *
48          * @param L10n    $l10n
49          * @param string  $queryString  The query string of the current page
50          * @param integer $itemsPerPage An optional number of items per page to override the default value
51          */
52         public function __construct(L10n $l10n, $queryString, $itemsPerPage = 50)
53         {
54                 $this->l10n = $l10n;
55
56                 $this->setQueryString($queryString);
57                 $this->setItemsPerPage($itemsPerPage);
58                 $this->setPage(($_GET['page'] ?? 0) ?: 1);
59         }
60
61         /**
62          * Returns the start offset for a LIMIT clause. Starts at 0.
63          *
64          * @return integer
65          */
66         public function getStart()
67         {
68                 return max(0, ($this->page * $this->itemsPerPage) - $this->itemsPerPage);
69         }
70
71         /**
72          * Returns the number of items per page
73          *
74          * @return integer
75          */
76         public function getItemsPerPage()
77         {
78                 return $this->itemsPerPage;
79         }
80
81         /**
82          * Returns the current page number
83          *
84          * @return int
85          */
86         public function getPage()
87         {
88                 return $this->page;
89         }
90
91         /**
92          * Returns the base query string.
93          *
94          * Warning: this isn't the same value as passed to the constructor.
95          * See setQueryString() for the inventory of transformations
96          *
97          * @see setBaseQuery()
98          * @return string
99          */
100         public function getBaseQueryString()
101         {
102                 return Strings::ensureQueryParameter($this->baseQueryString);
103         }
104
105         /**
106          * Sets the number of items per page, 1 minimum.
107          *
108          * @param integer $itemsPerPage
109          */
110         public function setItemsPerPage($itemsPerPage)
111         {
112                 $this->itemsPerPage = max(1, intval($itemsPerPage));
113         }
114
115         /**
116          * Sets the current page number. Starts at 1.
117          *
118          * @param integer $page
119          */
120         public function setPage($page)
121         {
122                 $this->page = max(1, intval($page));
123         }
124
125         /**
126          * Sets the base query string from a full query string.
127          *
128          * Strips the 'page' parameter, and remove the 'q=' string for some reason.
129          *
130          * @param string $queryString
131          */
132         public function setQueryString($queryString)
133         {
134                 $stripped = preg_replace('/([&?]page=[0-9]*)/', '', $queryString);
135
136                 $stripped = trim($stripped, '/');
137
138                 $this->baseQueryString = $stripped;
139         }
140
141         /**
142          * Minimal pager (newer/older)
143          *
144          * This mode is intended for reverse chronological pages and presents only two links, newer (previous) and older (next).
145          * The itemCount is the number of displayed items. If no items are displayed, the older button is disabled.
146          *
147          * Example usage:
148          *
149          * $pager = new Pager($a->query_string);
150          *
151          * $params = ['order' => ['sort_field' => true], 'limit' => [$pager->getStart(), $pager->getItemsPerPage()]];
152          * $items = DBA::toArray(DBA::select($table, $fields, $condition, $params));
153          *
154          * $html = $pager->renderMinimal(count($items));
155          *
156          * @param int $itemCount The number of displayed items on the page
157          * @return string HTML string of the pager
158          * @throws \Exception
159          */
160         public function renderMinimal(int $itemCount)
161         {
162                 $displayedItemCount = max(0, intval($itemCount));
163
164                 $data = [
165                         'class' => 'pager',
166                         'prev'  => [
167                                 'url'   => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . ($this->getPage() - 1)),
168                                 'text'  => $this->l10n->t('newer'),
169                                 'class' => 'previous' . ($this->getPage() == 1 ? ' disabled' : '')
170                         ],
171                         'next'  => [
172                                 'url'   => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . ($this->getPage() + 1)),
173                                 'text'  => $this->l10n->t('older'),
174                                 'class' =>  'next' . ($displayedItemCount < $this->getItemsPerPage() ? ' disabled' : '')
175                         ]
176                 ];
177
178                 $tpl = Renderer::getMarkupTemplate('paginate.tpl');
179                 return Renderer::replaceMacros($tpl, ['pager' => $data]);
180         }
181
182         /**
183          * Full pager (first / prev / 1 / 2 / ... / 14 / 15 / next / last)
184          *
185          * This mode presents page numbers as well as first, previous, next and last links.
186          * The itemCount is the total number of items including those not displayed.
187          *
188          * Example usage:
189          *
190          * $total = DBA::count($table, $condition);
191          *
192          * $pager = new Pager($a->query_string, $total);
193          *
194          * $params = ['limit' => [$pager->getStart(), $pager->getItemsPerPage()]];
195          * $items = DBA::toArray(DBA::select($table, $fields, $condition, $params));
196          *
197          * $html = $pager->renderFull();
198          *
199          * @param integer $itemCount The total number of items including those note displayed on the page
200          * @return string HTML string of the pager
201          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
202          */
203         public function renderFull($itemCount)
204         {
205                 $totalItemCount = max(0, intval($itemCount));
206
207                 $data = [];
208
209                 $data['class'] = 'pagination';
210                 if ($totalItemCount > $this->getItemsPerPage()) {
211                         $data['first'] = [
212                                 'url'   => Strings::ensureQueryParameter($this->baseQueryString . '&page=1'),
213                                 'text'  => $this->l10n->t('first'),
214                                 'class' => $this->getPage() == 1 ? 'disabled' : ''
215                         ];
216                         $data['prev'] = [
217                                 'url'   => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . ($this->getPage() - 1)),
218                                 'text'  => $this->l10n->t('prev'),
219                                 'class' => $this->getPage() == 1 ? 'disabled' : ''
220                         ];
221
222                         $numpages = $totalItemCount / $this->getItemsPerPage();
223
224                         $numstart = 1;
225                         $numstop = $numpages;
226
227                         // Limit the number of displayed page number buttons.
228                         if ($numpages > 8) {
229                                 $numstart = (($this->getPage() > 4) ? ($this->getPage() - 4) : 1);
230                                 $numstop = (($this->getPage() > ($numpages - 7)) ? $numpages : ($numstart + 8));
231                         }
232
233                         $pages = [];
234
235                         for ($i = $numstart; $i <= $numstop; $i++) {
236                                 if ($i == $this->getPage()) {
237                                         $pages[$i] = [
238                                                 'url'   => '#',
239                                                 'text'  => $i,
240                                                 'class' => 'current active'
241                                         ];
242                                 } else {
243                                         $pages[$i] = [
244                                                 'url'   => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . $i),
245                                                 'text'  => $i,
246                                                 'class' => 'n'
247                                         ];
248                                 }
249                         }
250
251                         if (($totalItemCount % $this->getItemsPerPage()) != 0) {
252                                 if ($i == $this->getPage()) {
253                                         $pages[$i] = [
254                                                 'url'   => '#',
255                                                 'text'  => $i,
256                                                 'class' => 'current active'
257                                         ];
258                                 } else {
259                                         $pages[$i] = [
260                                                 'url'   => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . $i),
261                                                 'text'  => $i,
262                                                 'class' => 'n'
263                                         ];
264                                 }
265                         }
266
267                         $data['pages'] = $pages;
268
269                         $lastpage = (($numpages > intval($numpages)) ? intval($numpages)+1 : $numpages);
270
271                         $data['next'] = [
272                                 'url'   => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . ($this->getPage() + 1)),
273                                 'text'  => $this->l10n->t('next'),
274                                 'class' => $this->getPage() == $lastpage ? 'disabled' : ''
275                         ];
276                         $data['last'] = [
277                                 'url'   => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . $lastpage),
278                                 'text'  => $this->l10n->t('last'),
279                                 'class' => $this->getPage() == $lastpage ? 'disabled' : ''
280                         ];
281                 }
282
283                 $tpl = Renderer::getMarkupTemplate('paginate.tpl');
284                 return Renderer::replaceMacros($tpl, ['pager' => $data]);
285         }
286 }