Issues

ZF-9148: Zend_Cache_Backend_Static doesn't work properly

Description

I'm trying to use Zend_Cache_Backend_Static like this:


protected function _initCache()
{
    $manager = new Zend_Cache_Manager();  
    $manager->setCacheTemplate('page', array(
        'frontend' => array(
            'name'    => 'Capture',
            'options' => array(
                'ignore_user_abort' => true,
                'automatic_serialization' => true
            ),
        ),
        'backend' => array(
            'name'    => 'Static',
            'options' => array(
                'public_dir' => 'cache',
            ),
        ),
    ));
    $manager->getCache('page')->start('nothing', array());
}

Firstly, why i have to specify {{$id}} and {{$tag}} in {{start()}}? Why not just {{$manager->getCache('page')->start()}}?

Then, in Zend_Cache_Backend_Static:


if (is_null($id) || strlen($id) == 0) {
    $id = $this->_detectId();
} else {
    $id = $this->_decodeId($id);
}

But {{$id}} couldn't ever be {{null}} or {{""}}. It's impossible to call {{start('', array())}}, because {{Zend_Cache_Core::validateIdOrTag}} will throw exception {{"Invalid id or tag '$string' : must use only [a-zA-Z0-9]"}}. So, {{$id = $this->_detectId();}} will never be executed, and {{$id = $this->_decodeId($id);}} will produce wrong filename.

Then, in ``` {{$pathName}} become {{"bla-bla/public/cache."}}, and name of file to be created become {{"bla-bla/public/cache./index.html"}}.

So, is it's my mistake or it's really BUG?

Comments

Reassigned for Padraic

It's important to remember that the static cache doesn't work like the other caches. It's designed to be a transparent backend system triggered from a controller action, and as such, it's entire operation is dictated by the Zend_Controller_Action_Helper_Cache class. About the only thing you should change is the location of the public_dir (you're using a non-path above - use the absolute path).

To offer a few points of difference:

IDs are the request URI, however the ID passed to the backend must first be encoded as hexadecimal characters (i.e. bin2hex()) to bypass the Zend_Cache_Core ID restrictions. The request URI may be empty (root URI) and detectId() simply adds a check to ensure this isn't an error passed along by mistake.

Tags are not stored to the static cache, since the static cache holds files to be served OUTSIDE of PHP. The tags are stored to an "inner" cache instead. The inner cache is managed by the backend, and so tags need to be passed at that point.

Data is never serialized unless it also requires a custom extension name outside of the default option. So setting automatic_serialization, as above, should not be done.

The cache is intended to be managed via the Cache action manager which allows you to setup which actions in a controller to cache, with what extension, and with which tags. It also offers methods for removing/purging the cache using the request URI or tags (the tag cleaning is similar to other backends). Use outside of the action helper should use the helper itself as a reference point for manual management. Manually, you would also need to register a helper/plugin to trigger the Capture frontend.

Here's an example from a current project:

.htaccess (includes extra settings for local XML feeds):

AddType application/rss+xml .xml
AddType application/atom+xml .xml

RewriteEngine On

RewriteCond %{REQUEST_URI} feed/rss$
RewriteCond %{DOCUMENT_ROOT}/cached/%{REQUEST_URI}.xml -f
RewriteRule .* cached/%{REQUEST_URI}.xml [L,T=application/rss+xml]

RewriteCond %{REQUEST_URI} feed/atom$
RewriteCond %{DOCUMENT_ROOT}/cached/%{REQUEST_URI}.xml -f
RewriteRule .* cached/%{REQUEST_URI}.xml [L,T=application/atom+xml]

RewriteCond %{DOCUMENT_ROOT}/cached/index.html -f
RewriteRule ^/*$ cached/index.html [L]
RewriteCond %{DOCUMENT_ROOT}/cached/%{REQUEST_URI}.(html|xml|json|opml) -f
RewriteRule .* cached/%{REQUEST_URI}.%1 [L]

RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]

RewriteRule ^.*$ index.php [NC,L]

application.ini:

; Custom Caches (Adjustments To Default CacheManager)
resources.cacheManager.page.backend.options.public_dir = APPLICATION_PATH "/../public/cached"
resources.cacheManager.pagetag.backend.options.cache_dir = APPLICATION_PATH "/../data/cache/tags"

IndexController (Cached):

class Zfplanet_IndexController extends Zend_Controller_Action
{

    protected $_paginator = null;

    public function init()
    {
        $this->_paginator = new Zend_Paginator(
            Doctrine_Core::getTable('Zfplanet_Model_Entry')
        );
        $this->view->paginator = $this->_paginator;
        $this->_helper->cache(array('index', 'page'), array('allentries'));
    }

    public function indexAction()
    {
        $this->_paginator->setCurrentPageNumber(1);
    }
    
    public function pageAction()
    {
        $this->_helper->viewRenderer->setNoRender();
        $this->_paginator->setCurrentPageNumber(
            $this->_getParam('pageNumber')
        );
        $this->render('index');
    }

}

Cache Purging (Here, after a feed is polled (updates index/pages with new content)):

<?php

class Zfplanet_CallbackController extends Zend_Controller_Action
{

    public function processAction()
    {
        // ...
        $this->_helper->getHelper('Cache')->removePagesTagged(array('allentries'));
        // ...
    }

}

This works perfectly fine here.

Padraic, thanks a lot!

Closing - report was the result of a misundertanding of how the static cache operated. Nothing to fix ;).