1<?php 2/** 3 * Zend Framework 4 * 5 * LICENSE 6 * 7 * This source file is subject to the new BSD license that is bundled 8 * with this package in the file LICENSE.txt. 9 * It is also available through the world-wide-web at this URL: 10 * http://framework.zend.com/license/new-bsd 11 * If you did not receive a copy of the license and are unable to 12 * obtain it through the world-wide-web, please send an email 13 * to license@zend.com so we can send you a copy immediately. 14 * 15 * @category Zend 16 * @package Zend_Paginator 17 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 18 * @license http://framework.zend.com/license/new-bsd New BSD License 19 * @version $Id$ 20 */ 21 22/** 23 * @see Zend_Loader_PluginLoader 24 */ 25 26/** 27 * @see Zend_Json 28 */ 29 30/** 31 * @category Zend 32 * @package Zend_Paginator 33 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 34 * @license http://framework.zend.com/license/new-bsd New BSD License 35 */ 36class Zend_Paginator implements Countable, IteratorAggregate 37{ 38 /** 39 * Specifies that the factory should try to detect the proper adapter type first 40 * 41 * @var string 42 */ 43 const INTERNAL_ADAPTER = 'Zend_Paginator_Adapter_Internal'; 44 45 /** 46 * The cache tag prefix used to namespace Paginator results in the cache 47 * 48 */ 49 const CACHE_TAG_PREFIX = 'Zend_Paginator_'; 50 51 /** 52 * Adapter plugin loader 53 * 54 * @var Zend_Loader_PluginLoader 55 */ 56 protected static $_adapterLoader = null; 57 58 /** 59 * Configuration file 60 * 61 * @var Zend_Config 62 */ 63 protected static $_config = null; 64 65 /** 66 * Default scrolling style 67 * 68 * @var string 69 */ 70 protected static $_defaultScrollingStyle = 'Sliding'; 71 72 /** 73 * Default item count per page 74 * 75 * @var int 76 */ 77 protected static $_defaultItemCountPerPage = 10; 78 79 /** 80 * Default number of local pages (i.e., the number of discretes 81 * page numbers that will be displayed, including the current 82 * page number) 83 * 84 * @var int 85 */ 86 protected static $_defaultPageRange = 10; 87 88 /** 89 * Scrolling style plugin loader 90 * 91 * @var Zend_Loader_PluginLoader 92 */ 93 protected static $_scrollingStyleLoader = null; 94 95 /** 96 * Cache object 97 * 98 * @var Zend_Cache_Core 99 */ 100 protected static $_cache; 101 102 /** 103 * Enable or disable the cache by Zend_Paginator instance 104 * 105 * @var bool 106 */ 107 protected $_cacheEnabled = true; 108 109 /** 110 * Adapter 111 * 112 * @var Zend_Paginator_Adapter_Interface 113 */ 114 protected $_adapter = null; 115 116 /** 117 * Number of items in the current page 118 * 119 * @var integer 120 */ 121 protected $_currentItemCount = null; 122 123 /** 124 * Current page items 125 * 126 * @var Traversable 127 */ 128 protected $_currentItems = null; 129 130 /** 131 * Current page number (starting from 1) 132 * 133 * @var integer 134 */ 135 protected $_currentPageNumber = 1; 136 137 /** 138 * Result filter 139 * 140 * @var Zend_Filter_Interface 141 */ 142 protected $_filter = null; 143 144 /** 145 * Number of items per page 146 * 147 * @var integer 148 */ 149 protected $_itemCountPerPage = null; 150 151 /** 152 * Number of pages 153 * 154 * @var integer 155 */ 156 protected $_pageCount = null; 157 158 /** 159 * Number of local pages (i.e., the number of discrete page numbers 160 * that will be displayed, including the current page number) 161 * 162 * @var integer 163 */ 164 protected $_pageRange = null; 165 166 /** 167 * Pages 168 * 169 * @var array 170 */ 171 protected $_pages = null; 172 173 /** 174 * View instance used for self rendering 175 * 176 * @var Zend_View_Interface 177 */ 178 protected $_view = null; 179 180 /** 181 * Adds an adapter prefix path to the plugin loader. 182 * 183 * @param string $prefix 184 * @param string $path 185 */ 186 public static function addAdapterPrefixPath($prefix, $path) 187 { 188 self::getAdapterLoader()->addPrefixPath($prefix, $path); 189 } 190 191 /** 192 * Adds an array of adapter prefix paths to the plugin 193 * loader. 194 * 195 * <code> 196 * $prefixPaths = array( 197 * 'My_Paginator_Adapter' => 'My/Paginator/Adapter/', 198 * 'Your_Paginator_Adapter' => 'Your/Paginator/Adapter/' 199 * ); 200 * </code> 201 * 202 * @param array $prefixPaths 203 */ 204 public static function addAdapterPrefixPaths(array $prefixPaths) 205 { 206 if (isset($prefixPaths['prefix']) && isset($prefixPaths['path'])) { 207 self::addAdapterPrefixPath($prefixPaths['prefix'], $prefixPaths['path']); 208 } else { 209 foreach ($prefixPaths as $prefix => $path) { 210 if (is_array($path) && isset($path['prefix']) && isset($path['path'])) { 211 $prefix = $path['prefix']; 212 $path = $path['path']; 213 } 214 215 self::addAdapterPrefixPath($prefix, $path); 216 } 217 } 218 } 219 220 /** 221 * Adds a scrolling style prefix path to the plugin loader. 222 * 223 * @param string $prefix 224 * @param string $path 225 */ 226 public static function addScrollingStylePrefixPath($prefix, $path) 227 { 228 self::getScrollingStyleLoader()->addPrefixPath($prefix, $path); 229 } 230 231 /** 232 * Adds an array of scrolling style prefix paths to the plugin 233 * loader. 234 * 235 * <code> 236 * $prefixPaths = array( 237 * 'My_Paginator_ScrollingStyle' => 'My/Paginator/ScrollingStyle/', 238 * 'Your_Paginator_ScrollingStyle' => 'Your/Paginator/ScrollingStyle/' 239 * ); 240 * </code> 241 * 242 * @param array $prefixPaths 243 */ 244 public static function addScrollingStylePrefixPaths(array $prefixPaths) 245 { 246 if (isset($prefixPaths['prefix']) && isset($prefixPaths['path'])) { 247 self::addScrollingStylePrefixPath($prefixPaths['prefix'], $prefixPaths['path']); 248 } else { 249 foreach ($prefixPaths as $prefix => $path) { 250 if (is_array($path) && isset($path['prefix']) && isset($path['path'])) { 251 $prefix = $path['prefix']; 252 $path = $path['path']; 253 } 254 255 self::addScrollingStylePrefixPath($prefix, $path); 256 } 257 } 258 } 259 260 /** 261 * Factory. 262 * 263 * @param mixed $data 264 * @param string $adapter 265 * @param array $prefixPaths 266 * @return Zend_Paginator 267 */ 268 public static function factory($data, $adapter = self::INTERNAL_ADAPTER, 269 array $prefixPaths = null) 270 { 271 if ($data instanceof Zend_Paginator_AdapterAggregate) { 272 return new self($data->getPaginatorAdapter()); 273 } else { 274 if ($adapter == self::INTERNAL_ADAPTER) { 275 if (is_array($data)) { 276 $adapter = 'Array'; 277 } else if ($data instanceof Zend_Db_Table_Select) { 278 $adapter = 'DbTableSelect'; 279 } else if ($data instanceof Zend_Db_Select) { 280 $adapter = 'DbSelect'; 281 } else if ($data instanceof Iterator) { 282 $adapter = 'Iterator'; 283 } else if (is_integer($data)) { 284 $adapter = 'Null'; 285 } else { 286 $type = (is_object($data)) ? get_class($data) : gettype($data); 287 288 /** 289 * @see Zend_Paginator_Exception 290 */ 291 292 throw new Zend_Paginator_Exception('No adapter for type ' . $type); 293 } 294 } 295 296 $pluginLoader = self::getAdapterLoader(); 297 298 if (null !== $prefixPaths) { 299 foreach ($prefixPaths as $prefix => $path) { 300 $pluginLoader->addPrefixPath($prefix, $path); 301 } 302 } 303 304 $adapterClassName = $pluginLoader->load($adapter); 305 306 return new self(new $adapterClassName($data)); 307 } 308 } 309 310 /** 311 * Returns the adapter loader. If it doesn't exist it's created. 312 * 313 * @return Zend_Loader_PluginLoader 314 */ 315 public static function getAdapterLoader() 316 { 317 if (self::$_adapterLoader === null) { 318 self::$_adapterLoader = new Zend_Loader_PluginLoader( 319 array('Zend_Paginator_Adapter' => 'Zend/Paginator/Adapter') 320 ); 321 } 322 323 return self::$_adapterLoader; 324 } 325 326 /** 327 * Set a global config 328 * 329 * @param Zend_Config $config 330 */ 331 public static function setConfig(Zend_Config $config) 332 { 333 self::$_config = $config; 334 335 $adapterPaths = $config->get('adapterpaths'); 336 337 if ($adapterPaths != null) { 338 self::addAdapterPrefixPaths($adapterPaths->adapterpath->toArray()); 339 } 340 341 $prefixPaths = $config->get('prefixpaths'); 342 343 if ($prefixPaths != null) { 344 self::addScrollingStylePrefixPaths($prefixPaths->prefixpath->toArray()); 345 } 346 347 $scrollingStyle = $config->get('scrollingstyle'); 348 349 if ($scrollingStyle != null) { 350 self::setDefaultScrollingStyle($scrollingStyle); 351 } 352 } 353 354 /** 355 * Returns the default scrolling style. 356 * 357 * @return string 358 */ 359 public static function getDefaultScrollingStyle() 360 { 361 return self::$_defaultScrollingStyle; 362 } 363 364 /** 365 * Get the default item count per page 366 * 367 * @return int 368 */ 369 public static function getDefaultItemCountPerPage() 370 { 371 return self::$_defaultItemCountPerPage; 372 } 373 374 /** 375 * Set the default item count per page 376 * 377 * @param int $count 378 */ 379 public static function setDefaultItemCountPerPage($count) 380 { 381 self::$_defaultItemCountPerPage = (int) $count; 382 } 383 384 /** 385 * Get the default page range 386 * 387 * @return int 388 */ 389 public static function getDefaultPageRange() 390 { 391 return self::$_defaultPageRange; 392 } 393 394 /** 395 * Set the default page range 396 * 397 * @param int $count 398 */ 399 public static function setDefaultPageRange($count) 400 { 401 self::$_defaultPageRange = (int) $count; 402 } 403 404 /** 405 * Sets a cache object 406 * 407 * @param Zend_Cache_Core $cache 408 */ 409 public static function setCache(Zend_Cache_Core $cache) 410 { 411 self::$_cache = $cache; 412 } 413 414 /** 415 * Sets the default scrolling style. 416 * 417 * @param string $scrollingStyle 418 */ 419 public static function setDefaultScrollingStyle($scrollingStyle = 'Sliding') 420 { 421 self::$_defaultScrollingStyle = $scrollingStyle; 422 } 423 424 /** 425 * Returns the scrolling style loader. If it doesn't exist it's 426 * created. 427 * 428 * @return Zend_Loader_PluginLoader 429 */ 430 public static function getScrollingStyleLoader() 431 { 432 if (self::$_scrollingStyleLoader === null) { 433 self::$_scrollingStyleLoader = new Zend_Loader_PluginLoader( 434 array('Zend_Paginator_ScrollingStyle' => 'Zend/Paginator/ScrollingStyle') 435 ); 436 } 437 438 return self::$_scrollingStyleLoader; 439 } 440 441 /** 442 * Constructor. 443 * 444 * @param Zend_Paginator_Adapter_Interface|Zend_Paginator_AdapterAggregate $adapter 445 */ 446 public function __construct($adapter) 447 { 448 if ($adapter instanceof Zend_Paginator_Adapter_Interface) { 449 $this->_adapter = $adapter; 450 } else if ($adapter instanceof Zend_Paginator_AdapterAggregate) { 451 $this->_adapter = $adapter->getPaginatorAdapter(); 452 } else { 453 /** 454 * @see Zend_Paginator_Exception 455 */ 456 457 throw new Zend_Paginator_Exception( 458 'Zend_Paginator only accepts instances of the type ' . 459 'Zend_Paginator_Adapter_Interface or Zend_Paginator_AdapterAggregate.' 460 ); 461 } 462 463 $config = self::$_config; 464 465 if ($config != null) { 466 $setupMethods = array('ItemCountPerPage', 'PageRange'); 467 468 foreach ($setupMethods as $setupMethod) { 469 $value = $config->get(strtolower($setupMethod)); 470 471 if ($value != null) { 472 $setupMethod = 'set' . $setupMethod; 473 $this->$setupMethod($value); 474 } 475 } 476 } 477 } 478 479 /** 480 * Serializes the object as a string. Proxies to {@link render()}. 481 * 482 * @return string 483 */ 484 public function __toString() 485 { 486 try { 487 $return = $this->render(); 488 return $return; 489 } catch (Exception $e) { 490 trigger_error($e->getMessage(), E_USER_WARNING); 491 } 492 493 return ''; 494 } 495 496 /** 497 * Enables/Disables the cache for this instance 498 * 499 * @param bool $enable 500 * @return Zend_Paginator 501 */ 502 public function setCacheEnabled($enable) 503 { 504 $this->_cacheEnabled = (bool)$enable; 505 return $this; 506 } 507 508 /** 509 * Returns the number of pages. 510 * 511 * @return integer 512 */ 513 public function count() 514 { 515 if (!$this->_pageCount) { 516 $this->_pageCount = $this->_calculatePageCount(); 517 } 518 519 return $this->_pageCount; 520 } 521 522 /** 523 * Returns the total number of items available. Uses cache if caching is enabled. 524 * 525 * @return integer 526 */ 527 public function getTotalItemCount() 528 { 529 if (!$this->_cacheEnabled()) { 530 return count($this->getAdapter()); 531 } else { 532 $cacheId = md5($this->_getCacheInternalId(). '_itemCount'); 533 $itemCount = self::$_cache->load($cacheId); 534 535 if ($itemCount === false) { 536 $itemCount = count($this->getAdapter()); 537 538 self::$_cache->save($itemCount, $cacheId, array($this->_getCacheInternalId())); 539 } 540 541 return $itemCount; 542 } 543 } 544 545 /** 546 * Clear the page item cache. 547 * 548 * @param int $pageNumber 549 * @return Zend_Paginator 550 */ 551 public function clearPageItemCache($pageNumber = null) 552 { 553 if (!$this->_cacheEnabled()) { 554 return $this; 555 } 556 557 if (null === $pageNumber) { 558 foreach (self::$_cache->getIdsMatchingTags(array($this->_getCacheInternalId())) as $id) { 559 if (preg_match('|'.self::CACHE_TAG_PREFIX."(\d+)_.*|", $id, $page)) { 560 self::$_cache->remove($this->_getCacheId($page[1])); 561 } 562 } 563 } else { 564 $cleanId = $this->_getCacheId($pageNumber); 565 self::$_cache->remove($cleanId); 566 } 567 return $this; 568 } 569 570 /** 571 * Returns the absolute item number for the specified item. 572 * 573 * @param integer $relativeItemNumber Relative item number 574 * @param integer $pageNumber Page number 575 * @return integer 576 */ 577 public function getAbsoluteItemNumber($relativeItemNumber, $pageNumber = null) 578 { 579 $relativeItemNumber = $this->normalizeItemNumber($relativeItemNumber); 580 581 if ($pageNumber == null) { 582 $pageNumber = $this->getCurrentPageNumber(); 583 } 584 585 $pageNumber = $this->normalizePageNumber($pageNumber); 586 587 return (($pageNumber - 1) * $this->getItemCountPerPage()) + $relativeItemNumber; 588 } 589 590 /** 591 * Returns the adapter. 592 * 593 * @return Zend_Paginator_Adapter_Interface 594 */ 595 public function getAdapter() 596 { 597 return $this->_adapter; 598 } 599 600 /** 601 * Returns the number of items for the current page. 602 * 603 * @return integer 604 */ 605 public function getCurrentItemCount() 606 { 607 if ($this->_currentItemCount === null) { 608 $this->_currentItemCount = $this->getItemCount($this->getCurrentItems()); 609 } 610 611 return $this->_currentItemCount; 612 } 613 614 /** 615 * Returns the items for the current page. 616 * 617 * @return Traversable 618 */ 619 public function getCurrentItems() 620 { 621 if ($this->_currentItems === null) { 622 $this->_currentItems = $this->getItemsByPage($this->getCurrentPageNumber()); 623 } 624 625 return $this->_currentItems; 626 } 627 628 /** 629 * Returns the current page number. 630 * 631 * @return integer 632 */ 633 public function getCurrentPageNumber() 634 { 635 return $this->normalizePageNumber($this->_currentPageNumber); 636 } 637 638 /** 639 * Sets the current page number. 640 * 641 * @param integer $pageNumber Page number 642 * @return Zend_Paginator $this 643 */ 644 public function setCurrentPageNumber($pageNumber) 645 { 646 $this->_currentPageNumber = (integer) $pageNumber; 647 $this->_currentItems = null; 648 $this->_currentItemCount = null; 649 650 return $this; 651 } 652 653 /** 654 * Get the filter 655 * 656 * @return Zend_Filter_Interface 657 */ 658 public function getFilter() 659 { 660 return $this->_filter; 661 } 662 663 /** 664 * Set a filter chain 665 * 666 * @param Zend_Filter_Interface $filter 667 * @return Zend_Paginator 668 */ 669 public function setFilter(Zend_Filter_Interface $filter) 670 { 671 $this->_filter = $filter; 672 673 return $this; 674 } 675 676 /** 677 * Returns an item from a page. The current page is used if there's no 678 * page sepcified. 679 * 680 * @param integer $itemNumber Item number (1 to itemCountPerPage) 681 * @param integer $pageNumber 682 * @return mixed 683 */ 684 public function getItem($itemNumber, $pageNumber = null) 685 { 686 if ($pageNumber == null) { 687 $pageNumber = $this->getCurrentPageNumber(); 688 } else if ($pageNumber < 0) { 689 $pageNumber = ($this->count() + 1) + $pageNumber; 690 } 691 692 $page = $this->getItemsByPage($pageNumber); 693 $itemCount = $this->getItemCount($page); 694 695 if ($itemCount == 0) { 696 /** 697 * @see Zend_Paginator_Exception 698 */ 699 700 throw new Zend_Paginator_Exception('Page ' . $pageNumber . ' does not exist'); 701 } 702 703 if ($itemNumber < 0) { 704 $itemNumber = ($itemCount + 1) + $itemNumber; 705 } 706 707 $itemNumber = $this->normalizeItemNumber($itemNumber); 708 709 if ($itemNumber > $itemCount) { 710 /** 711 * @see Zend_Paginator_Exception 712 */ 713 714 throw new Zend_Paginator_Exception('Page ' . $pageNumber . ' does not' 715 . ' contain item number ' . $itemNumber); 716 } 717 718 return $page[$itemNumber - 1]; 719 } 720 721 /** 722 * Returns the number of items per page. 723 * 724 * @return integer 725 */ 726 public function getItemCountPerPage() 727 { 728 if (empty($this->_itemCountPerPage)) { 729 $this->_itemCountPerPage = self::getDefaultItemCountPerPage(); 730 } 731 732 return $this->_itemCountPerPage; 733 } 734 735 /** 736 * Sets the number of items per page. 737 * 738 * @param integer $itemCountPerPage 739 * @return Zend_Paginator $this 740 */ 741 public function setItemCountPerPage($itemCountPerPage = -1) 742 { 743 $this->_itemCountPerPage = (integer) $itemCountPerPage; 744 if ($this->_itemCountPerPage < 1) { 745 $this->_itemCountPerPage = $this->getTotalItemCount(); 746 } 747 $this->_pageCount = $this->_calculatePageCount(); 748 $this->_currentItems = null; 749 $this->_currentItemCount = null; 750 751 return $this; 752 } 753 754 /** 755 * Returns the number of items in a collection. 756 * 757 * @param mixed $items Items 758 * @return integer 759 */ 760 public function getItemCount($items) 761 { 762 $itemCount = 0; 763 764 if (is_array($items) || $items instanceof Countable) { 765 $itemCount = count($items); 766 } else { // $items is something like LimitIterator 767 $itemCount = iterator_count($items); 768 } 769 770 return $itemCount; 771 } 772 773 /** 774 * Returns the items for a given page. 775 * 776 * @return Traversable 777 */ 778 public function getItemsByPage($pageNumber) 779 { 780 $pageNumber = $this->normalizePageNumber($pageNumber); 781 782 if ($this->_cacheEnabled()) { 783 $data = self::$_cache->load($this->_getCacheId($pageNumber)); 784 if ($data !== false) { 785 return $data; 786 } 787 } 788 789 $offset = ($pageNumber - 1) * $this->getItemCountPerPage(); 790 791 $items = $this->_adapter->getItems($offset, $this->getItemCountPerPage()); 792 793 $filter = $this->getFilter(); 794 795 if ($filter !== null) { 796 $items = $filter->filter($items); 797 } 798 799 if (!$items instanceof Traversable) { 800 $items = new ArrayIterator($items); 801 } 802 803 if ($this->_cacheEnabled()) { 804 self::$_cache->save($items, $this->_getCacheId($pageNumber), array($this->_getCacheInternalId())); 805 } 806 807 return $items; 808 } 809 810 /** 811 * Returns a foreach-compatible iterator. 812 * 813 * @return Traversable 814 */ 815 public function getIterator() 816 { 817 return $this->getCurrentItems(); 818 } 819 820 /** 821 * Returns the page range (see property declaration above). 822 * 823 * @return integer 824 */ 825 public function getPageRange() 826 { 827 if (null === $this->_pageRange) { 828 $this->_pageRange = self::getDefaultPageRange(); 829 } 830 831 return $this->_pageRange; 832 } 833 834 /** 835 * Sets the page range (see property declaration above). 836 * 837 * @param integer $pageRange 838 * @return Zend_Paginator $this 839 */ 840 public function setPageRange($pageRange) 841 { 842 $this->_pageRange = (integer) $pageRange; 843 844 return $this; 845 } 846 847 /** 848 * Returns the page collection. 849 * 850 * @param string $scrollingStyle Scrolling style 851 * @return array 852 */ 853 public function getPages($scrollingStyle = null) 854 { 855 if ($this->_pages === null) { 856 $this->_pages = $this->_createPages($scrollingStyle); 857 } 858 859 return $this->_pages; 860 } 861 862 /** 863 * Returns a subset of pages within a given range. 864 * 865 * @param integer $lowerBound Lower bound of the range 866 * @param integer $upperBound Upper bound of the range 867 * @return array 868 */ 869 public function getPagesInRange($lowerBound, $upperBound) 870 { 871 $lowerBound = $this->normalizePageNumber($lowerBound); 872 $upperBound = $this->normalizePageNumber($upperBound); 873 874 $pages = array(); 875 876 for ($pageNumber = $lowerBound; $pageNumber <= $upperBound; $pageNumber++) { 877 $pages[$pageNumber] = $pageNumber; 878 } 879 880 return $pages; 881 } 882 883 /** 884 * Returns the page item cache. 885 * 886 * @return array 887 */ 888 public function getPageItemCache() 889 { 890 $data = array(); 891 if ($this->_cacheEnabled()) { 892 foreach (self::$_cache->getIdsMatchingTags(array($this->_getCacheInternalId())) as $id) { 893 if (preg_match('|'.self::CACHE_TAG_PREFIX."(\d+)_.*|", $id, $page)) { 894 $data[$page[1]] = self::$_cache->load($this->_getCacheId($page[1])); 895 } 896 } 897 } 898 return $data; 899 } 900 901 /** 902 * Retrieves the view instance. If none registered, attempts to pull f 903 * rom ViewRenderer. 904 * 905 * @return Zend_View_Interface|null 906 */ 907 public function getView() 908 { 909 if ($this->_view === null) { 910 /** 911 * @see Zend_Controller_Action_HelperBroker 912 */ 913 914 $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); 915 if ($viewRenderer->view === null) { 916 $viewRenderer->initView(); 917 } 918 $this->_view = $viewRenderer->view; 919 } 920 921 return $this->_view; 922 } 923 924 /** 925 * Sets the view object. 926 * 927 * @param Zend_View_Interface $view 928 * @return Zend_Paginator 929 */ 930 public function setView(Zend_View_Interface $view = null) 931 { 932 $this->_view = $view; 933 934 return $this; 935 } 936 937 /** 938 * Brings the item number in range of the page. 939 * 940 * @param integer $itemNumber 941 * @return integer 942 */ 943 public function normalizeItemNumber($itemNumber) 944 { 945 $itemNumber = (integer) $itemNumber; 946 947 if ($itemNumber < 1) { 948 $itemNumber = 1; 949 } 950 951 if ($itemNumber > $this->getItemCountPerPage()) { 952 $itemNumber = $this->getItemCountPerPage(); 953 } 954 955 return $itemNumber; 956 } 957 958 /** 959 * Brings the page number in range of the paginator. 960 * 961 * @param integer $pageNumber 962 * @return integer 963 */ 964 public function normalizePageNumber($pageNumber) 965 { 966 $pageNumber = (integer) $pageNumber; 967 968 if ($pageNumber < 1) { 969 $pageNumber = 1; 970 } 971 972 $pageCount = $this->count(); 973 974 if ($pageCount > 0 && $pageNumber > $pageCount) { 975 $pageNumber = $pageCount; 976 } 977 978 return $pageNumber; 979 } 980 981 /** 982 * Renders the paginator. 983 * 984 * @param Zend_View_Interface $view 985 * @return string 986 */ 987 public function render(Zend_View_Interface $view = null) 988 { 989 if (null !== $view) { 990 $this->setView($view); 991 } 992 993 $view = $this->getView(); 994 995 return $view->paginationControl($this); 996 } 997 998 /** 999 * Returns the items of the current page as JSON. 1000 * 1001 * @return string 1002 */ 1003 public function toJson() 1004 { 1005 $currentItems = $this->getCurrentItems(); 1006 1007 if ($currentItems instanceof Zend_Db_Table_Rowset_Abstract) { 1008 return Zend_Json::encode($currentItems->toArray()); 1009 } else { 1010 return Zend_Json::encode($currentItems); 1011 } 1012 } 1013 1014 /** 1015 * Tells if there is an active cache object 1016 * and if the cache has not been desabled 1017 * 1018 * @return bool 1019 */ 1020 protected function _cacheEnabled() 1021 { 1022 return ((self::$_cache !== null) && $this->_cacheEnabled); 1023 } 1024 1025 /** 1026 * Makes an Id for the cache 1027 * Depends on the adapter object and the page number 1028 * 1029 * Used to store item in cache from that Paginator instance 1030 * and that current page 1031 * 1032 * @param int $page 1033 * @return string 1034 */ 1035 protected function _getCacheId($page = null) 1036 { 1037 if ($page === null) { 1038 $page = $this->getCurrentPageNumber(); 1039 } 1040 return self::CACHE_TAG_PREFIX . $page . '_' . $this->_getCacheInternalId(); 1041 } 1042 1043 /** 1044 * Get the internal cache id 1045 * Depends on the adapter and the item count per page 1046 * 1047 * Used to tag that unique Paginator instance in cache 1048 * 1049 * @return string 1050 */ 1051 protected function _getCacheInternalId() 1052 { 1053 $adapter = $this->getAdapter(); 1054 1055 if (method_exists($adapter, 'getCacheIdentifier')) { 1056 return md5(serialize(array( 1057 $adapter->getCacheIdentifier(), $this->getItemCountPerPage() 1058 ))); 1059 } else { 1060 return md5(serialize(array( 1061 $adapter, 1062 $this->getItemCountPerPage() 1063 ))); 1064 } 1065 } 1066 1067 /** 1068 * Calculates the page count. 1069 * 1070 * @return integer 1071 */ 1072 protected function _calculatePageCount() 1073 { 1074 return (integer) ceil($this->getTotalItemCount() / $this->getItemCountPerPage()); 1075 } 1076 1077 /** 1078 * Creates the page collection. 1079 * 1080 * @param string $scrollingStyle Scrolling style 1081 * @return stdClass 1082 */ 1083 protected function _createPages($scrollingStyle = null) 1084 { 1085 $pageCount = $this->count(); 1086 $currentPageNumber = $this->getCurrentPageNumber(); 1087 1088 $pages = new stdClass(); 1089 $pages->pageCount = $pageCount; 1090 $pages->itemCountPerPage = $this->getItemCountPerPage(); 1091 $pages->first = 1; 1092 $pages->current = $currentPageNumber; 1093 $pages->last = $pageCount; 1094 1095 // Previous and next 1096 if ($currentPageNumber - 1 > 0) { 1097 $pages->previous = $currentPageNumber - 1; 1098 } 1099 1100 if ($currentPageNumber + 1 <= $pageCount) { 1101 $pages->next = $currentPageNumber + 1; 1102 } 1103 1104 // Pages in range 1105 $scrollingStyle = $this->_loadScrollingStyle($scrollingStyle); 1106 $pages->pagesInRange = $scrollingStyle->getPages($this); 1107 $pages->firstPageInRange = min($pages->pagesInRange); 1108 $pages->lastPageInRange = max($pages->pagesInRange); 1109 1110 // Item numbers 1111 if ($this->getCurrentItems() !== null) { 1112 $pages->currentItemCount = $this->getCurrentItemCount(); 1113 $pages->itemCountPerPage = $this->getItemCountPerPage(); 1114 $pages->totalItemCount = $this->getTotalItemCount(); 1115 $pages->firstItemNumber = (($currentPageNumber - 1) * $this->getItemCountPerPage()) + 1; 1116 $pages->lastItemNumber = $pages->firstItemNumber + $pages->currentItemCount - 1; 1117 } 1118 1119 return $pages; 1120 } 1121 1122 /** 1123 * Loads a scrolling style. 1124 * 1125 * @param string $scrollingStyle 1126 * @return Zend_Paginator_ScrollingStyle_Interface 1127 */ 1128 protected function _loadScrollingStyle($scrollingStyle = null) 1129 { 1130 if ($scrollingStyle === null) { 1131 $scrollingStyle = self::$_defaultScrollingStyle; 1132 } 1133 1134 switch (strtolower(gettype($scrollingStyle))) { 1135 case 'object': 1136 if (!$scrollingStyle instanceof Zend_Paginator_ScrollingStyle_Interface) { 1137 /** 1138 * @see Zend_View_Exception 1139 */ 1140 1141 throw new Zend_View_Exception('Scrolling style must implement ' . 1142 'Zend_Paginator_ScrollingStyle_Interface'); 1143 } 1144 1145 return $scrollingStyle; 1146 1147 case 'string': 1148 $className = self::getScrollingStyleLoader()->load($scrollingStyle); 1149 1150 return new $className(); 1151 1152 case 'null': 1153 // Fall through to default case 1154 1155 default: 1156 /** 1157 * @see Zend_View_Exception 1158 */ 1159 1160 throw new Zend_View_Exception('Scrolling style must be a class ' . 1161 'name or object implementing Zend_Paginator_ScrollingStyle_Interface'); 1162 } 1163 } 1164} 1165