Mercurial > hg > Members > shoshi > webvirt
comparison cake/libs/view/helpers/paginator.php @ 0:261e66bd5a0c
hg init
author | Shoshi TAMAKI <shoshi@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Sun, 24 Jul 2011 21:08:31 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:261e66bd5a0c |
---|---|
1 <?php | |
2 /** | |
3 * Pagination Helper class file. | |
4 * | |
5 * Generates pagination links | |
6 * | |
7 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) | |
8 * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) | |
9 * | |
10 * Licensed under The MIT License | |
11 * Redistributions of files must retain the above copyright notice. | |
12 * | |
13 * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) | |
14 * @link http://cakephp.org CakePHP(tm) Project | |
15 * @package cake | |
16 * @subpackage cake.cake.libs.view.helpers | |
17 * @since CakePHP(tm) v 1.2.0 | |
18 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) | |
19 */ | |
20 | |
21 /** | |
22 * Pagination Helper class for easy generation of pagination links. | |
23 * | |
24 * PaginationHelper encloses all methods needed when working with pagination. | |
25 * | |
26 * @package cake | |
27 * @subpackage cake.cake.libs.view.helpers | |
28 * @link http://book.cakephp.org/view/1458/Paginator | |
29 */ | |
30 class PaginatorHelper extends AppHelper { | |
31 | |
32 /** | |
33 * Helper dependencies | |
34 * | |
35 * @var array | |
36 */ | |
37 var $helpers = array('Html'); | |
38 | |
39 /** | |
40 * Holds the default model for paged recordsets | |
41 * | |
42 * @var string | |
43 */ | |
44 var $__defaultModel = null; | |
45 | |
46 /** | |
47 * The class used for 'Ajax' pagination links. | |
48 * | |
49 * @var string | |
50 */ | |
51 var $_ajaxHelperClass = 'Js'; | |
52 | |
53 /** | |
54 * Holds the default options for pagination links | |
55 * | |
56 * The values that may be specified are: | |
57 * | |
58 * - `$options['format']` Format of the counter. Supported formats are 'range' and 'pages' | |
59 * and custom (default). In the default mode the supplied string is parsed and constants are replaced | |
60 * by their actual values. | |
61 * Constants: %page%, %pages%, %current%, %count%, %start%, %end% . | |
62 * - `$options['separator']` The separator of the actual page and number of pages (default: ' of '). | |
63 * - `$options['url']` Url of the action. See Router::url() | |
64 * - `$options['url']['sort']` the key that the recordset is sorted. | |
65 * - `$options['url']['direction']` Direction of the sorting (default: 'asc'). | |
66 * - `$options['url']['page']` Page # to display. | |
67 * - `$options['model']` The name of the model. | |
68 * - `$options['escape']` Defines if the title field for the link should be escaped (default: true). | |
69 * - `$options['update']` DOM id of the element updated with the results of the AJAX call. | |
70 * If this key isn't specified Paginator will use plain HTML links. | |
71 * - `$options['indicator']` DOM id of the element that will be shown when doing AJAX requests. **Only supported by | |
72 * AjaxHelper** | |
73 * | |
74 * @var array | |
75 * @access public | |
76 */ | |
77 var $options = array(); | |
78 | |
79 /** | |
80 * Constructor for the helper. Sets up the helper that is used for creating 'AJAX' links. | |
81 * | |
82 * Use `var $helpers = array('Paginator' => array('ajax' => 'CustomHelper'));` to set a custom Helper | |
83 * or choose a non JsHelper Helper. If you want to use a specific library with JsHelper declare JsHelper and its | |
84 * adapter before including PaginatorHelper in your helpers array. | |
85 * | |
86 * The chosen custom helper must implement a `link()` method. | |
87 * | |
88 * @return void | |
89 */ | |
90 function __construct($config = array()) { | |
91 parent::__construct($config); | |
92 $ajaxProvider = isset($config['ajax']) ? $config['ajax'] : 'Js'; | |
93 $this->helpers[] = $ajaxProvider; | |
94 $this->_ajaxHelperClass = $ajaxProvider; | |
95 | |
96 App::import('Helper', $ajaxProvider); | |
97 $classname = $ajaxProvider . 'Helper'; | |
98 if (!is_callable(array($classname, 'link'))) { | |
99 trigger_error(sprintf(__('%s does not implement a link() method, it is incompatible with PaginatorHelper', true), $classname), E_USER_WARNING); | |
100 } | |
101 } | |
102 | |
103 /** | |
104 * Before render callback. Overridden to merge passed args with url options. | |
105 * | |
106 * @return void | |
107 * @access public | |
108 */ | |
109 function beforeRender() { | |
110 $this->options['url'] = array_merge($this->params['pass'], $this->params['named']); | |
111 | |
112 parent::beforeRender(); | |
113 } | |
114 | |
115 /** | |
116 * Gets the current paging parameters from the resultset for the given model | |
117 * | |
118 * @param string $model Optional model name. Uses the default if none is specified. | |
119 * @return array The array of paging parameters for the paginated resultset. | |
120 * @access public | |
121 */ | |
122 function params($model = null) { | |
123 if (empty($model)) { | |
124 $model = $this->defaultModel(); | |
125 } | |
126 if (!isset($this->params['paging']) || empty($this->params['paging'][$model])) { | |
127 return null; | |
128 } | |
129 return $this->params['paging'][$model]; | |
130 } | |
131 | |
132 /** | |
133 * Sets default options for all pagination links | |
134 * | |
135 * @param mixed $options Default options for pagination links. If a string is supplied - it | |
136 * is used as the DOM id element to update. See PaginatorHelper::$options for list of keys. | |
137 * @return void | |
138 * @access public | |
139 */ | |
140 function options($options = array()) { | |
141 if (is_string($options)) { | |
142 $options = array('update' => $options); | |
143 } | |
144 | |
145 if (!empty($options['paging'])) { | |
146 if (!isset($this->params['paging'])) { | |
147 $this->params['paging'] = array(); | |
148 } | |
149 $this->params['paging'] = array_merge($this->params['paging'], $options['paging']); | |
150 unset($options['paging']); | |
151 } | |
152 $model = $this->defaultModel(); | |
153 | |
154 if (!empty($options[$model])) { | |
155 if (!isset($this->params['paging'][$model])) { | |
156 $this->params['paging'][$model] = array(); | |
157 } | |
158 $this->params['paging'][$model] = array_merge( | |
159 $this->params['paging'][$model], $options[$model] | |
160 ); | |
161 unset($options[$model]); | |
162 } | |
163 $this->options = array_filter(array_merge($this->options, $options)); | |
164 } | |
165 | |
166 /** | |
167 * Gets the current page of the recordset for the given model | |
168 * | |
169 * @param string $model Optional model name. Uses the default if none is specified. | |
170 * @return string The current page number of the recordset. | |
171 * @access public | |
172 */ | |
173 function current($model = null) { | |
174 $params = $this->params($model); | |
175 | |
176 if (isset($params['page'])) { | |
177 return $params['page']; | |
178 } | |
179 return 1; | |
180 } | |
181 | |
182 /** | |
183 * Gets the current key by which the recordset is sorted | |
184 * | |
185 * @param string $model Optional model name. Uses the default if none is specified. | |
186 * @param mixed $options Options for pagination links. See #options for list of keys. | |
187 * @return string The name of the key by which the recordset is being sorted, or | |
188 * null if the results are not currently sorted. | |
189 * @access public | |
190 */ | |
191 function sortKey($model = null, $options = array()) { | |
192 if (empty($options)) { | |
193 $params = $this->params($model); | |
194 $options = array_merge($params['defaults'], $params['options']); | |
195 } | |
196 | |
197 if (isset($options['sort']) && !empty($options['sort'])) { | |
198 return $options['sort']; | |
199 } elseif (isset($options['order']) && is_array($options['order'])) { | |
200 return key($options['order']); | |
201 } elseif (isset($options['order']) && is_string($options['order'])) { | |
202 return $options['order']; | |
203 } | |
204 return null; | |
205 } | |
206 | |
207 /** | |
208 * Gets the current direction the recordset is sorted | |
209 * | |
210 * @param string $model Optional model name. Uses the default if none is specified. | |
211 * @param mixed $options Options for pagination links. See #options for list of keys. | |
212 * @return string The direction by which the recordset is being sorted, or | |
213 * null if the results are not currently sorted. | |
214 * @access public | |
215 */ | |
216 function sortDir($model = null, $options = array()) { | |
217 $dir = null; | |
218 | |
219 if (empty($options)) { | |
220 $params = $this->params($model); | |
221 $options = array_merge($params['defaults'], $params['options']); | |
222 } | |
223 | |
224 if (isset($options['direction'])) { | |
225 $dir = strtolower($options['direction']); | |
226 } elseif (isset($options['order']) && is_array($options['order'])) { | |
227 $dir = strtolower(current($options['order'])); | |
228 } | |
229 | |
230 if ($dir == 'desc') { | |
231 return 'desc'; | |
232 } | |
233 return 'asc'; | |
234 } | |
235 | |
236 /** | |
237 * Generates a "previous" link for a set of paged records | |
238 * | |
239 * ### Options: | |
240 * | |
241 * - `tag` The tag wrapping tag you want to use, defaults to 'span' | |
242 * - `escape` Whether you want the contents html entity encoded, defaults to true | |
243 * - `model` The model to use, defaults to PaginatorHelper::defaultModel() | |
244 * | |
245 * @param string $title Title for the link. Defaults to '<< Previous'. | |
246 * @param mixed $options Options for pagination link. See #options for list of keys. | |
247 * @param string $disabledTitle Title when the link is disabled. | |
248 * @param mixed $disabledOptions Options for the disabled pagination link. See #options for list of keys. | |
249 * @return string A "previous" link or $disabledTitle text if the link is disabled. | |
250 * @access public | |
251 */ | |
252 function prev($title = '<< Previous', $options = array(), $disabledTitle = null, $disabledOptions = array()) { | |
253 return $this->__pagingLink('Prev', $title, $options, $disabledTitle, $disabledOptions); | |
254 } | |
255 | |
256 /** | |
257 * Generates a "next" link for a set of paged records | |
258 * | |
259 * ### Options: | |
260 * | |
261 * - `tag` The tag wrapping tag you want to use, defaults to 'span' | |
262 * - `escape` Whether you want the contents html entity encoded, defaults to true | |
263 * - `model` The model to use, defaults to PaginatorHelper::defaultModel() | |
264 * | |
265 * @param string $title Title for the link. Defaults to 'Next >>'. | |
266 * @param mixed $options Options for pagination link. See above for list of keys. | |
267 * @param string $disabledTitle Title when the link is disabled. | |
268 * @param mixed $disabledOptions Options for the disabled pagination link. See above for list of keys. | |
269 * @return string A "next" link or or $disabledTitle text if the link is disabled. | |
270 * @access public | |
271 */ | |
272 function next($title = 'Next >>', $options = array(), $disabledTitle = null, $disabledOptions = array()) { | |
273 return $this->__pagingLink('Next', $title, $options, $disabledTitle, $disabledOptions); | |
274 } | |
275 | |
276 /** | |
277 * Generates a sorting link. Sets named parameters for the sort and direction. Handles | |
278 * direction switching automatically. | |
279 * | |
280 * ### Options: | |
281 * | |
282 * - `escape` Whether you want the contents html entity encoded, defaults to true | |
283 * - `model` The model to use, defaults to PaginatorHelper::defaultModel() | |
284 * | |
285 * @param string $title Title for the link. | |
286 * @param string $key The name of the key that the recordset should be sorted. If $key is null | |
287 * $title will be used for the key, and a title will be generated by inflection. | |
288 * @param array $options Options for sorting link. See above for list of keys. | |
289 * @return string A link sorting default by 'asc'. If the resultset is sorted 'asc' by the specified | |
290 * key the returned link will sort by 'desc'. | |
291 * @access public | |
292 */ | |
293 function sort($title, $key = null, $options = array()) { | |
294 $options = array_merge(array('url' => array(), 'model' => null), $options); | |
295 $url = $options['url']; | |
296 unset($options['url']); | |
297 | |
298 if (empty($key)) { | |
299 $key = $title; | |
300 $title = __(Inflector::humanize(preg_replace('/_id$/', '', $title)), true); | |
301 } | |
302 $dir = isset($options['direction']) ? $options['direction'] : 'asc'; | |
303 unset($options['direction']); | |
304 | |
305 $sortKey = $this->sortKey($options['model']); | |
306 $defaultModel = $this->defaultModel(); | |
307 $isSorted = ( | |
308 $sortKey === $key || | |
309 $sortKey === $defaultModel . '.' . $key || | |
310 $key === $defaultModel . '.' . $sortKey | |
311 ); | |
312 | |
313 if ($isSorted) { | |
314 $dir = $this->sortDir($options['model']) === 'asc' ? 'desc' : 'asc'; | |
315 $class = $dir === 'asc' ? 'desc' : 'asc'; | |
316 if (!empty($options['class'])) { | |
317 $options['class'] .= ' ' . $class; | |
318 } else { | |
319 $options['class'] = $class; | |
320 } | |
321 } | |
322 if (is_array($title) && array_key_exists($dir, $title)) { | |
323 $title = $title[$dir]; | |
324 } | |
325 | |
326 $url = array_merge(array('sort' => $key, 'direction' => $dir), $url, array('order' => null)); | |
327 return $this->link($title, $url, $options); | |
328 } | |
329 | |
330 /** | |
331 * Generates a plain or Ajax link with pagination parameters | |
332 * | |
333 * ### Options | |
334 * | |
335 * - `update` The Id of the DOM element you wish to update. Creates Ajax enabled links | |
336 * with the AjaxHelper. | |
337 * - `escape` Whether you want the contents html entity encoded, defaults to true | |
338 * - `model` The model to use, defaults to PaginatorHelper::defaultModel() | |
339 * | |
340 * @param string $title Title for the link. | |
341 * @param mixed $url Url for the action. See Router::url() | |
342 * @param array $options Options for the link. See #options for list of keys. | |
343 * @return string A link with pagination parameters. | |
344 * @access public | |
345 */ | |
346 function link($title, $url = array(), $options = array()) { | |
347 $options = array_merge(array('model' => null, 'escape' => true), $options); | |
348 $model = $options['model']; | |
349 unset($options['model']); | |
350 | |
351 if (!empty($this->options)) { | |
352 $options = array_merge($this->options, $options); | |
353 } | |
354 if (isset($options['url'])) { | |
355 $url = array_merge((array)$options['url'], (array)$url); | |
356 unset($options['url']); | |
357 } | |
358 $url = $this->url($url, true, $model); | |
359 | |
360 $obj = isset($options['update']) ? $this->_ajaxHelperClass : 'Html'; | |
361 $url = array_merge(array('page' => $this->current($model)), $url); | |
362 $url = array_merge(Set::filter($url, true), array_intersect_key($url, array('plugin' => true))); | |
363 return $this->{$obj}->link($title, $url, $options); | |
364 } | |
365 | |
366 /** | |
367 * Merges passed URL options with current pagination state to generate a pagination URL. | |
368 * | |
369 * @param array $options Pagination/URL options array | |
370 * @param boolean $asArray Return the url as an array, or a URI string | |
371 * @param string $model Which model to paginate on | |
372 * @return mixed By default, returns a full pagination URL string for use in non-standard contexts (i.e. JavaScript) | |
373 * @access public | |
374 */ | |
375 function url($options = array(), $asArray = false, $model = null) { | |
376 $paging = $this->params($model); | |
377 $url = array_merge(array_filter(Set::diff(array_merge( | |
378 $paging['defaults'], $paging['options']), $paging['defaults'])), $options | |
379 ); | |
380 | |
381 if (isset($url['order'])) { | |
382 $sort = $direction = null; | |
383 if (is_array($url['order'])) { | |
384 list($sort, $direction) = array($this->sortKey($model, $url), current($url['order'])); | |
385 } | |
386 unset($url['order']); | |
387 $url = array_merge($url, compact('sort', 'direction')); | |
388 } | |
389 | |
390 if ($asArray) { | |
391 return $url; | |
392 } | |
393 return parent::url($url); | |
394 } | |
395 | |
396 /** | |
397 * Protected method for generating prev/next links | |
398 * | |
399 * @access protected | |
400 */ | |
401 function __pagingLink($which, $title = null, $options = array(), $disabledTitle = null, $disabledOptions = array()) { | |
402 $check = 'has' . $which; | |
403 $_defaults = array( | |
404 'url' => array(), 'step' => 1, 'escape' => true, | |
405 'model' => null, 'tag' => 'span', 'class' => strtolower($which) | |
406 ); | |
407 $options = array_merge($_defaults, (array)$options); | |
408 $paging = $this->params($options['model']); | |
409 if (empty($disabledOptions)) { | |
410 $disabledOptions = $options; | |
411 } | |
412 | |
413 if (!$this->{$check}($options['model']) && (!empty($disabledTitle) || !empty($disabledOptions))) { | |
414 if (!empty($disabledTitle) && $disabledTitle !== true) { | |
415 $title = $disabledTitle; | |
416 } | |
417 $options = array_merge($_defaults, (array)$disabledOptions); | |
418 } elseif (!$this->{$check}($options['model'])) { | |
419 return null; | |
420 } | |
421 | |
422 foreach (array_keys($_defaults) as $key) { | |
423 ${$key} = $options[$key]; | |
424 unset($options[$key]); | |
425 } | |
426 $url = array_merge(array('page' => $paging['page'] + ($which == 'Prev' ? $step * -1 : $step)), $url); | |
427 | |
428 if ($this->{$check}($model)) { | |
429 return $this->Html->tag($tag, $this->link($title, $url, array_merge($options, compact('escape', 'class')))); | |
430 } else { | |
431 return $this->Html->tag($tag, $title, array_merge($options, compact('escape', 'class'))); | |
432 } | |
433 } | |
434 | |
435 /** | |
436 * Returns true if the given result set is not at the first page | |
437 * | |
438 * @param string $model Optional model name. Uses the default if none is specified. | |
439 * @return boolean True if the result set is not at the first page. | |
440 * @access public | |
441 */ | |
442 function hasPrev($model = null) { | |
443 return $this->__hasPage($model, 'prev'); | |
444 } | |
445 | |
446 /** | |
447 * Returns true if the given result set is not at the last page | |
448 * | |
449 * @param string $model Optional model name. Uses the default if none is specified. | |
450 * @return boolean True if the result set is not at the last page. | |
451 * @access public | |
452 */ | |
453 function hasNext($model = null) { | |
454 return $this->__hasPage($model, 'next'); | |
455 } | |
456 | |
457 /** | |
458 * Returns true if the given result set has the page number given by $page | |
459 * | |
460 * @param string $model Optional model name. Uses the default if none is specified. | |
461 * @param int $page The page number - if not set defaults to 1. | |
462 * @return boolean True if the given result set has the specified page number. | |
463 * @access public | |
464 */ | |
465 function hasPage($model = null, $page = 1) { | |
466 if (is_numeric($model)) { | |
467 $page = $model; | |
468 $model = null; | |
469 } | |
470 $paging = $this->params($model); | |
471 return $page <= $paging['pageCount']; | |
472 } | |
473 | |
474 /** | |
475 * Does $model have $page in its range? | |
476 * | |
477 * @param string $model Model name to get parameters for. | |
478 * @param integer $page Page number you are checking. | |
479 * @return boolean Whether model has $page | |
480 * @access protected | |
481 */ | |
482 function __hasPage($model, $page) { | |
483 $params = $this->params($model); | |
484 if (!empty($params)) { | |
485 if ($params["{$page}Page"] == true) { | |
486 return true; | |
487 } | |
488 } | |
489 return false; | |
490 } | |
491 | |
492 /** | |
493 * Gets the default model of the paged sets | |
494 * | |
495 * @return string Model name or null if the pagination isn't initialized. | |
496 * @access public | |
497 */ | |
498 function defaultModel() { | |
499 if ($this->__defaultModel != null) { | |
500 return $this->__defaultModel; | |
501 } | |
502 if (empty($this->params['paging'])) { | |
503 return null; | |
504 } | |
505 list($this->__defaultModel) = array_keys($this->params['paging']); | |
506 return $this->__defaultModel; | |
507 } | |
508 | |
509 /** | |
510 * Returns a counter string for the paged result set | |
511 * | |
512 * ### Options | |
513 * | |
514 * - `model` The model to use, defaults to PaginatorHelper::defaultModel(); | |
515 * - `format` The format string you want to use, defaults to 'pages' Which generates output like '1 of 5' | |
516 * set to 'range' to generate output like '1 - 3 of 13'. Can also be set to a custom string, containing | |
517 * the following placeholders `%page%`, `%pages%`, `%current%`, `%count%`, `%start%`, `%end%` and any | |
518 * custom content you would like. | |
519 * - `separator` The separator string to use, default to ' of ' | |
520 * | |
521 * @param mixed $options Options for the counter string. See #options for list of keys. | |
522 * @return string Counter string. | |
523 * @access public | |
524 */ | |
525 function counter($options = array()) { | |
526 if (is_string($options)) { | |
527 $options = array('format' => $options); | |
528 } | |
529 | |
530 $options = array_merge( | |
531 array( | |
532 'model' => $this->defaultModel(), | |
533 'format' => 'pages', | |
534 'separator' => __(' of ', true) | |
535 ), | |
536 $options); | |
537 | |
538 $paging = $this->params($options['model']); | |
539 if ($paging['pageCount'] == 0) { | |
540 $paging['pageCount'] = 1; | |
541 } | |
542 $start = 0; | |
543 if ($paging['count'] >= 1) { | |
544 $start = (($paging['page'] - 1) * $paging['options']['limit']) + 1; | |
545 } | |
546 $end = $start + $paging['options']['limit'] - 1; | |
547 if ($paging['count'] < $end) { | |
548 $end = $paging['count']; | |
549 } | |
550 | |
551 switch ($options['format']) { | |
552 case 'range': | |
553 if (!is_array($options['separator'])) { | |
554 $options['separator'] = array(' - ', $options['separator']); | |
555 } | |
556 $out = $start . $options['separator'][0] . $end . $options['separator'][1]; | |
557 $out .= $paging['count']; | |
558 break; | |
559 case 'pages': | |
560 $out = $paging['page'] . $options['separator'] . $paging['pageCount']; | |
561 break; | |
562 default: | |
563 $map = array( | |
564 '%page%' => $paging['page'], | |
565 '%pages%' => $paging['pageCount'], | |
566 '%current%' => $paging['current'], | |
567 '%count%' => $paging['count'], | |
568 '%start%' => $start, | |
569 '%end%' => $end | |
570 ); | |
571 $out = str_replace(array_keys($map), array_values($map), $options['format']); | |
572 | |
573 $newKeys = array( | |
574 '{:page}', '{:pages}', '{:current}', '{:count}', '{:start}', '{:end}' | |
575 ); | |
576 $out = str_replace($newKeys, array_values($map), $out); | |
577 break; | |
578 } | |
579 return $out; | |
580 } | |
581 | |
582 /** | |
583 * Returns a set of numbers for the paged result set | |
584 * uses a modulus to decide how many numbers to show on each side of the current page (default: 8) | |
585 * | |
586 * ### Options | |
587 * | |
588 * - `before` Content to be inserted before the numbers | |
589 * - `after` Content to be inserted after the numbers | |
590 * - `model` Model to create numbers for, defaults to PaginatorHelper::defaultModel() | |
591 * - `modulus` how many numbers to include on either side of the current page, defaults to 8. | |
592 * - `separator` Separator content defaults to ' | ' | |
593 * - `tag` The tag to wrap links in, defaults to 'span' | |
594 * - `first` Whether you want first links generated, set to an integer to define the number of 'first' | |
595 * links to generate | |
596 * - `last` Whether you want last links generated, set to an integer to define the number of 'last' | |
597 * links to generate | |
598 * | |
599 * @param mixed $options Options for the numbers, (before, after, model, modulus, separator) | |
600 * @return string numbers string. | |
601 * @access public | |
602 */ | |
603 function numbers($options = array()) { | |
604 if ($options === true) { | |
605 $options = array( | |
606 'before' => ' | ', 'after' => ' | ', 'first' => 'first', 'last' => 'last' | |
607 ); | |
608 } | |
609 | |
610 $defaults = array( | |
611 'tag' => 'span', 'before' => null, 'after' => null, 'model' => $this->defaultModel(), | |
612 'modulus' => '8', 'separator' => ' | ', 'first' => null, 'last' => null, | |
613 ); | |
614 $options += $defaults; | |
615 | |
616 $params = (array)$this->params($options['model']) + array('page'=> 1); | |
617 unset($options['model']); | |
618 | |
619 if ($params['pageCount'] <= 1) { | |
620 return false; | |
621 } | |
622 | |
623 extract($options); | |
624 unset($options['tag'], $options['before'], $options['after'], $options['model'], | |
625 $options['modulus'], $options['separator'], $options['first'], $options['last']); | |
626 | |
627 $out = ''; | |
628 | |
629 if ($modulus && $params['pageCount'] > $modulus) { | |
630 $half = intval($modulus / 2); | |
631 $end = $params['page'] + $half; | |
632 | |
633 if ($end > $params['pageCount']) { | |
634 $end = $params['pageCount']; | |
635 } | |
636 $start = $params['page'] - ($modulus - ($end - $params['page'])); | |
637 if ($start <= 1) { | |
638 $start = 1; | |
639 $end = $params['page'] + ($modulus - $params['page']) + 1; | |
640 } | |
641 | |
642 if ($first && $start > 1) { | |
643 $offset = ($start <= (int)$first) ? $start - 1 : $first; | |
644 if ($offset < $start - 1) { | |
645 $out .= $this->first($offset, array('tag' => $tag, 'separator' => $separator)); | |
646 } else { | |
647 $out .= $this->first($offset, array('tag' => $tag, 'after' => $separator, 'separator' => $separator)); | |
648 } | |
649 } | |
650 | |
651 $out .= $before; | |
652 | |
653 for ($i = $start; $i < $params['page']; $i++) { | |
654 $out .= $this->Html->tag($tag, $this->link($i, array('page' => $i), $options)) | |
655 . $separator; | |
656 } | |
657 | |
658 $out .= $this->Html->tag($tag, $params['page'], array('class' => 'current')); | |
659 if ($i != $params['pageCount']) { | |
660 $out .= $separator; | |
661 } | |
662 | |
663 $start = $params['page'] + 1; | |
664 for ($i = $start; $i < $end; $i++) { | |
665 $out .= $this->Html->tag($tag, $this->link($i, array('page' => $i), $options)) | |
666 . $separator; | |
667 } | |
668 | |
669 if ($end != $params['page']) { | |
670 $out .= $this->Html->tag($tag, $this->link($i, array('page' => $end), $options)); | |
671 } | |
672 | |
673 $out .= $after; | |
674 | |
675 if ($last && $end < $params['pageCount']) { | |
676 $offset = ($params['pageCount'] < $end + (int)$last) ? $params['pageCount'] - $end : $last; | |
677 if ($offset <= $last && $params['pageCount'] - $end > $offset) { | |
678 $out .= $this->last($offset, array('tag' => $tag, 'separator' => $separator)); | |
679 } else { | |
680 $out .= $this->last($offset, array('tag' => $tag, 'before' => $separator, 'separator' => $separator)); | |
681 } | |
682 } | |
683 | |
684 } else { | |
685 $out .= $before; | |
686 | |
687 for ($i = 1; $i <= $params['pageCount']; $i++) { | |
688 if ($i == $params['page']) { | |
689 $out .= $this->Html->tag($tag, $i, array('class' => 'current')); | |
690 } else { | |
691 $out .= $this->Html->tag($tag, $this->link($i, array('page' => $i), $options)); | |
692 } | |
693 if ($i != $params['pageCount']) { | |
694 $out .= $separator; | |
695 } | |
696 } | |
697 | |
698 $out .= $after; | |
699 } | |
700 | |
701 return $out; | |
702 } | |
703 | |
704 /** | |
705 * Returns a first or set of numbers for the first pages | |
706 * | |
707 * ### Options: | |
708 * | |
709 * - `tag` The tag wrapping tag you want to use, defaults to 'span' | |
710 * - `after` Content to insert after the link/tag | |
711 * - `model` The model to use defaults to PaginatorHelper::defaultModel() | |
712 * - `separator` Content between the generated links, defaults to ' | ' | |
713 * | |
714 * @param mixed $first if string use as label for the link, if numeric print page numbers | |
715 * @param mixed $options | |
716 * @return string numbers string. | |
717 * @access public | |
718 */ | |
719 function first($first = '<< first', $options = array()) { | |
720 $options = array_merge( | |
721 array( | |
722 'tag' => 'span', | |
723 'after'=> null, | |
724 'model' => $this->defaultModel(), | |
725 'separator' => ' | ', | |
726 ), | |
727 (array)$options); | |
728 | |
729 $params = array_merge(array('page'=> 1), (array)$this->params($options['model'])); | |
730 unset($options['model']); | |
731 | |
732 if ($params['pageCount'] <= 1) { | |
733 return false; | |
734 } | |
735 extract($options); | |
736 unset($options['tag'], $options['after'], $options['model'], $options['separator']); | |
737 | |
738 $out = ''; | |
739 | |
740 if (is_int($first) && $params['page'] > $first) { | |
741 if ($after === null) { | |
742 $after = '...'; | |
743 } | |
744 for ($i = 1; $i <= $first; $i++) { | |
745 $out .= $this->Html->tag($tag, $this->link($i, array('page' => $i), $options)); | |
746 if ($i != $first) { | |
747 $out .= $separator; | |
748 } | |
749 } | |
750 $out .= $after; | |
751 } elseif ($params['page'] > 1) { | |
752 $out = $this->Html->tag($tag, $this->link($first, array('page' => 1), $options)) | |
753 . $after; | |
754 } | |
755 return $out; | |
756 } | |
757 | |
758 /** | |
759 * Returns a last or set of numbers for the last pages | |
760 * | |
761 * ### Options: | |
762 * | |
763 * - `tag` The tag wrapping tag you want to use, defaults to 'span' | |
764 * - `before` Content to insert before the link/tag | |
765 * - `model` The model to use defaults to PaginatorHelper::defaultModel() | |
766 * - `separator` Content between the generated links, defaults to ' | ' | |
767 * | |
768 * @param mixed $last if string use as label for the link, if numeric print page numbers | |
769 * @param mixed $options Array of options | |
770 * @return string numbers string. | |
771 * @access public | |
772 */ | |
773 function last($last = 'last >>', $options = array()) { | |
774 $options = array_merge( | |
775 array( | |
776 'tag' => 'span', | |
777 'before'=> null, | |
778 'model' => $this->defaultModel(), | |
779 'separator' => ' | ', | |
780 ), | |
781 (array)$options); | |
782 | |
783 $params = array_merge(array('page'=> 1), (array)$this->params($options['model'])); | |
784 unset($options['model']); | |
785 | |
786 if ($params['pageCount'] <= 1) { | |
787 return false; | |
788 } | |
789 | |
790 extract($options); | |
791 unset($options['tag'], $options['before'], $options['model'], $options['separator']); | |
792 | |
793 $out = ''; | |
794 $lower = $params['pageCount'] - $last + 1; | |
795 | |
796 if (is_int($last) && $params['page'] < $lower) { | |
797 if ($before === null) { | |
798 $before = '...'; | |
799 } | |
800 for ($i = $lower; $i <= $params['pageCount']; $i++) { | |
801 $out .= $this->Html->tag($tag, $this->link($i, array('page' => $i), $options)); | |
802 if ($i != $params['pageCount']) { | |
803 $out .= $separator; | |
804 } | |
805 } | |
806 $out = $before . $out; | |
807 } elseif ($params['page'] < $params['pageCount']) { | |
808 $out = $before . $this->Html->tag( | |
809 $tag, $this->link($last, array('page' => $params['pageCount']), $options | |
810 )); | |
811 } | |
812 return $out; | |
813 } | |
814 } |