Zend Framework

Zend_Paginator does not use cached Zend_Db_Select correctly

Details

  • Type: Bug Bug
  • Status: Resolved Resolved
  • Priority: Major Major
  • Resolution: Duplicate
  • Affects Version/s: 1.8.4
  • Fix Version/s: None
  • Component/s: Zend_Paginator
  • Labels:
    None

Description

Caching is not working correctly when using Zend_Paginator to paginate Zend_Db_Select results. The values are being cached (I can see the files in my cache location), but they are not being used.

The problem is that the cache IDs are being generated incorrectly.

Feed.php
class Dashboard_Feed extends Zend_Db_Table_Abstract
{
    protected $_name = 'FEED';
    protected $_primary = 'FEED_ID';
}
FeedController.php
$feed = new Dashboard_Feed( Zend_Registry::get('db') );
$select = $feed->select()->order('FEED_TITLE' );

$paginator = Zend_Paginator::factory( $select );
$paginator->setCache( Zend_Registry::get('cache') );
$paginator->setCurrentPageNumber( $this->_getParam('page', 1) );
$paginator->setItemCountPerPage(10);
cache settings
cache.frontend.type = "Core"
cache.frontend.options.automatic_serialization = true
cache.frontend.options.cache_id_prefix = "dashboard_"

cache.backend.type = "File"
cache.backend.options.cache_dir = APPLICATION_PATH "/../data/cache/"

Db adapter is Oracle

Upon first execution, zend_cache---dashboard_Zend_Paginator_1_81a9b1f25e24763494338baa43444b99 is creating in my cache directory - so far so good.

I make a change to one of the items in the DB and refresh. I should not see the change since the results are cached; however, I do see it. Zend_Paginator went back to the database to get the info.

I looked into the Zend_Paginator.php to attempt to get to the bottom of the issue. The problem can be observed in getItemsByPage(...). See the comments I inserted.

Paginator.php
public function getItemsByPage($pageNumber)
{
    $pageNumber = $this->normalizePageNumber($pageNumber);

    if ($this->_cacheEnabled()) {
        // here, _getCacheId(...)  returns "Zend_Paginator_1_a479583744ccc3a9c4d653c390e7ff7f"
        $data = self::$_cache->load($this->_getCacheId($pageNumber));
        if ($data !== false) {
            return $data;
        }
    }

    $offset = ($pageNumber - 1) * $this->_itemCountPerPage;

    $items = $this->_adapter->getItems($offset, $this->_itemCountPerPage);

    $filter = $this->getFilter();

    if ($filter !== null) {
        $items = $filter->filter($items);
    }

    if (!$items instanceof Traversable) {
        $items = new ArrayIterator($items);
    }

    if ($this->_cacheEnabled()) {
        // here, _getCacheId(...)  returns "Zend_Paginator_1_81a9b1f25e24763494338baa43444b99"
        self::$_cache->save($items, $this->_getCacheId($pageNumber), array($this->_getCacheInternalId()));
    }

    return $items;
}

As you can see, when the items are cached, the cache ID corresponds to what was created in my cache directory (obviously), but when Paginator tries to read the cache, it's looking for the wrong ID!

The source of the problem is that _getCacheInternalId() serializes the adapter to identify the cache entry.

Paginator.php
protected function _getCacheInternalId()
{
    return md5(serialize($this->_adapter).$this->_itemCountPerPage);
}

Of course, the adapter's state is going to be different after results are retrieved vs before they are retrieved, so this mechanism cannot work. I saved the serialized value of the adapter from the first and second calls to _getInternalCacheId() to a file and did a diff... there are several differences.

The problem is greatly exacerbated if one is using Zend_Db_Profiler. I was using the profiler to determine if the cache was working correctly. Instead, Zend_Paginator was creating a brand new cache entry with a different ID each time every time I reloaded the page. Why? Well, the profiler contains performance information on the queries that have been run thus far. This information will be different from request to request 99.99% of the time. Different content = different serialization = different cacheId.

I would appreciate it if anybody can comment on this bug and perhaps queue up a resolution for the next ZF patch/release.

I am devising a workaround to use in my project and will post it here for the benefit of others who have encountered this problem.

Issue Links

Activity

Hide
julien PAULI added a comment -

Duplicates #ZF-6989 , even if it gives more informations (will be linked into #ZF-6989)

Show
julien PAULI added a comment - Duplicates #ZF-6989 , even if it gives more informations (will be linked into #ZF-6989)
Hide
julien PAULI added a comment -

Please, get the patch attached to ZF-6989 and make a use case.
We are actually looking for help to test that in order to provide a patch the better it could be.

Show
julien PAULI added a comment - Please, get the patch attached to ZF-6989 and make a use case. We are actually looking for help to test that in order to provide a patch the better it could be.

People

Vote (0)
Watch (1)

Dates

  • Created:
    Updated:
    Resolved: