Bladeren bron

ZF-6989: Zend_Paginator_Adapter_DbSelect should not use Select object in serialization

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@24754 44c647ce-9c0f-0410-b52a-842ac1e357ba
adamlundrigan 13 jaren geleden
bovenliggende
commit
7f9163445e

+ 28 - 7
library/Zend/Paginator.php

@@ -524,13 +524,26 @@ class Zend_Paginator implements Countable, IteratorAggregate
     }
 
     /**
-     * Returns the total number of items available.
+     * Returns the total number of items available.  Uses cache if caching is enabled.
      *
      * @return integer
      */
     public function getTotalItemCount()
     {
-        return count($this->getAdapter());
+        if (!$this->_cacheEnabled()) {
+            return count($this->getAdapter());
+        } else {
+            $cacheId   = md5($this->_getCacheInternalId(). '_itemCount');            
+            $itemCount = self::$_cache->load($cacheId);
+
+            if ($itemCount === false) {
+                $itemCount = count($this->getAdapter());
+
+                self::$_cache->save($itemCount, $cacheId, array($this->_getCacheInternalId()));
+            }
+            
+            return $itemCount;
+        }
     }
 
     /**
@@ -1044,10 +1057,18 @@ class Zend_Paginator implements Countable, IteratorAggregate
      */
     protected function _getCacheInternalId()
     {
-        return md5(serialize(array(
-            $this->getAdapter(),
-            $this->getItemCountPerPage()
-        )));
+        $adapter = $this->getAdapter();
+        
+        if (method_exists($adapter, 'getCacheIdentifier')) {
+            return md5(serialize(array(
+                $adapter->getCacheIdentifier(), $this->getItemCountPerPage()
+            )));
+        } else {
+            return md5(serialize(array(
+                $adapter,
+                $this->getItemCountPerPage()
+            )));
+        }
     }
 
     /**
@@ -1057,7 +1078,7 @@ class Zend_Paginator implements Countable, IteratorAggregate
      */
     protected function _calculatePageCount()
     {
-        return (integer) ceil($this->getAdapter()->count() / $this->getItemCountPerPage());
+        return (integer) ceil($this->getTotalItemCount() / $this->getItemCountPerPage());
     }
 
     /**

+ 19 - 0
library/Zend/Paginator/Adapter/DbSelect.php

@@ -71,6 +71,14 @@ class Zend_Paginator_Adapter_DbSelect implements Zend_Paginator_Adapter_Interfac
     protected $_rowCount = null;
 
     /**
+     * Identifies this adapter for caching purposes.  This value will remain constant for
+     * the entire life of this adapter regardless of how many different pages are queried.
+     *
+     * @var string
+     */
+    protected $_cacheIdentifier = null;
+
+    /**
      * Constructor.
      *
      * @param Zend_Db_Select $select The select query
@@ -78,9 +86,20 @@ class Zend_Paginator_Adapter_DbSelect implements Zend_Paginator_Adapter_Interfac
     public function __construct(Zend_Db_Select $select)
     {
         $this->_select = $select;
+        $this->_cacheIdentifier = md5($select->assemble());
     }
 
     /**
+     * Returns the cache identifier.
+     * 
+     * @return string
+     */
+    public function getCacheIdentifier()
+    {
+        return $this->_cacheIdentifier;
+    }
+    
+    /**
      * Sets the total row count, either directly or through a supplied
      * query.  Without setting this, {@link getPages()} selects the count
      * as a subquery (SELECT COUNT ... FROM (SELECT ...)).  While this

+ 15 - 0
tests/Zend/Paginator/Adapter/DbSelectTest.php

@@ -99,6 +99,21 @@ class Zend_Paginator_Adapter_DbSelectTest extends PHPUnit_Framework_TestCase
         parent::tearDown();
     }
 
+    /**
+     * @group ZF-6989
+     */
+    public function testCacheIdentifierIsHashOfAssembledSelect()
+    {
+        $dbAdapter = $this->getMockForAbstractClass('Zend_Db_Adapter_Abstract', array(''), '', false);
+        $select    = new Zend_Db_Select($dbAdapter);
+        $select->from('ZF_6989');
+
+        $paginatorAdapter = new Zend_Paginator_Adapter_DbSelect($select);
+
+        $this->assertSame(md5($select->assemble()), $paginatorAdapter->getCacheIdentifier(),
+                          'Cache identifier incorrect!');
+    }
+    
     public function testGetsItemsAtOffsetZero()
     {
         $actual = $this->_adapter->getItems(0, 10);

+ 106 - 0
tests/Zend/PaginatorTest.php

@@ -85,6 +85,11 @@ require_once 'Zend/Cache.php';
 require_once 'Zend/Filter/Callback.php';
 
 /**
+ * @see Zend_Paginator_Adapter_DbSelect
+ */
+require_once 'Zend/Paginator/Adapter/DbSelect.php';
+
+/**
  * @category   Zend
  * @package    Zend_Paginator
  * @subpackage UnitTests
@@ -1031,6 +1036,91 @@ class Zend_PaginatorTest extends PHPUnit_Framework_TestCase
 
         $this->_restorePaginatorDefaults();
     }
+
+    /**
+    * @group ZF-6989
+    */
+    public function testCurrentItemCountIsRetrievedFromCacheIfCachingIsEnabled()
+    {
+    	$dbAdapter = $this->getMockForAbstractClass('Zend_Db_Adapter_Abstract', array(''), '', false);
+    	$select    = new Zend_Db_Select($dbAdapter);
+    	$select->from('ZF_6989');
+    
+    	$paginatorAdapter = new Zend_Paginator_Adapter_DbSelect($select);
+    	$paginatorAdapter->setRowCount(6989);
+    
+    	$paginator       = new Zend_Paginator_TestCache($paginatorAdapter);
+    	$expectedCacheId = md5($paginator->getCacheInternalId() . '_itemCount');
+    
+    	$cache = $this->getMock('Zend_Cache_Core', array('load'), array(), '', false);
+    	$cache->expects($this->once())
+    	       ->method('load')
+    	       ->with($expectedCacheId)
+    	       ->will($this->returnValue(6989));
+    
+    	$paginator->setCacheEnabled(true)
+    	          ->setCache($cache);
+    
+    	$this->assertSame(6989, $paginator->getTotalItemCount(), 'Total item count incorrect!');
+    }
+    
+    /**
+     * @group ZF-6989
+     */
+    public function testPaginatorGeneratesSameCacheIdentifierForDbSelectAdaptersWithIdenticalSqlStatements()
+    {
+        $dbAdapterOne = $this->getMockForAbstractClass('Zend_Db_Adapter_Abstract', array(''),
+                                                       __FUNCTION__ . 'DbAdapterOne', false);
+        $selectOne    = new Zend_Db_Select($dbAdapterOne);
+        $selectOne->from('ZF_6989');
+
+        $paginatorAdapterOne = new Zend_Paginator_Adapter_DbSelect($selectOne);
+        $paginatorAdapterOne->setRowCount(6989);
+
+        $paginatorOne = new Zend_Paginator_TestCache($paginatorAdapterOne);
+
+        $dbAdapterTwo = $this->getMockForAbstractClass('Zend_Db_Adapter_Abstract', array(''), 
+                                                       __FUNCTION__ . 'DbAdapterTwo', false);
+        $selectTwo = new Zend_Db_Select($dbAdapterTwo);
+        $selectTwo->from('ZF_6989');
+   
+        $paginatorAdapterTwo = new Zend_Paginator_Adapter_DbSelect($selectTwo);
+        $paginatorAdapterTwo->setRowCount(6989);
+
+        $paginatorTwo = new Zend_Paginator_TestCache($paginatorAdapterTwo);
+
+        $this->assertSame($paginatorOne->getCacheInternalId(), $paginatorTwo->getCacheInternalId(),
+                          'DbSelect adapters with identical select statements should have the same cache internal IDs!');
+    }
+    
+    /**
+    * @group ZF-6989
+    */
+    public function testPaginatorGeneratesSameCacheIdentifierForDbTableSelectAdaptersWithIdenticalSqlStatements()
+    {
+        $dbAdapterOne = $this->getMockForAbstractClass('Zend_Db_Adapter_Abstract', array(''),
+                                                       __FUNCTION__ . 'DbAdapterOne', false);
+        $selectOne    = new Zend_Db_Select($dbAdapterOne);
+        $selectOne->from('ZF_6989');
+    
+        $paginatorAdapterOne = new Zend_Paginator_Adapter_DbSelect($selectOne);
+        $paginatorAdapterOne->setRowCount(6989);
+    
+        $paginatorOne = new Zend_Paginator_TestCache($paginatorAdapterOne);
+    
+        $dbAdapterTwo = $this->getMockForAbstractClass('Zend_Db_Adapter_Abstract', array(''), 
+                                                       __FUNCTION__ . 'DbAdapterTwo', false);
+        $selectTwo = new Zend_Db_Select($dbAdapterTwo);
+        $selectTwo->from('ZF_6989');
+         
+        $paginatorAdapterTwo = new Zend_Paginator_Adapter_DbSelect($selectTwo);
+        $paginatorAdapterTwo->setRowCount(6989);
+    
+        $paginatorTwo = new Zend_Paginator_TestCache($paginatorAdapterTwo);
+    
+        $this->assertSame($paginatorOne->getCacheInternalId(), $paginatorTwo->getCacheInternalId(),
+                              'DbSelect adapters with identical select statements should have the same cache internal IDs!');
+    }
 }
 
 class Zend_Paginator_TestArrayAggregate implements Zend_Paginator_AdapterAggregate
@@ -1041,6 +1131,22 @@ class Zend_Paginator_TestArrayAggregate implements Zend_Paginator_AdapterAggrega
     }
 }
 
+/**
+ * Wrapper around Zend_Paginator to provide access to cache internal ID method 
+ * for testing purposes.
+ */
+class Zend_Paginator_TestCache extends Zend_Paginator
+{
+    /**
+     * Returns the cache internal ID.
+     * @return string
+     */
+    public function getCacheInternalId()
+    {
+        return $this->_getCacheInternalId();
+    }
+}
+
 // Call Zend_PaginatorTest::main() if this source file is executed directly.
 if (PHPUnit_MAIN_METHOD === 'Zend_PaginatorTest::main') {
     Zend_PaginatorTest::main();