CRM-15789 - Move htmlAttributes helper to utils class
[civicrm-core.git] / CRM / Utils / Pager.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2014
32 * $Id$
33 *
34 */
35
36 /**
37 *
38 * This class extends the PEAR pager object by substituting standard default pager arguments
39 * We also extract the pageId from either the GET variables or the POST variable (since we
40 * use a POST to jump to a specific page). At some point we should evaluate if we want
41 * to use Pager_Jumping instead. We've changed the format to allow navigation by jumping
42 * to a page and also First, Prev CURRENT Next Last
43 *
44 */
45
46 require_once 'Pager/Sliding.php';
47
48 /**
49 * Class CRM_Utils_Pager
50 */
51 class CRM_Utils_Pager extends Pager_Sliding {
52
53 /**
54 * Constants for static parameters of the pager
55 */
56 const ROWCOUNT = 50, PAGE_ID = 'crmPID', PAGE_ID_TOP = 'crmPID', PAGE_ID_BOTTOM = 'crmPID_B', PAGE_ROWCOUNT = 'crmRowCount';
57
58 /**
59 * The output of the pager. This is a name/value array with various keys
60 * that an application could use to display the pager
61 * @var array
62 */
63 public $_response;
64
65 /**
66 * The pager constructor. Takes a few values, and then assigns a lot of defaults
67 * to the PEAR pager class
68 * We have embedded some html in this class. Need to figure out how to export this
69 * to the top level at some point in time
70 *
71 * @param array $params
72 *
73 * @internal param \total $int the total count of items to be displayed
74 * @internal param \currentPage $int the page currently being displayed
75 * @internal param \status $string the status message to be displayed. It embeds a token
76 * %%statusMessage%% that will be replaced with which items
77 * are currently being displayed
78 * @internal param \csvString $string the title of the link to be displayed for the export
79 * @internal param \perPage $int the number of items displayed per page
80 *
81 * @return \CRM_Utils_Pager the newly created and initialized pager object
82 */
83 public function __construct($params) {
84 if ($params['status'] === NULL) {
85 $params['status'] = ts('Contacts %%StatusMessage%%');
86 }
87
88 $this->initialize($params);
89
90 $this->Pager_Sliding($params);
91
92 list($offset, $limit) = $this->getOffsetAndRowCount();
93 $start = $offset + 1;
94 $end = $offset + $limit;
95 if ($end > $params['total']) {
96 $end = $params['total'];
97 }
98
99 if ($params['total'] == 0) {
100 $statusMessage = '';
101 }
102 else {
103 $statusMessage = ts('%1 - %2 of %3', array(1 => $start, 2 => $end, 3 => $params['total']));
104 }
105 $params['status'] = str_replace('%%StatusMessage%%', $statusMessage, $params['status']);
106
107 $this->_response = array(
108 'first' => $this->getFirstPageLink(),
109 'back' => $this->getBackPageLink(),
110 'next' => $this->getNextPageLink(),
111 'last' => $this->getLastPageLink(),
112 'currentPage' => $this->getCurrentPageID(),
113 'numPages' => $this->numPages(),
114 'csvString' => CRM_Utils_Array::value('csvString', $params),
115 'status' => CRM_Utils_Array::value('status', $params),
116 'buttonTop' => CRM_Utils_Array::value('buttonTop', $params),
117 'buttonBottom' => CRM_Utils_Array::value('buttonBottom', $params),
118 'currentLocation' => $this->getCurrentLocation(),
119 );
120
121 /**
122 * A page cannot have two variables with the same form name. Hence in the
123 * pager display, we have a form submission at the top with the normal
124 * page variable, but a different form element for one at the bottom
125 *
126 */
127 $this->_response['titleTop'] = ts('Page %1 of %2', array(
128 1 => '<input size="2" maxlength="3" name="' . self::PAGE_ID . '" type="text" value="' . $this->_response['currentPage'] . '" />',
129 2 => $this->_response['numPages'],
130 ));
131 $this->_response['titleBottom'] = ts('Page %1 of %2', array(
132 1 => '<input size="2" maxlength="3" name="' . self::PAGE_ID_BOTTOM . '" type="text" value="' . $this->_response['currentPage'] . '" />',
133 2 => $this->_response['numPages'],
134 ));
135 }
136
137 /**
138 * Helper function to assign remaining pager options as good default
139 * values
140 *
141 * @param array $params
142 * The set of options needed to initialize the parent.
143 * constructor
144 *
145 *
146 * @return void
147 */
148 public function initialize(&$params) {
149 /* set the mode for the pager to Sliding */
150
151 $params['mode'] = 'Sliding';
152
153 /* also set the urlVar to be a crm specific get variable */
154
155 $params['urlVar'] = self::PAGE_ID;
156
157 /* set this to a small value, since we dont use this functionality */
158
159 $params['delta'] = 1;
160
161 $params['totalItems'] = $params['total'];
162 $params['append'] = TRUE;
163 $params['separator'] = '';
164 $params['spacesBeforeSeparator'] = 1;
165 $params['spacesAfterSeparator'] = 1;
166 $params['extraVars'] = array('force' => 1);
167 $params['excludeVars'] = array('reset', 'snippet', 'section');
168
169 // set previous and next text labels
170 $params['prevImg'] = ' ' . ts('&lt; Previous');
171 $params['nextImg'] = ts('Next &gt;') . ' ';
172
173 // set first and last text fragments
174 $params['firstPagePre'] = '';
175 $params['firstPageText'] = ' ' . ts('&lt;&lt; First');
176 $params['firstPagePost'] = '';
177
178 $params['lastPagePre'] = '';
179 $params['lastPageText'] = ts('Last &gt;&gt;') . ' ';
180 $params['lastPagePost'] = '';
181
182 if (isset($params['pageID'])) {
183 $params['currentPage'] = $this->getPageID($params['pageID'], $params);
184 }
185
186 $params['perPage'] = $this->getPageRowCount($params['rowCount']);
187
188 return $params;
189 }
190
191 /**
192 * Figure out the current page number based on value of
193 * GET / POST variables. Hierarchy rules are followed,
194 * POST over-rides a GET, a POST at the top overrides
195 * a POST at the bottom (of the page)
196 *
197 * @param int $defaultPageId
198 * DefaultPageId current pageId.
199 *
200 * @param array $params
201 *
202 * @return int
203 * new pageId to display to the user
204 */
205 public function getPageID($defaultPageId = 1, &$params) {
206 // POST has higher priority than GET vars
207 // else if a value is set that has higher priority and finally the GET var
208 $currentPage = $defaultPageId;
209 if (!empty($_POST)) {
210 if (isset($_POST[CRM_Utils_Array::value('buttonTop', $params)]) && isset($_POST[self::PAGE_ID])) {
211 $currentPage = max((int ) @$_POST[self::PAGE_ID], 1);
212 }
213 elseif (isset($_POST[$params['buttonBottom']]) && isset($_POST[self::PAGE_ID_BOTTOM])) {
214 $currentPage = max((int ) @$_POST[self::PAGE_ID_BOTTOM], 1);
215 }
216 elseif (isset($_POST[self::PAGE_ID])) {
217 $currentPage = max((int ) @$_POST[self::PAGE_ID], 1);
218 }
219 elseif (isset($_POST[self::PAGE_ID_BOTTOM])) {
220 $currentPage = max((int ) @$_POST[self::PAGE_ID_BOTTOM]);
221 }
222 }
223 elseif (isset($_GET[self::PAGE_ID])) {
224 $currentPage = max((int ) @$_GET[self::PAGE_ID], 1);
225 }
226 return $currentPage;
227 }
228
229 /**
230 * Get the number of rows to display from either a GET / POST variable
231 *
232 * @param int $defaultPageRowCount
233 * The default value if not set.
234 *
235 * @return int
236 * the rowCount value to use
237 */
238 public function getPageRowCount($defaultPageRowCount = self::ROWCOUNT) {
239 // POST has higher priority than GET vars
240 if (isset($_POST[self::PAGE_ROWCOUNT])) {
241 $rowCount = max((int ) @$_POST[self::PAGE_ROWCOUNT], 1);
242 }
243 elseif (isset($_GET[self::PAGE_ROWCOUNT])) {
244 $rowCount = max((int ) @$_GET[self::PAGE_ROWCOUNT], 1);
245 }
246 else {
247 $rowCount = $defaultPageRowCount;
248 }
249 return $rowCount;
250 }
251
252 /**
253 * Use the pager class to get the pageId and Offset
254 *
255 * @return array
256 * an array of the pageID and offset
257 */
258 public function getOffsetAndRowCount() {
259 $pageId = $this->getCurrentPageID();
260 if (!$pageId) {
261 $pageId = 1;
262 }
263
264 $offset = ($pageId - 1) * $this->_perPage;
265
266 return array($offset, $this->_perPage);
267 }
268
269 /**
270 * @return string
271 */
272 public function getCurrentLocation() {
273 $config = CRM_Core_Config::singleton();
274 $path = CRM_Utils_Array::value($config->userFrameworkURLVar, $_GET);
275 return CRM_Utils_System::url($path, CRM_Utils_System::getLinksUrl(self::PAGE_ID, FALSE, TRUE), FALSE, NULL, FALSE) . $this->getCurrentPageID();
276 }
277
278 /**
279 * @return string
280 */
281 public function getFirstPageLink() {
282 if ($this->isFirstPage()) {
283 return '';
284 }
285 $href = $this->makeURL(self::PAGE_ID, 1);
286 return $this->formatLink($href, str_replace('%d', 1, $this->_altFirst), $this->_firstPagePre . $this->_firstPageText . $this->_firstPagePost) .
287 $this->_spacesBefore . $this->_spacesAfter;
288 }
289
290 /**
291 * @return string
292 */
293 public function getLastPageLink() {
294 if ($this->isLastPage()) {
295 return '';
296 }
297 $href = $this->makeURL(self::PAGE_ID, $this->_totalPages);
298 return $this->formatLink($href, str_replace('%d', $this->_totalPages, $this->_altLast), $this->_lastPagePre . $this->_lastPageText . $this->_lastPagePost);
299 }
300
301 /**
302 * @return string
303 */
304 public function getBackPageLink() {
305 if ($this->_currentPage > 1) {
306 $href = $this->makeURL(self::PAGE_ID, $this->getPreviousPageID());
307 return $this->formatLink($href, $this->_altPrev, $this->_prevImg) . $this->_spacesBefore . $this->_spacesAfter;
308 }
309 return '';
310 }
311
312 /**
313 * @return string
314 */
315 public function getNextPageLink() {
316 if ($this->_currentPage < $this->_totalPages) {
317 $href = $this->makeURL(self::PAGE_ID, $this->getNextPageID());
318 return $this->_spacesAfter .
319 $this->formatLink($href, $this->_altNext, $this->_nextImg) .
320 $this->_spacesBefore . $this->_spacesAfter;
321 }
322 return '';
323 }
324
325 /**
326 * Build a url for pager links
327 */
328 public function makeURL($key, $value) {
329 $href = CRM_Utils_System::makeURL($key, TRUE);
330 // CRM-12212 Remove alpha sort param
331 if (strpos($href, '&amp;sortByCharacter=')) {
332 $href = preg_replace('#(.*)\&amp;sortByCharacter=[^&]*(.*)#', '\1\2', $href);
333 }
334 return $href . $value;
335 }
336
337 /**
338 * Output the html pager link
339 * @param string $href
340 * @param string $title
341 * @param string $image
342 * @return string
343 */
344 private function formatLink($href, $title, $image) {
345 return sprintf('<a class="crm-pager-link action-item crm-hover-button" href="%s" title="%s">%s</a>', $href, $title, $image);
346 }
347
348 }