views:

33

answers:

1

Hello,

I use Stacic Page Cache (with cache action helper) to cache most of the pages of my App.
This is extremly fast, but not always suitable.

  • How do you cache pages with dynamic data? Eg. layout contains info specific to user.

One solution I considered is to load additional data via Ajax. But in my case it would be better to cache parts of the pages (eg. list of entries or sidebar partial).

  • Is there any ZF recommended way to do it? Eg. cache the view only, not the layout or vice versa.

Cache action helper provides nice interface to cache all the actions. Any solution to cache the page content or partials or view helpers?

A: 

What I've been doing lately is creating a service and then configuring that service with both a db connection and a cache object. Retrieving the data uses a kind of "lazy-loading cascade", looking first in memory, then in cache, then to the db.

For example, one of my apps is for a real-estate agency that operates in several - but not all - of the provinces in our country. We have a db-table of provinces, some of which are enabled for the front-end, and we need to render them in various places (say, as options in a select element). We do something like this (the legacy code-base on which I am working uses DAO objects for db access and PEAR's Cache_Lite for caching, so the example is not strictly Zend Framework, but the principle applies equally):

/**
 * A service for fetching provinces
 */
class My_Service_Provinces
{
    protected $_daoProvinces;
    protected $_provinces = array();
    protected $_cache;


    public function __construct($daoProvinces)
    {
        $this->setDaoProvinces($daoProvinces);
    }

    public function setDaoProvinces($daoProvinces)
    {
        $this->_daoProvinces = $daoProvinces;
        return $this;
    }

    public function getDaoProvinces()
    {
        return $this->_daoProvinces;
    }

    public function setCache($cache)
    {
        $this->_cache = $cache;
        return $this;
    }

    public function getCache()
    {
        if (null == $this->_cache){
            $this->_cache = new My_Cache_Provinces();
        }
        return $this->_cache;
    }

    public function getProvinces()
    {
        if (null == $this->_provinces){
            $cache = $this->getCache();
            $data = $cache->get();
            if (!$data){
                $dao = $this->getDaoProvinces();
                $rows = $dao->frontend();
                $data = array();
                while ($row = $rows->get_row()){
                    $data[$row['provinceId']] = $row;
                }
                $cache->save(serialize($data));
            } else {
                $data = unserialize($data);
            }
            $this->_provinces = $data;
        }
        return $this->_provinces;
    }

    public function getProvince($provinceId)
    {
        $provinces = $this->getProvinces();
        return isset($provinces[$provinceId]) ? $provinces[$provinceId] : null;
    }
}

The cache object is pre-configured with whatever lifetime is appropriate. I give a long lifetime to seldom-changing data, shorter lifetimes to frequently-changing data. If I really need the change to the data to be immediately available to the app - say, the admin adds a new province - I instantiate the cache object and clear the cache on update.

I've even added a factory to help instantiate the service so that calling code does not have to sweat the dependencies. Calling code - perhaps in a controller or even in a view or view-helper - looks something like:

$service = My_Service_Factory::getService('provinces');
$provinces = $service->getProvinces();

Knowwhatimsayin'?

David Weinraub
Thanks. This is kind of obvious. But reading your post I got the idea of `My_View_Helper_Cached_Abstract` or `My_Service_Abstract::setCache($cache, $lifetime)`. What do you think? How to set up the cache resource in the application.ini then?
takeshin
Yeah, it is kind of obvious. ;-) For content unrelated to the "core" page request - layout stuff, like sidebars - I like your view helper approach. The view helper calls the service which employs caching. Your idea to add a configurable lifetime to the cache seems really good. But doesn't the cache object itself have a lifetime "baked-in" as one of the frontend options? So I see a method signature of the form `My_Service_Astract::setCacheLifetime($lifetime)`. Then specific service subclasses could use different lifetimes when they lazy-instantiate the cache object.
David Weinraub
Actually in most cases `$lifetime` will be infinite. The more important parameter is `$cachetag`, to clear up upon request.
takeshin