web/lib/Zend/Paginator.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     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-2010 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 22865 2010-08-21 12:28:09Z ramon $
       
    20  */
       
    21 
       
    22 /**
       
    23  * @see Zend_Loader_PluginLoader
       
    24  */
       
    25 require_once 'Zend/Loader/PluginLoader.php';
       
    26 
       
    27 /**
       
    28  * @see Zend_Json
       
    29  */
       
    30 require_once 'Zend/Json.php';
       
    31 
       
    32 /**
       
    33  * @category   Zend
       
    34  * @package    Zend_Paginator
       
    35  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    36  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    37  */
       
    38 class 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 }