Steve
Steve

Reputation: 3649

Zend_Navigation caching

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.

Upvotes: 1

Views: 1851

Answers (3)

Lionel Gaillard
Lionel Gaillard

Reputation: 3023

Just a warning about caching pages array...

If you cache the array from toArray(), and want to simply use setPages($pagesFromCache), you need to deactive all pages in cached array for future use.

Be careful, Zend_Navigation_Page_Mvc::isActive() checks current request. It means isActive() of your current MVC page still return true, even if you called setActive(false).

The only way I found to deactivate all pages is to recursively walk trough the resulting array :

$pages = $navigation->toArray();

array_walk_recursive(
    $pages,
    function(&$item, $key)
    {
        if($key === 'active')
            $item = false;
    }
);

$cache->save($pages, 'pages');

Upvotes: 1

matthew setter
matthew setter

Reputation: 1

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.

Upvotes: 0

X-Istence
X-Istence

Reputation: 16665

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.

Upvotes: 1

Related Questions