Conditional page cache with COutputCache

I want to do full page caching in my application with COutputCache as a filter as in the example in the Page Caching chapter in the guide.

However, I only want to cache pages from guest (not logged in) visitors (full page caching for members would take too much space in the cache causing more useful stuff to get pushed out. Instead they get only some resource-intensive fragments/data items cached).

I can not find any way to do this.

I was hoping I could do it with something like this




                        array('COutputCache',

                                'duration'=>86400,

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

                                'dependency'=>

                                                array(

                                                        'class'=>'CExpressionDependency',

                                                        'expression'=>'$_SESSION["user"]->isGuest',

                                                ),

                        ),



but it looks like this would cache 2 copies, one for guest, one for logged in.

What I need is something like requestTypes except allowing an arbitrary expression instead of just GET/POST.

I potentially have the same problem with CDbCacheDependency. If I have an expression like the example




'dependency'=>array(

        'class'=>'system.caching.dependencies.CDbCacheDependency',

        'sql'=>'SELECT MAX(lastModified) FROM Post'

)



is it smart enough to delete the old cache version when the lastModified date gets bumped, or does it make a new one and leave the old one there wasting space?

How can I do this?

I may be able to work around this by using renderDynamic() for the content that varies for guest/member but this would end up adding quite a bit of complexity (multiple items vary) and wouldn’t provide as much of a performance boost because those content fragments would still need to be calculated for guests.

For your first problem, maybe try this:




array(

    'class'=>'COutputCache',

    'duration'=> Yii::app()->user->isGuest ? 86400 : 0,

    'varyByExpression'=>'Yii::app()->user->isGuest',

),

That sounds like a workable solution. Caching doesn’t seem to be working right tho. I’ve ended up with:




class Users extends CActiveRecord

{

        public isGuest=1;

...

}






        public function filters()

        {

                return array(

                        'accessControl', // perform access control for CRUD operations

                        array('COutputCache',

                                'duration'=> Yii::app()->user->isGuest ? 86400 : 0,

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

                                'cacheID'=>'cache',

                                'varyByExpression'=>'Yii::app()->user->isGuest',

                                #'dependency'=>array(

                                #               'class'=>'CDbCacheDependency',

                                #               'sql'=>'SELECT MAX(lastModified) FROM Post',

                                #               ),

                        ),

                );

        }




(sql dependancy commented out because I don’t have the lastModified stuff set up yet). If I reload the page it seems to load much faster since it’s pulling from memcached but the ajax pagination in the CListView widget doesn’t seem to work anymore unless I comment out the page cache code.

Also, what is the difference between varyByExpression and CExpressionDependency?

I can’t see a difference between the two.

Wonder why you add isGuest to your ActiveRecord - it’s not related to the user component of the application at all (which is a CWebUser object).

Before you introduce caching you should think more if it’s applicable to the current page. You mentioned a ListView - so ask yourself if you really want to cache all different pages of that listview. If you do, you need to vary by the page parameter. Else you’ll always only see the first (cached) page.

Tip: Enable a CWebLogRoute to find out, wether a page is delivered from cache or not.

I was confused about the CWebUser object, but have mostly clarified that now. I guess I’ll need to extend CWebUser and add the attributes of user preferences or an attribute containing the User ActiveRecord class for that currently logged in user.

As for vary by page parameter, I was under the impression that COutputCache automatically varied by GET parameters. Seems I was mistaken so I’ll definitely need to make some adjustments there.

Also, thanks for the CWebLogRoute tip, should be very useful in help trace issues.

You need to specify the names of GET parameters you want to vary by in varyByParam.

I also wanted to enable COutputCache only for quests, so i thought that i could break down the rules. Since in filters() function you only have to return an array of filters, you can make it very simple.

eg.




public function filters()

{

    $filters = array();

    $filters[] = 'accessControl';


    // do caching only if guest user

    if (Yii::app()->user->isGuest) {    

        // output caching

        $filters[] = array(

            'COutputCache + index, view',

            'duration' => 3600,

            'varyByRoute' => true,

            'varyByParam' => array('id', 'Job_page'),

        );

    }

            

    return $filters;

}



Thank you Thanasis, this worked just fine for me :)