Is there any way to invalidate cached version of a whole-cached page?

Is there any way to invalidate cached version of a whole-cached page (I use COutputCache as a filter in controller)? I know that I can use subclasses of CCacheDependency, but this solution isn’t perfect: one needs to call the method with all request and it can be complicated if conditions are more complicated.

with kind regards,

Augustin




<?php

/**

 * Flush cache Command

 *

 * Deletes all cached data.

 *

 * Usage:

 * yiic flushcache

 *

 * @author Alexander Makarov

 */

class FlushCacheCommand extends CConsoleCommand {

    /**

     * Executes the command.

     * @param array command line parameters for this command.

     */

    public function run($args)

    {

        $cache=Yii::app()->getComponent('cache');

        if($cache!==null){

            $cache->flush();

            echo "Done.\n";

        }

        else {

            echo "Can't flush cache.\n";

        }

    }

}



I didn’t mean “clear the whole cache” but “delete the single page from cache”. Single page = what was cached with COutputCache filter. And I don’t want to do this from console level, but from the class (api) level.

regards,

Augustin

[s]The first thing you need to know, is what ID value is the cache you want to flush (erase). Assuming you know it and you place that value in $pageCacheIDorFragment, hen, just use:

$myCachedPage = Yii::app()->getComponent($pageCacheIDorFragment);

$myCachedPage->flush(); // there you go:[/s]

resources:

flush: http://www.yiiframework.com/doc/api/1.1/ICache#flush-detail

getCache (check source): http://www.yiiframework.com/doc/api/1.1/COutputCache#getCache-detail

how to compute this ID in an elegant way (i.e. using some function, not looking into implementation details and writing one’s own…)?

I don’t wont to flush all the cache (cacheID is the ID of WHOLE cache), I want to delete SINGLE page in cache (keyCache instead of cacheID is what I want).

This question comes up from time to time. Yii’s caching mechanism is a little different. Maybe it helps to first understand how the components interact with each other. Instead of talking to the cache like this:

"Hey cache, please delete page xyz…"

The cache will ask you each time, a page is found in the cache:

"Hey, you out there: I have a cached version for the current request here. Is it still valid?"

So, what you want to do instead, is to attach a cache dependency, that will answer this question with no, if a page is expired. Then the cache component will throw it out of the cache automatically.

In that case, CExpressionDependency will be the best to suit the needs of a cache that we want to erase upon a custom expression is that right?

Well, it depends (pun intended). ;)

CExpressionDependency should be the most flexible one.

Let’s say, if you edit a page, that could have been cached, you want this page to get removed from the cache. To do so you first need to think about how you compose a custom unique page key, that identifies a page. This could be “actionId + itemId” or something more complicated. It completely depends on your application. You should be able to compose this key from the request data of any page that should be cached.

Now the basic principle could be like this:

  • When you edit the page, you use use your custom page key and save a "expired" flag under that key somewhere (maybe also in the cache)

  • In the dependency you use the same key and check if the expired flag is set. If it is set, you remove that flag and return false.

I have to admit, that i’ve never used a cache dependency, but that’s the way i would try it.

What do you mean with Cache Objects / Fragments here? There’s usually only 1 cache component in the application. If you call flush() on that component, it will erase all content from the cache.

http://www.yiiframework.com/doc/api/1.1/COutputCache

“the ID of the cache application component. Defaults to ‘cache’ (the primary cache application component.)”

Nevermind, I am a moron

I should read very carefully what I wrongly suggest. +1 to you Mike. Apologies to all.

Another, maybe easier way to solve this issue might be, to extend COutputCache and override getCacheKey() there. You could create some static method that generates a key from a set of given parameters. Again you need to come up with a logic how to create a unique cache id for any given page that should get cached.




public function getCacheKey()

{

    // Retrieve any request data, that you need to identify the current page here

    return self::createCacheKey($param1,$param2,$param3,...);

}


public static function createCacheKey($param1,$param2,$param3,...)

{

    // put some logic to compose a unique key from the params here

}



Now, when you want to remove a specific page from the cache, you should know the params, that identify this page (again: depends heaviliy on the different request params of your pages). Then you can remove this page from the cache like this:


$key=YourOutputCacheWidget::createCacheKey($param1,$param2,$param3,...);

Yii::app()->cache->delete($key);

check this wiki page

how to invalidate specific page

Interesting approach. This got me to another idea, that doesn’t require to override COutputCache:




     		$filters[]= array(

                'COutputCache',

                'requestTypes'      =>array('GET'),

                'duration'          =>isset($_GET['nocache'] ? 0 : 3600,

            ),



This does not work, because the cached value is not removed from cache if duration=0.

@Alexander: Maybe this could be fixed? Would give a nice way to manually remove pages from cache.

Here’s a workaround (but it comes with a drawback):




            $filters[]= array(


                'COutputCache',

                'requestTypes'      =>array('GET'),

                'duration'          =>3600,


                'dependency'=>array(

                    'class'=>'CExpressionDependency',

                    'expression'=>'isset($_GET["nocache"])',

                ),

     		),



Now if you add “?nocache” to a cached page, the cached page will be removed. So far so good - but now a new version was cached with “?nocache”. So if you reload the page with “?nocache” it will show the recently cached page. To flush this page again, you’ll have to load the page again without “?nocache”.

Apart from that it seems to work nicely.

Mike

I think it worth looking at. Can you add an issue for it to the tracker?

Done:

http://code.google.com/p/yii/issues/detail?id=2258

Cool, this was fixed in SVN and will be in 1.1.8!

is there any way to invalidate cache when it’s an ajax request?. I have problems with the pagination. Thanks.