Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
bc77d7c0 | 4 | | Copyright CiviCRM LLC. All rights reserved. | |
6a488035 | 5 | | | |
bc77d7c0 TO |
6 | | This work is published under the GNU AGPLv3 license with some | |
7 | | permitted exceptions and without any warranty. For full license | | |
8 | | and copyright information, see https://civicrm.org/licensing | | |
6a488035 | 9 | +--------------------------------------------------------------------+ |
d25dd0ee | 10 | */ |
6a488035 TO |
11 | |
12 | /** | |
6a488035 | 13 | * @package CRM |
ca5cec67 | 14 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
6a488035 TO |
15 | */ |
16 | ||
17 | /** | |
6a488035 TO |
18 | * This class extends the PEAR pager object by substituting standard default pager arguments |
19 | * We also extract the pageId from either the GET variables or the POST variable (since we | |
20 | * use a POST to jump to a specific page). At some point we should evaluate if we want | |
21 | * to use Pager_Jumping instead. We've changed the format to allow navigation by jumping | |
22 | * to a page and also First, Prev CURRENT Next Last | |
6a488035 TO |
23 | */ |
24 | ||
25 | require_once 'Pager/Sliding.php'; | |
5bc392e6 EM |
26 | |
27 | /** | |
28 | * Class CRM_Utils_Pager | |
29 | */ | |
6a488035 TO |
30 | class CRM_Utils_Pager extends Pager_Sliding { |
31 | ||
32 | /** | |
100fef9d | 33 | * Constants for static parameters of the pager |
6a488035 | 34 | */ |
7fa7c084 SL |
35 | const PAGE_ID = 'crmPID', PAGE_ID_TOP = 'crmPID', PAGE_ID_BOTTOM = 'crmPID_B', PAGE_ROWCOUNT = 'crmRowCount'; |
36 | ||
37 | /** | |
38 | * Deprecated constants that might still be used by extensions but no longer by core | |
39 | * @deprecated | |
40 | */ | |
41 | const ROWCOUNT = 50; | |
6a488035 TO |
42 | |
43 | /** | |
100fef9d | 44 | * The output of the pager. This is a name/value array with various keys |
6a488035 | 45 | * that an application could use to display the pager |
50bfb460 | 46 | * |
6a488035 TO |
47 | * @var array |
48 | */ | |
49 | public $_response; | |
50 | ||
51 | /** | |
52 | * The pager constructor. Takes a few values, and then assigns a lot of defaults | |
53 | * to the PEAR pager class | |
54 | * We have embedded some html in this class. Need to figure out how to export this | |
55 | * to the top level at some point in time | |
56 | * | |
c490a46a | 57 | * @param array $params |
f4aaa82a | 58 | * |
e0b82b44 | 59 | * @return \CRM_Utils_Pager the newly created and initialized pager object |
6a488035 | 60 | */ |
00be9182 | 61 | public function __construct($params) { |
6a488035 TO |
62 | if ($params['status'] === NULL) { |
63 | $params['status'] = ts('Contacts %%StatusMessage%%'); | |
64 | } | |
65 | ||
66 | $this->initialize($params); | |
67 | ||
6ef04c72 | 68 | parent::__construct($params); |
6a488035 TO |
69 | |
70 | list($offset, $limit) = $this->getOffsetAndRowCount(); | |
71 | $start = $offset + 1; | |
72 | $end = $offset + $limit; | |
73 | if ($end > $params['total']) { | |
74 | $end = $params['total']; | |
75 | } | |
76 | ||
77 | if ($params['total'] == 0) { | |
78 | $statusMessage = ''; | |
79 | } | |
80 | else { | |
be2fb01f | 81 | $statusMessage = ts('%1 - %2 of %3', [1 => $start, 2 => $end, 3 => $params['total']]); |
6a488035 TO |
82 | } |
83 | $params['status'] = str_replace('%%StatusMessage%%', $statusMessage, $params['status']); | |
84 | ||
be2fb01f | 85 | $this->_response = [ |
6a488035 TO |
86 | 'first' => $this->getFirstPageLink(), |
87 | 'back' => $this->getBackPageLink(), | |
88 | 'next' => $this->getNextPageLink(), | |
89 | 'last' => $this->getLastPageLink(), | |
90 | 'currentPage' => $this->getCurrentPageID(), | |
91 | 'numPages' => $this->numPages(), | |
6b409353 CW |
92 | 'csvString' => $params['csvString'] ?? NULL, |
93 | 'status' => $params['status'] ?? NULL, | |
94 | 'buttonTop' => $params['buttonTop'] ?? NULL, | |
95 | 'buttonBottom' => $params['buttonBottom'] ?? NULL, | |
fe010227 | 96 | 'currentLocation' => $this->getCurrentLocation(), |
be2fb01f | 97 | ]; |
6a488035 TO |
98 | |
99 | /** | |
100 | * A page cannot have two variables with the same form name. Hence in the | |
101 | * pager display, we have a form submission at the top with the normal | |
50bfb460 | 102 | * page variable, but a different form element for one at the bottom. |
6a488035 | 103 | */ |
be2fb01f | 104 | $this->_response['titleTop'] = ts('Page %1 of %2', [ |
6714d8d2 SL |
105 | 1 => '<input size="2" maxlength="4" name="' . self::PAGE_ID . '" type="text" value="' . $this->_response['currentPage'] . '" />', |
106 | 2 => $this->_response['numPages'], | |
107 | ]); | |
be2fb01f | 108 | $this->_response['titleBottom'] = ts('Page %1 of %2', [ |
6714d8d2 SL |
109 | 1 => '<input size="2" maxlength="4" name="' . self::PAGE_ID_BOTTOM . '" type="text" value="' . $this->_response['currentPage'] . '" />', |
110 | 2 => $this->_response['numPages'], | |
111 | ]); | |
6a488035 TO |
112 | } |
113 | ||
114 | /** | |
100fef9d | 115 | * Helper function to assign remaining pager options as good default |
4d429319 | 116 | * values. |
6a488035 | 117 | * |
77855840 | 118 | * @param array $params |
b8c71ffa | 119 | * The set of options needed to initialize the parent constructor. |
6a488035 | 120 | * |
b8c71ffa | 121 | * @return array |
6a488035 | 122 | */ |
00be9182 | 123 | public function initialize(&$params) { |
50bfb460 | 124 | // set the mode for the pager to Sliding |
6a488035 TO |
125 | |
126 | $params['mode'] = 'Sliding'; | |
127 | ||
50bfb460 | 128 | // also set the urlVar to be a crm specific get variable. |
6a488035 TO |
129 | |
130 | $params['urlVar'] = self::PAGE_ID; | |
131 | ||
50bfb460 | 132 | // set this to a small value, since we dont use this functionality |
6a488035 TO |
133 | |
134 | $params['delta'] = 1; | |
135 | ||
136 | $params['totalItems'] = $params['total']; | |
137 | $params['append'] = TRUE; | |
138 | $params['separator'] = ''; | |
139 | $params['spacesBeforeSeparator'] = 1; | |
140 | $params['spacesAfterSeparator'] = 1; | |
be2fb01f CW |
141 | $params['extraVars'] = ['force' => 1]; |
142 | $params['excludeVars'] = ['reset', 'snippet', 'section']; | |
6a488035 TO |
143 | |
144 | // set previous and next text labels | |
145 | $params['prevImg'] = ' ' . ts('< Previous'); | |
146 | $params['nextImg'] = ts('Next >') . ' '; | |
147 | ||
6a488035 TO |
148 | // set first and last text fragments |
149 | $params['firstPagePre'] = ''; | |
150 | $params['firstPageText'] = ' ' . ts('<< First'); | |
151 | $params['firstPagePost'] = ''; | |
152 | ||
153 | $params['lastPagePre'] = ''; | |
154 | $params['lastPageText'] = ts('Last >>') . ' '; | |
155 | $params['lastPagePost'] = ''; | |
156 | ||
157 | if (isset($params['pageID'])) { | |
158 | $params['currentPage'] = $this->getPageID($params['pageID'], $params); | |
159 | } | |
160 | ||
161 | $params['perPage'] = $this->getPageRowCount($params['rowCount']); | |
162 | ||
163 | return $params; | |
164 | } | |
165 | ||
166 | /** | |
167 | * Figure out the current page number based on value of | |
168 | * GET / POST variables. Hierarchy rules are followed, | |
169 | * POST over-rides a GET, a POST at the top overrides | |
170 | * a POST at the bottom (of the page) | |
171 | * | |
77855840 TO |
172 | * @param int $defaultPageId |
173 | * DefaultPageId current pageId. | |
f4aaa82a | 174 | * |
c490a46a | 175 | * @param array $params |
6a488035 | 176 | * |
a6c01b45 CW |
177 | * @return int |
178 | * new pageId to display to the user | |
6a488035 | 179 | */ |
47eea6b6 | 180 | public function getPageID($defaultPageId, &$params) { |
6a488035 TO |
181 | // POST has higher priority than GET vars |
182 | // else if a value is set that has higher priority and finally the GET var | |
183 | $currentPage = $defaultPageId; | |
184 | if (!empty($_POST)) { | |
185 | if (isset($_POST[CRM_Utils_Array::value('buttonTop', $params)]) && isset($_POST[self::PAGE_ID])) { | |
e7292422 | 186 | $currentPage = max((int ) @$_POST[self::PAGE_ID], 1); |
6a488035 TO |
187 | } |
188 | elseif (isset($_POST[$params['buttonBottom']]) && isset($_POST[self::PAGE_ID_BOTTOM])) { | |
e7292422 | 189 | $currentPage = max((int ) @$_POST[self::PAGE_ID_BOTTOM], 1); |
6a488035 TO |
190 | } |
191 | elseif (isset($_POST[self::PAGE_ID])) { | |
e7292422 | 192 | $currentPage = max((int ) @$_POST[self::PAGE_ID], 1); |
6a488035 TO |
193 | } |
194 | elseif (isset($_POST[self::PAGE_ID_BOTTOM])) { | |
b208d4d5 | 195 | $currentPage = max((int ) @$_POST[self::PAGE_ID_BOTTOM], 1); |
6a488035 TO |
196 | } |
197 | } | |
198 | elseif (isset($_GET[self::PAGE_ID])) { | |
e7292422 | 199 | $currentPage = max((int ) @$_GET[self::PAGE_ID], 1); |
6a488035 TO |
200 | } |
201 | return $currentPage; | |
202 | } | |
203 | ||
204 | /** | |
205 | * Get the number of rows to display from either a GET / POST variable | |
206 | * | |
7fa7c084 | 207 | * @param int|null $defaultPageRowCount |
77855840 | 208 | * The default value if not set. |
6a488035 | 209 | * |
a6c01b45 CW |
210 | * @return int |
211 | * the rowCount value to use | |
6a488035 | 212 | */ |
7fa7c084 | 213 | public function getPageRowCount($defaultPageRowCount = NULL) { |
6a488035 TO |
214 | // POST has higher priority than GET vars |
215 | if (isset($_POST[self::PAGE_ROWCOUNT])) { | |
e7292422 | 216 | $rowCount = max((int ) @$_POST[self::PAGE_ROWCOUNT], 1); |
6a488035 TO |
217 | } |
218 | elseif (isset($_GET[self::PAGE_ROWCOUNT])) { | |
e7292422 | 219 | $rowCount = max((int ) @$_GET[self::PAGE_ROWCOUNT], 1); |
6a488035 TO |
220 | } |
221 | else { | |
7fa7c084 | 222 | if (empty($defaultPageRowCount)) { |
9f3d3f19 | 223 | $rowCount = Civi::settings()->get('default_pager_size'); |
7fa7c084 SL |
224 | } |
225 | else { | |
226 | $rowCount = $defaultPageRowCount; | |
227 | } | |
6a488035 TO |
228 | } |
229 | return $rowCount; | |
230 | } | |
231 | ||
232 | /** | |
fe482240 | 233 | * Use the pager class to get the pageId and Offset. |
6a488035 | 234 | * |
a6c01b45 CW |
235 | * @return array |
236 | * an array of the pageID and offset | |
6a488035 | 237 | */ |
00be9182 | 238 | public function getOffsetAndRowCount() { |
6a488035 TO |
239 | $pageId = $this->getCurrentPageID(); |
240 | if (!$pageId) { | |
241 | $pageId = 1; | |
242 | } | |
243 | ||
244 | $offset = ($pageId - 1) * $this->_perPage; | |
245 | ||
be2fb01f | 246 | return [$offset, $this->_perPage]; |
6a488035 TO |
247 | } |
248 | ||
5bc392e6 EM |
249 | /** |
250 | * @return string | |
251 | */ | |
00be9182 | 252 | public function getCurrentLocation() { |
13594d55 | 253 | $path = CRM_Utils_System::currentPath(); |
fe010227 | 254 | return CRM_Utils_System::url($path, CRM_Utils_System::getLinksUrl(self::PAGE_ID, FALSE, TRUE), FALSE, NULL, FALSE) . $this->getCurrentPageID(); |
6a488035 TO |
255 | } |
256 | ||
5bc392e6 EM |
257 | /** |
258 | * @return string | |
259 | */ | |
00be9182 | 260 | public function getFirstPageLink() { |
6a488035 TO |
261 | if ($this->isFirstPage()) { |
262 | return ''; | |
263 | } | |
10824c72 | 264 | $href = $this->makeURL(self::PAGE_ID, 1); |
c5d647c1 | 265 | return $this->formatLink($href, str_replace('%d', 1, $this->_altFirst), $this->_firstPagePre . $this->_firstPageText . $this->_firstPagePost) . |
353ffa53 | 266 | $this->_spacesBefore . $this->_spacesAfter; |
6a488035 TO |
267 | } |
268 | ||
5bc392e6 EM |
269 | /** |
270 | * @return string | |
271 | */ | |
00be9182 | 272 | public function getLastPageLink() { |
6a488035 TO |
273 | if ($this->isLastPage()) { |
274 | return ''; | |
275 | } | |
10824c72 | 276 | $href = $this->makeURL(self::PAGE_ID, $this->_totalPages); |
c5d647c1 | 277 | return $this->formatLink($href, str_replace('%d', $this->_totalPages, $this->_altLast), $this->_lastPagePre . $this->_lastPageText . $this->_lastPagePost); |
6a488035 TO |
278 | } |
279 | ||
5bc392e6 EM |
280 | /** |
281 | * @return string | |
282 | */ | |
00be9182 | 283 | public function getBackPageLink() { |
6a488035 | 284 | if ($this->_currentPage > 1) { |
10824c72 | 285 | $href = $this->makeURL(self::PAGE_ID, $this->getPreviousPageID()); |
c5d647c1 | 286 | return $this->formatLink($href, $this->_altPrev, $this->_prevImg) . $this->_spacesBefore . $this->_spacesAfter; |
6a488035 TO |
287 | } |
288 | return ''; | |
289 | } | |
290 | ||
5bc392e6 EM |
291 | /** |
292 | * @return string | |
293 | */ | |
00be9182 | 294 | public function getNextPageLink() { |
6a488035 | 295 | if ($this->_currentPage < $this->_totalPages) { |
10824c72 | 296 | $href = $this->makeURL(self::PAGE_ID, $this->getNextPageID()); |
c5d647c1 | 297 | return $this->_spacesAfter . |
353ffa53 TO |
298 | $this->formatLink($href, $this->_altNext, $this->_nextImg) . |
299 | $this->_spacesBefore . $this->_spacesAfter; | |
6a488035 TO |
300 | } |
301 | return ''; | |
302 | } | |
10824c72 CW |
303 | |
304 | /** | |
fe482240 | 305 | * Build a url for pager links. |
54957108 | 306 | * |
307 | * @param string $key | |
308 | * @param string $value | |
309 | * | |
310 | * @return string | |
10824c72 | 311 | */ |
00be9182 | 312 | public function makeURL($key, $value) { |
e6add384 | 313 | $href = CRM_Utils_System::makeURL($key, TRUE); |
10824c72 CW |
314 | // CRM-12212 Remove alpha sort param |
315 | if (strpos($href, '&sortByCharacter=')) { | |
316 | $href = preg_replace('#(.*)\&sortByCharacter=[^&]*(.*)#', '\1\2', $href); | |
317 | } | |
318 | return $href . $value; | |
319 | } | |
c5d647c1 CW |
320 | |
321 | /** | |
fe482240 | 322 | * Output the html pager link. |
c5d647c1 CW |
323 | * @param string $href |
324 | * @param string $title | |
325 | * @param string $image | |
326 | * @return string | |
327 | */ | |
328 | private function formatLink($href, $title, $image) { | |
329 | return sprintf('<a class="crm-pager-link action-item crm-hover-button" href="%s" title="%s">%s</a>', $href, $title, $image); | |
330 | } | |
96025800 | 331 | |
6a488035 | 332 | } |