Merge pull request #3580 from monishdeb/CRM-14701
[civicrm-core.git] / CRM / Utils / Pager.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.4 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
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-2013
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 class CRM_Utils_Pager extends Pager_Sliding {
48
49 /**
50 * constants for static parameters of the pager
51 */
52 CONST ROWCOUNT = 50, PAGE_ID = 'crmPID', PAGE_ID_TOP = 'crmPID', PAGE_ID_BOTTOM = 'crmPID_B', PAGE_ROWCOUNT = 'crmRowCount';
53
54 /**
55 * the output of the pager. This is a name/value array with various keys
56 * that an application could use to display the pager
57 * @var array
58 */
59 public $_response;
60
61 /**
62 * The pager constructor. Takes a few values, and then assigns a lot of defaults
63 * to the PEAR pager class
64 * We have embedded some html in this class. Need to figure out how to export this
65 * to the top level at some point in time
66 *
67 * @param int total the total count of items to be displayed
68 * @param int currentPage the page currently being displayed
69 * @param string status the status message to be displayed. It embeds a token
70 * %%statusMessage%% that will be replaced with which items
71 * are currently being displayed
72 * @param string csvString the title of the link to be displayed for the export
73 * @param int perPage the number of items displayed per page
74 *
75 * @return object the newly created and initialized pager object
76 *
77 * @access public
78 *
79 */
80 function __construct($params) {
81 if ($params['status'] === NULL) {
82 $params['status'] = ts('Contacts %%StatusMessage%%');
83 }
84
85 $this->initialize($params);
86
87 $this->Pager_Sliding($params);
88
89 list($offset, $limit) = $this->getOffsetAndRowCount();
90 $start = $offset + 1;
91 $end = $offset + $limit;
92 if ($end > $params['total']) {
93 $end = $params['total'];
94 }
95
96 if ($params['total'] == 0) {
97 $statusMessage = '';
98 }
99 else {
100 $statusMessage = ts('%1 - %2 of %3', array(1 => $start, 2 => $end, 3 => $params['total']));
101 }
102 $params['status'] = str_replace('%%StatusMessage%%', $statusMessage, $params['status']);
103
104 $this->_response = array(
105 'first' => $this->getFirstPageLink(),
106 'back' => $this->getBackPageLink(),
107 'next' => $this->getNextPageLink(),
108 'last' => $this->getLastPageLink(),
109 'currentPage' => $this->getCurrentPageID(),
110 'numPages' => $this->numPages(),
111 'csvString' => CRM_Utils_Array::value('csvString', $params),
112 'status' => CRM_Utils_Array::value('status', $params),
113 'buttonTop' => CRM_Utils_Array::value('buttonTop', $params),
114 'buttonBottom' => CRM_Utils_Array::value('buttonBottom', $params),
115 'twentyfive' => $this->getPerPageLink(25),
116 'fifty' => $this->getPerPageLink(50),
117 'onehundred' => $this->getPerPageLink(100),
118 );
119
120 /**
121 * A page cannot have two variables with the same form name. Hence in the
122 * pager display, we have a form submission at the top with the normal
123 * page variable, but a different form element for one at the bottom
124 *
125 */
126 $this->_response['titleTop'] = ts('Page %1 of %2', array(1 => '<input size="2" maxlength="3" name="' . self::PAGE_ID . '" type="text" value="' . $this->_response['currentPage'] . '" />', 2 => $this->_response['numPages']));
127 $this->_response['titleBottom'] = ts('Page %1 of %2', array(1 => '<input size="2" maxlength="3" name="' . self::PAGE_ID_BOTTOM . '" type="text" value="' . $this->_response['currentPage'] . '" />', 2 => $this->_response['numPages']));
128 }
129
130 /**
131 * helper function to assign remaining pager options as good default
132 * values
133 *
134 * @param array $params the set of options needed to initialize the parent
135 * constructor
136 *
137 * @access public
138 *
139 * @return void
140 *
141 */
142 function initialize(&$params) {
143 /* set the mode for the pager to Sliding */
144
145 $params['mode'] = 'Sliding';
146
147 /* also set the urlVar to be a crm specific get variable */
148
149 $params['urlVar'] = self::PAGE_ID;
150
151 /* set this to a small value, since we dont use this functionality */
152
153 $params['delta'] = 1;
154
155 $params['totalItems'] = $params['total'];
156 $params['append'] = TRUE;
157 $params['separator'] = '';
158 $params['spacesBeforeSeparator'] = 1;
159 $params['spacesAfterSeparator'] = 1;
160 $params['extraVars'] = array('force' => 1);
161 $params['excludeVars'] = array('reset', 'snippet', 'section');
162
163 // set previous and next text labels
164 $params['prevImg'] = ' ' . ts('&lt; Previous');
165 $params['nextImg'] = ts('Next &gt;') . ' ';
166
167
168 // set first and last text fragments
169 $params['firstPagePre'] = '';
170 $params['firstPageText'] = ' ' . ts('&lt;&lt; First');
171 $params['firstPagePost'] = '';
172
173 $params['lastPagePre'] = '';
174 $params['lastPageText'] = ts('Last &gt;&gt;') . ' ';
175 $params['lastPagePost'] = '';
176
177 if (isset($params['pageID'])) {
178 $params['currentPage'] = $this->getPageID($params['pageID'], $params);
179 }
180
181 $params['perPage'] = $this->getPageRowCount($params['rowCount']);
182
183 return $params;
184 }
185
186 /**
187 * Figure out the current page number based on value of
188 * GET / POST variables. Hierarchy rules are followed,
189 * POST over-rides a GET, a POST at the top overrides
190 * a POST at the bottom (of the page)
191 *
192 * @param int defaultPageId current pageId
193 *
194 * @return int new pageId to display to the user
195 * @access public
196 *
197 */
198 function getPageID($defaultPageId = 1, &$params) {
199 // POST has higher priority than GET vars
200 // else if a value is set that has higher priority and finally the GET var
201 $currentPage = $defaultPageId;
202 if (!empty($_POST)) {
203 if (isset($_POST[CRM_Utils_Array::value('buttonTop', $params)]) && isset($_POST[self::PAGE_ID])) {
204 $currentPage = max((int )@$_POST[self::PAGE_ID], 1);
205 }
206 elseif (isset($_POST[$params['buttonBottom']]) && isset($_POST[self::PAGE_ID_BOTTOM])) {
207 $currentPage = max((int )@$_POST[self::PAGE_ID_BOTTOM], 1);
208 }
209 elseif (isset($_POST[self::PAGE_ID])) {
210 $currentPage = max((int )@$_POST[self::PAGE_ID], 1);
211 }
212 elseif (isset($_POST[self::PAGE_ID_BOTTOM])) {
213 $currentPage = max((int )@$_POST[self::PAGE_ID_BOTTOM]);
214 }
215 }
216 elseif (isset($_GET[self::PAGE_ID])) {
217 $currentPage = max((int )@$_GET[self::PAGE_ID], 1);
218 }
219 return $currentPage;
220 }
221
222 /**
223 * Get the number of rows to display from either a GET / POST variable
224 *
225 * @param int $defaultPageRowCount the default value if not set
226 *
227 * @return int the rowCount value to use
228 * @access public
229 *
230 */
231 function getPageRowCount($defaultPageRowCount = self::ROWCOUNT) {
232 // POST has higher priority than GET vars
233 if (isset($_POST[self::PAGE_ROWCOUNT])) {
234 $rowCount = max((int )@$_POST[self::PAGE_ROWCOUNT], 1);
235 }
236 elseif (isset($_GET[self::PAGE_ROWCOUNT])) {
237 $rowCount = max((int )@$_GET[self::PAGE_ROWCOUNT], 1);
238 }
239 else {
240 $rowCount = $defaultPageRowCount;
241 }
242 return $rowCount;
243 }
244
245 /**
246 * Use the pager class to get the pageId and Offset
247 *
248 * @param void
249 *
250 * @return array: an array of the pageID and offset
251 *
252 * @access public
253 *
254 */
255 function getOffsetAndRowCount() {
256 $pageId = $this->getCurrentPageID();
257 if (!$pageId) {
258 $pageId = 1;
259 }
260
261 $offset = ($pageId - 1) * $this->_perPage;
262
263 return array($offset, $this->_perPage);
264 }
265
266 /**
267 * given a number create a link that will display the number of
268 * rows as specified by that link
269 *
270 * @param int $perPage the number of rows
271 *
272 * @return string the link
273 * @access void
274 */
275 function getPerPageLink($perPage) {
276 if ($perPage != $this->_perPage) {
277 $href = $this->makeURL(self::PAGE_ROWCOUNT, $perPage);
278 $link = sprintf('<a href="%s" %s>%s</a>',
279 $href,
280 $this->_classString,
281 $perPage
282 ) . $this->_spacesBefore . $this->_spacesAfter;
283 }
284 else {
285 $link = $this->_spacesBefore . $perPage . $this->_spacesAfter;
286 }
287
288 return $link;
289 }
290
291 function getFirstPageLink() {
292 if ($this->isFirstPage()) {
293 return '';
294 }
295
296 $href = $this->makeURL(self::PAGE_ID, 1);
297 return sprintf('<a href="%s" title="%s">%s</a>',
298 $href,
299 str_replace('%d', 1, $this->_altFirst),
300 $this->_firstPagePre . $this->_firstPageText . $this->_firstPagePost
301 ) . $this->_spacesBefore . $this->_spacesAfter;
302 }
303
304 function getLastPageLink() {
305 if ($this->isLastPage()) {
306 return '';
307 }
308
309 $href = $this->makeURL(self::PAGE_ID, $this->_totalPages);
310 return sprintf('<a href="%s" title="%s">%s</a>',
311 $href,
312 str_replace('%d', $this->_totalPages, $this->_altLast),
313 $this->_lastPagePre . $this->_lastPageText . $this->_lastPagePost
314 );
315 }
316
317 function getBackPageLink() {
318 if ($this->_currentPage > 1) {
319 $href = $this->makeURL(self::PAGE_ID, $this->getPreviousPageID());
320 return sprintf('<a href="%s" title="%s">%s</a>',
321 $href,
322 $this->_altPrev, $this->_prevImg
323 ) . $this->_spacesBefore . $this->_spacesAfter;
324 }
325 return '';
326 }
327
328 function getNextPageLink() {
329 if ($this->_currentPage < $this->_totalPages) {
330 $href = $this->makeURL(self::PAGE_ID, $this->getNextPageID());
331 return $this->_spacesAfter . sprintf('<a href="%s" title="%s">%s</a>',
332 $href,
333 $this->_altNext, $this->_nextImg
334 ) . $this->_spacesBefore . $this->_spacesAfter;
335 }
336 return '';
337 }
338
339 /**
340 * Build a url for pager links
341 */
342 function makeURL($key, $value) {
343 $href = CRM_Utils_System::makeURL($key);
344 // CRM-12212 Remove alpha sort param
345 if (strpos($href, '&amp;sortByCharacter=')) {
346 $href = preg_replace('#(.*)\&amp;sortByCharacter=[^&]*(.*)#', '\1\2', $href);
347 }
348 return $href . $value;
349 }
350 }
351