Todd Valentine
Todd Valentine

Reputation: 185

Partial Cache Members

I am using the DataObjectsAsPage module. It returns a Datalist ($Items) to the holder page which loops through each $Item. I am also trying to develop a partial caching strategy for the page. I read in the docs that you cannot place cache blocks inside of a loop, so in my DataObjectsAsPageHolder Page, I have the following:

<% cached 'items', LastEdited, CacheSegment %>
    <% loop $Items %>
        $Me
    <% end_loop %>
<% end_cached %>

I checked the silverstripe-cache/cache directory and this seems to be caching the $Items list.

The problem is that I have added a DataExtension to each $Item that allows the admin to set whether or not an $Item is viewable based on the CurrentMember's group. So within each $Me template I have the following:

<% if HasAccess %>
<% end_if %>

I have two issues:

  1. Given the cache key above, if an authorized member is the first to view a page, then the page gets cached and exclusive material gets shown to non-members in subsequent page views.

  2. If I adjust the cache key to the following:

    <% cached 'items', Items.max(Created), CacheSegment unless CurrentMember %>
        <% loop $Items %>
            $Me
        <% end_loop %>
    <% end_cached %>
    

Then the content in each $Me template is never cached for members - which is the largest portion of my sites viewers.

Is there a way I can cache the $Items list for members and non-members and still be able to use the HasAccess check on $Item within the loop?

Upvotes: 1

Views: 457

Answers (1)

drzax
drzax

Reputation: 1665

The simplest solution is probably to add the current member's ID to the cache key.

<% cached 'items', LastEdited, CacheSegment, CurrentMember.ID %>
    <% loop $Items %>
        $Me
    <% end_loop %>
<% end_cached %>

However, this will cache the block uniquely for each registered member. To make the caching a little more useful, you should use the current member's groups in the cache key. Unfortunately, there's no easy way that I know of to get a template cache key ready list of groups for a member.

The easiest way to get a round this issue is probably to add a GroupsCacheKey function to your Page class. It's a bit of a dirty solution, but it should work effectively.

// Untested function
public function GroupsCacheKey() {
    if ($member = Member::currentUser()) {
        return implode('', $member->Groups()->map('ID', 'ID')->toArray());
    }
    return 'nonmember';
}

Then in your template:

<% cached 'items', LastEdited, CacheSegment, GroupsCacheKey %>
    <% loop $Items %>
        $Me
    <% end_loop %>
<% end_cached %>

There is a better solution than this out there somewhere, but it will work.

Upvotes: 3

Related Questions