PageRenderTime 155ms CodeModel.GetById 60ms app.highlight 34ms RepoModel.GetById 17ms app.codeStats 0ms

/Zend/Paginator.php

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