PageRenderTime 331ms CodeModel.GetById 100ms app.highlight 101ms RepoModel.GetById 120ms app.codeStats 1ms

/library/Zend/Paginator.php

https://bitbucket.org/luizbrandaoj/mini-blog
PHP | 1152 lines | 523 code | 158 blank | 471 comment | 93 complexity | 0d2e35572c6161d319347c703d8ee5c0 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-2011 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 23775 2011-03-01 17:25:24Z ralph $
  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-2011 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.
 528     *
 529     * @return integer
 530     */
 531    public function getTotalItemCount()
 532    {
 533        return count($this->getAdapter());
 534    }
 535
 536    /**
 537     * Clear the page item cache.
 538     *
 539     * @param int $pageNumber
 540     * @return Zend_Paginator
 541     */
 542    public function clearPageItemCache($pageNumber = null)
 543    {
 544        if (!$this->_cacheEnabled()) {
 545            return $this;
 546        }
 547
 548        if (null === $pageNumber) {
 549            foreach (self::$_cache->getIdsMatchingTags(array($this->_getCacheInternalId())) as $id) {
 550                if (preg_match('|'.self::CACHE_TAG_PREFIX."(\d+)_.*|", $id, $page)) {
 551                    self::$_cache->remove($this->_getCacheId($page[1]));
 552                }
 553            }
 554        } else {
 555            $cleanId = $this->_getCacheId($pageNumber);
 556            self::$_cache->remove($cleanId);
 557        }
 558        return $this;
 559    }
 560
 561    /**
 562     * Returns the absolute item number for the specified item.
 563     *
 564     * @param  integer $relativeItemNumber Relative item number
 565     * @param  integer $pageNumber Page number
 566     * @return integer
 567     */
 568    public function getAbsoluteItemNumber($relativeItemNumber, $pageNumber = null)
 569    {
 570        $relativeItemNumber = $this->normalizeItemNumber($relativeItemNumber);
 571
 572        if ($pageNumber == null) {
 573            $pageNumber = $this->getCurrentPageNumber();
 574        }
 575
 576        $pageNumber = $this->normalizePageNumber($pageNumber);
 577
 578        return (($pageNumber - 1) * $this->getItemCountPerPage()) + $relativeItemNumber;
 579    }
 580
 581    /**
 582     * Returns the adapter.
 583     *
 584     * @return Zend_Paginator_Adapter_Interface
 585     */
 586    public function getAdapter()
 587    {
 588        return $this->_adapter;
 589    }
 590
 591    /**
 592     * Returns the number of items for the current page.
 593     *
 594     * @return integer
 595     */
 596    public function getCurrentItemCount()
 597    {
 598        if ($this->_currentItemCount === null) {
 599            $this->_currentItemCount = $this->getItemCount($this->getCurrentItems());
 600        }
 601
 602        return $this->_currentItemCount;
 603    }
 604
 605    /**
 606     * Returns the items for the current page.
 607     *
 608     * @return Traversable
 609     */
 610    public function getCurrentItems()
 611    {
 612        if ($this->_currentItems === null) {
 613            $this->_currentItems = $this->getItemsByPage($this->getCurrentPageNumber());
 614        }
 615
 616        return $this->_currentItems;
 617    }
 618
 619    /**
 620     * Returns the current page number.
 621     *
 622     * @return integer
 623     */
 624    public function getCurrentPageNumber()
 625    {
 626        return $this->normalizePageNumber($this->_currentPageNumber);
 627    }
 628
 629    /**
 630     * Sets the current page number.
 631     *
 632     * @param  integer $pageNumber Page number
 633     * @return Zend_Paginator $this
 634     */
 635    public function setCurrentPageNumber($pageNumber)
 636    {
 637        $this->_currentPageNumber = (integer) $pageNumber;
 638        $this->_currentItems      = null;
 639        $this->_currentItemCount  = null;
 640
 641        return $this;
 642    }
 643
 644    /**
 645     * Get the filter
 646     *
 647     * @return Zend_Filter_Interface
 648     */
 649    public function getFilter()
 650    {
 651        return $this->_filter;
 652    }
 653
 654    /**
 655     * Set a filter chain
 656     *
 657     * @param Zend_Filter_Interface $filter
 658     * @return Zend_Paginator
 659     */
 660    public function setFilter(Zend_Filter_Interface $filter)
 661    {
 662        $this->_filter = $filter;
 663
 664        return $this;
 665    }
 666
 667    /**
 668     * Returns an item from a page.  The current page is used if there's no
 669     * page sepcified.
 670     *
 671     * @param  integer $itemNumber Item number (1 to itemCountPerPage)
 672     * @param  integer $pageNumber
 673     * @return mixed
 674     */
 675    public function getItem($itemNumber, $pageNumber = null)
 676    {
 677        if ($pageNumber == null) {
 678            $pageNumber = $this->getCurrentPageNumber();
 679        } else if ($pageNumber < 0) {
 680            $pageNumber = ($this->count() + 1) + $pageNumber;
 681        }
 682
 683        $page = $this->getItemsByPage($pageNumber);
 684        $itemCount = $this->getItemCount($page);
 685
 686        if ($itemCount == 0) {
 687            /**
 688             * @see Zend_Paginator_Exception
 689             */
 690            require_once 'Zend/Paginator/Exception.php';
 691
 692            throw new Zend_Paginator_Exception('Page ' . $pageNumber . ' does not exist');
 693        }
 694
 695        if ($itemNumber < 0) {
 696            $itemNumber = ($itemCount + 1) + $itemNumber;
 697        }
 698
 699        $itemNumber = $this->normalizeItemNumber($itemNumber);
 700
 701        if ($itemNumber > $itemCount) {
 702            /**
 703             * @see Zend_Paginator_Exception
 704             */
 705            require_once 'Zend/Paginator/Exception.php';
 706
 707            throw new Zend_Paginator_Exception('Page ' . $pageNumber . ' does not'
 708                                             . ' contain item number ' . $itemNumber);
 709        }
 710
 711        return $page[$itemNumber - 1];
 712    }
 713
 714    /**
 715     * Returns the number of items per page.
 716     *
 717     * @return integer
 718     */
 719    public function getItemCountPerPage()
 720    {
 721        if (empty($this->_itemCountPerPage)) {
 722            $this->_itemCountPerPage = self::getDefaultItemCountPerPage();
 723        }
 724
 725        return $this->_itemCountPerPage;
 726    }
 727
 728    /**
 729     * Sets the number of items per page.
 730     *
 731     * @param  integer $itemCountPerPage
 732     * @return Zend_Paginator $this
 733     */
 734    public function setItemCountPerPage($itemCountPerPage = -1)
 735    {
 736        $this->_itemCountPerPage = (integer) $itemCountPerPage;
 737        if ($this->_itemCountPerPage < 1) {
 738            $this->_itemCountPerPage = $this->getTotalItemCount();
 739        }
 740        $this->_pageCount        = $this->_calculatePageCount();
 741        $this->_currentItems     = null;
 742        $this->_currentItemCount = null;
 743
 744        return $this;
 745    }
 746
 747    /**
 748     * Returns the number of items in a collection.
 749     *
 750     * @param  mixed $items Items
 751     * @return integer
 752     */
 753    public function getItemCount($items)
 754    {
 755        $itemCount = 0;
 756
 757        if (is_array($items) || $items instanceof Countable) {
 758            $itemCount = count($items);
 759        } else { // $items is something like LimitIterator
 760            $itemCount = iterator_count($items);
 761        }
 762
 763        return $itemCount;
 764    }
 765
 766    /**
 767     * Returns the items for a given page.
 768     *
 769     * @return Traversable
 770     */
 771    public function getItemsByPage($pageNumber)
 772    {
 773        $pageNumber = $this->normalizePageNumber($pageNumber);
 774
 775        if ($this->_cacheEnabled()) {
 776            $data = self::$_cache->load($this->_getCacheId($pageNumber));
 777            if ($data !== false) {
 778                return $data;
 779            }
 780        }
 781
 782        $offset = ($pageNumber - 1) * $this->getItemCountPerPage();
 783
 784        $items = $this->_adapter->getItems($offset, $this->getItemCountPerPage());
 785
 786        $filter = $this->getFilter();
 787
 788        if ($filter !== null) {
 789            $items = $filter->filter($items);
 790        }
 791
 792        if (!$items instanceof Traversable) {
 793            $items = new ArrayIterator($items);
 794        }
 795
 796        if ($this->_cacheEnabled()) {
 797            self::$_cache->save($items, $this->_getCacheId($pageNumber), array($this->_getCacheInternalId()));
 798        }
 799
 800        return $items;
 801    }
 802
 803    /**
 804     * Returns a foreach-compatible iterator.
 805     *
 806     * @return Traversable
 807     */
 808    public function getIterator()
 809    {
 810        return $this->getCurrentItems();
 811    }
 812
 813    /**
 814     * Returns the page range (see property declaration above).
 815     *
 816     * @return integer
 817     */
 818    public function getPageRange()
 819    {
 820        if (null === $this->_pageRange) {
 821            $this->_pageRange = self::getDefaultPageRange();
 822        }
 823
 824        return $this->_pageRange;
 825    }
 826
 827    /**
 828     * Sets the page range (see property declaration above).
 829     *
 830     * @param  integer $pageRange
 831     * @return Zend_Paginator $this
 832     */
 833    public function setPageRange($pageRange)
 834    {
 835        $this->_pageRange = (integer) $pageRange;
 836
 837        return $this;
 838    }
 839
 840    /**
 841     * Returns the page collection.
 842     *
 843     * @param  string $scrollingStyle Scrolling style
 844     * @return array
 845     */
 846    public function getPages($scrollingStyle = null)
 847    {
 848        if ($this->_pages === null) {
 849            $this->_pages = $this->_createPages($scrollingStyle);
 850        }
 851
 852        return $this->_pages;
 853    }
 854
 855    /**
 856     * Returns a subset of pages within a given range.
 857     *
 858     * @param  integer $lowerBound Lower bound of the range
 859     * @param  integer $upperBound Upper bound of the range
 860     * @return array
 861     */
 862    public function getPagesInRange($lowerBound, $upperBound)
 863    {
 864        $lowerBound = $this->normalizePageNumber($lowerBound);
 865        $upperBound = $this->normalizePageNumber($upperBound);
 866
 867        $pages = array();
 868
 869        for ($pageNumber = $lowerBound; $pageNumber <= $upperBound; $pageNumber++) {
 870            $pages[$pageNumber] = $pageNumber;
 871        }
 872
 873        return $pages;
 874    }
 875
 876    /**
 877     * Returns the page item cache.
 878     *
 879     * @return array
 880     */
 881    public function getPageItemCache()
 882    {
 883        $data = array();
 884        if ($this->_cacheEnabled()) {
 885            foreach (self::$_cache->getIdsMatchingTags(array($this->_getCacheInternalId())) as $id) {
 886                    if (preg_match('|'.self::CACHE_TAG_PREFIX."(\d+)_.*|", $id, $page)) {
 887                        $data[$page[1]] = self::$_cache->load($this->_getCacheId($page[1]));
 888                    }
 889            }
 890        }
 891        return $data;
 892    }
 893
 894    /**
 895     * Retrieves the view instance.  If none registered, attempts to pull f
 896     * rom ViewRenderer.
 897     *
 898     * @return Zend_View_Interface|null
 899     */
 900    public function getView()
 901    {
 902        if ($this->_view === null) {
 903            /**
 904             * @see Zend_Controller_Action_HelperBroker
 905             */
 906            require_once 'Zend/Controller/Action/HelperBroker.php';
 907
 908            $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
 909            if ($viewRenderer->view === null) {
 910                $viewRenderer->initView();
 911            }
 912            $this->_view = $viewRenderer->view;
 913        }
 914
 915        return $this->_view;
 916    }
 917
 918    /**
 919     * Sets the view object.
 920     *
 921     * @param  Zend_View_Interface $view
 922     * @return Zend_Paginator
 923     */
 924    public function setView(Zend_View_Interface $view = null)
 925    {
 926        $this->_view = $view;
 927
 928        return $this;
 929    }
 930
 931    /**
 932     * Brings the item number in range of the page.
 933     *
 934     * @param  integer $itemNumber
 935     * @return integer
 936     */
 937    public function normalizeItemNumber($itemNumber)
 938    {
 939        $itemNumber = (integer) $itemNumber;
 940
 941        if ($itemNumber < 1) {
 942            $itemNumber = 1;
 943        }
 944
 945        if ($itemNumber > $this->getItemCountPerPage()) {
 946            $itemNumber = $this->getItemCountPerPage();
 947        }
 948
 949        return $itemNumber;
 950    }
 951
 952    /**
 953     * Brings the page number in range of the paginator.
 954     *
 955     * @param  integer $pageNumber
 956     * @return integer
 957     */
 958    public function normalizePageNumber($pageNumber)
 959    {
 960        $pageNumber = (integer) $pageNumber;
 961
 962        if ($pageNumber < 1) {
 963            $pageNumber = 1;
 964        }
 965
 966        $pageCount = $this->count();
 967
 968        if ($pageCount > 0 && $pageNumber > $pageCount) {
 969            $pageNumber = $pageCount;
 970        }
 971
 972        return $pageNumber;
 973    }
 974
 975    /**
 976     * Renders the paginator.
 977     *
 978     * @param  Zend_View_Interface $view
 979     * @return string
 980     */
 981    public function render(Zend_View_Interface $view = null)
 982    {
 983        if (null !== $view) {
 984            $this->setView($view);
 985        }
 986
 987        $view = $this->getView();
 988
 989        return $view->paginationControl($this);
 990    }
 991
 992    /**
 993     * Returns the items of the current page as JSON.
 994     *
 995     * @return string
 996     */
 997    public function toJson()
 998    {
 999        $currentItems = $this->getCurrentItems();
1000
1001        if ($currentItems instanceof Zend_Db_Table_Rowset_Abstract) {
1002            return Zend_Json::encode($currentItems->toArray());
1003        } else {
1004            return Zend_Json::encode($currentItems);
1005        }
1006    }
1007
1008    /**
1009     * Tells if there is an active cache object
1010     * and if the cache has not been desabled
1011     *
1012     * @return bool
1013     */
1014    protected function _cacheEnabled()
1015    {
1016        return ((self::$_cache !== null) && $this->_cacheEnabled);
1017    }
1018
1019    /**
1020     * Makes an Id for the cache
1021     * Depends on the adapter object and the page number
1022     *
1023     * Used to store item in cache from that Paginator instance
1024     *  and that current page
1025     *
1026     * @param int $page
1027     * @return string
1028     */
1029    protected function _getCacheId($page = null)
1030    {
1031        if ($page === null) {
1032            $page = $this->getCurrentPageNumber();
1033        }
1034        return self::CACHE_TAG_PREFIX . $page . '_' . $this->_getCacheInternalId();
1035    }
1036
1037    /**
1038     * Get the internal cache id
1039     * Depends on the adapter and the item count per page
1040     *
1041     * Used to tag that unique Paginator instance in cache
1042     *
1043     * @return string
1044     */
1045    protected function _getCacheInternalId()
1046    {
1047        return md5(serialize(array(
1048            $this->getAdapter(),
1049            $this->getItemCountPerPage()
1050        )));
1051    }
1052
1053    /**
1054     * Calculates the page count.
1055     *
1056     * @return integer
1057     */
1058    protected function _calculatePageCount()
1059    {
1060        return (integer) ceil($this->getAdapter()->count() / $this->getItemCountPerPage());
1061    }
1062
1063    /**
1064     * Creates the page collection.
1065     *
1066     * @param  string $scrollingStyle Scrolling style
1067     * @return stdClass
1068     */
1069    protected function _createPages($scrollingStyle = null)
1070    {
1071        $pageCount         = $this->count();
1072        $currentPageNumber = $this->getCurrentPageNumber();
1073
1074        $pages = new stdClass();
1075        $pages->pageCount        = $pageCount;
1076        $pages->itemCountPerPage = $this->getItemCountPerPage();
1077        $pages->first            = 1;
1078        $pages->current          = $currentPageNumber;
1079        $pages->last             = $pageCount;
1080
1081        // Previous and next
1082        if ($currentPageNumber - 1 > 0) {
1083            $pages->previous = $currentPageNumber - 1;
1084        }
1085
1086        if ($currentPageNumber + 1 <= $pageCount) {
1087            $pages->next = $currentPageNumber + 1;
1088        }
1089
1090        // Pages in range
1091        $scrollingStyle = $this->_loadScrollingStyle($scrollingStyle);
1092        $pages->pagesInRange     = $scrollingStyle->getPages($this);
1093        $pages->firstPageInRange = min($pages->pagesInRange);
1094        $pages->lastPageInRange  = max($pages->pagesInRange);
1095
1096        // Item numbers
1097        if ($this->getCurrentItems() !== null) {
1098            $pages->currentItemCount = $this->getCurrentItemCount();
1099            $pages->itemCountPerPage = $this->getItemCountPerPage();
1100            $pages->totalItemCount   = $this->getTotalItemCount();
1101            $pages->firstItemNumber  = (($currentPageNumber - 1) * $this->getItemCountPerPage()) + 1;
1102            $pages->lastItemNumber   = $pages->firstItemNumber + $pages->currentItemCount - 1;
1103        }
1104
1105        return $pages;
1106    }
1107
1108    /**
1109     * Loads a scrolling style.
1110     *
1111     * @param string $scrollingStyle
1112     * @return Zend_Paginator_ScrollingStyle_Interface
1113     */
1114    protected function _loadScrollingStyle($scrollingStyle = null)
1115    {
1116        if ($scrollingStyle === null) {
1117            $scrollingStyle = self::$_defaultScrollingStyle;
1118        }
1119
1120        switch (strtolower(gettype($scrollingStyle))) {
1121            case 'object':
1122                if (!$scrollingStyle instanceof Zend_Paginator_ScrollingStyle_Interface) {
1123                    /**
1124                     * @see Zend_View_Exception
1125                     */
1126                    require_once 'Zend/View/Exception.php';
1127
1128                    throw new Zend_View_Exception('Scrolling style must implement ' .
1129                        'Zend_Paginator_ScrollingStyle_Interface');
1130                }
1131
1132                return $scrollingStyle;
1133
1134            case 'string':
1135                $className = self::getScrollingStyleLoader()->load($scrollingStyle);
1136
1137                return new $className();
1138
1139            case 'null':
1140                // Fall through to default case
1141
1142            default:
1143                /**
1144                 * @see Zend_View_Exception
1145                 */
1146                require_once 'Zend/View/Exception.php';
1147
1148                throw new Zend_View_Exception('Scrolling style must be a class ' .
1149                    'name or object implementing Zend_Paginator_ScrollingStyle_Interface');
1150        }
1151    }
1152}