ZF-8731: Zend_Paginator bug with caching
Description
Hello,
I found a bug in Zend_Paginator. If we enable caching of queries to the database through Zend_Paginator:
$cache = Zend_Cache::factory('Core', 'File', $frontendOptions, $backendOptions);
Zend_Paginator::setCache($cache);
....and then run the page with the following code:
$news = new Default_Model_DbTable_News();
$select = $news->select();
$paginator = Zend_Paginator::factory($select);
$page = (int)$this->_getParam('page', 1);
$paginator->setItemCountPerPage(1);
$paginator->setCurrentPageNumber($page);
$this->view->result = $paginator;
...it will execute 4 queries:
0.00359 connect NULL
0.00019 SELECT COUNT(1) AS zend_paginator_row_count FROM news NULL
0.00067 connect NULL
0.0003 SELECT news.* FROM news LIMIT 1 NULL
Also, it always creates a new cache with different name even though it performed the same query. I found function in code, which is responsible for generating name of cache
return md5(serialize($this->getAdapter()) . $this->getItemCountPerPage());
The problem is that the serialized object (Zend_Paginator_Adapter_DbSelect) when Zend_Db_Profiler is enable, has also included a unique time measurement queries. So we can be 100% sure that the result of function md5() will be different every time. Also, when we execute the function serialize() of adapter, Zend_Db disconnect from the database.
I prepared an initial fix, which solves the problem with the cache and re-connecting to the database. Zend_Paginator_Adapter_DbSelect class should implement Serializable interface (although I think it should all implement adapters, not only DbSelect):
class Zend_Paginator_Adapter_DbSelect implements Zend_Paginator_Adapter_Interface, Serializable
{
...
public function serialize()
{
return serialize($this->_select->__toString());
}
public function unserialize($data) {}
...
}
I hope that this bug will be fixed soon.
Regards deallas
Comments
Posted by Dolf Schimmel (Freeaqingme) (freak) on 2010-01-06T17:19:40.000+0000
Added formatting
Posted by Chuck Reeves (creeves1982) on 2010-02-04T08:09:38.000+0000
Please note that:
Should be
__toString is a method call not a property.
Posted by Chuck Reeves (creeves1982) on 2010-02-05T12:47:33.000+0000
There is still an issue with the above fix. The limit clause for the select statement will not be set until after the cache is checked. When the cache is checked initially the query might look like the following:
SELECT
_table.* FROM_tableORDER BYidASCAfter the cache is checked a call to getItems() is made to the adapter which will add the limit clause making the select statement:
SELECT
_table.* FROM_tableORDER BYidASC LIMIT 10That causes the generated md5 to change. The fix would be to save the cache key to a class member and set that key on the 1st call to Zend_Paginator::_getCacheId() and unset on each call to Zend_Paginator::setItemCountPerPage() and Zend_Paginator::setCurrentPageNumber()
Below is my suggestion to help fix this issue: Please note that _getCacheInternalId now accepts the page parameter
Posted by Marco Kaiser (bate) on 2010-05-26T04:19:08.000+0000
fixed with r22302