views:

310

answers:

2

Hi

I'm having trouble with the page hierarchy of Zend_Navigation getting scrambled when I cache it using Zend_Cache.

Background: I have approx 50 pages and approx 300 products stored in a database. I query the database and create an array to feed to Zend_Navigation.

The cache is

        $secondsBetweenRefreshes = APPLICATION_ENV == 'development' ? 30 : 300; 
        self::$cache = Zend_Cache::factory( 'Core', 'File',
                             array( 'automatic_serialization' => true,
                                    'lifetime' => $secondsBetweenRefreshes ),
                             array( 'cache_dir' => CACHE_PATH . 'nav/' )
                           );

This works fine

    $struct = $cache->load('Zend_Navigation'); 
    if (empty($struct))
    {
        $cache->save($struct = self::getSiteStructure() );
    }
    return new Zend_Navigation( $struct );

And this gets scrambled

    $struct = $cache->load('Zend_Navigation'); 
    if (empty($struct))
    {
        $cache->save($struct = new Zend_Navigation( self::getSiteStructure() );
    }
    return $struct;

The navigation works fine if it is not pulled from the cache. Yes, the obvious solution is not to cache the Zend_Navigation, but the constructor does a lot of work to build its internal representation: makes sense to do the caching with as much pre-computed as I can...

I'm still trying to see if there is a pattern in the scrambled results. There are no loops / cycles in the tree.

A: 

After reading this question, I took a quick glance at the Zend_Navigation code and it does not seem that there should be any inherent issues with caching it using serialisation. However looking at the Zend_Navigation documentation I found the following:

The toArray() method converts the container and the pages in it to an array. This can be useful for serializing and debugging. - Zend Navigation Containers: Other

You may want to create the Zend_Navigation object, use the toArray() function to create the array and cache that. Re-creating the pages from an array should be fairly inexpensive, although you may want to do some testing.

Also, if possible, file a bug report with the Zend Framework maintainers so that they can take a look at it.

Zend_Navigation although an interesting component, and arguably a useful one is not something I use much. For big websites having 10,000+ objects in memory is not a smart idea, and the way certain items are implemented in Zend_Navigation makes it slow and unwieldy. Many developers using the Zend Framework have found other ways of accomplishing the same goals.

X-Istence
Thanks. Spot on. Looking through the code, they use spl_object_hash() http://nz.php.net/manual/en/function.spl-object-hash.php to calculate hash keys for pages within a container. These get obviously screwed up when unserializing().So the answer is to use toArray(). But then further problems occur if you are caching from your Bootstrap. The answer seems to be to create a controller action helper and load it on demand.
Steve
A: 

Thanks for the post; I thought there may be issues combining Zend_Navigation and Zend_Cache, but I've been able to use the save method on a normal Zend_Navigation object and then retrieve the object back from the cache without any need to use toArray().

X-Istence: I agree that as the size of the navigation objects grow, it may become become rather unwieldly; though I'll have to dig deeper in the code to complete my understanding as to the size tipping point.

cheers,

Matt

matthew setter