KBD

Keith Devens .com

Saturday, March 20, 2010 Flag waving
Mistakes were made. – Ronald Reagan
← Ninjai back onlineCSS3 Selectors →

Daily link icon Friday, June 20, 2003

Caching, Templates, and MVC

I'm starting to look into caching for my web site, now that my CMS is largely in a stable form. So I hopped over to smarty.php.net and they have some interesting looking articles. One on template engines and one on Industrial Strength MVC.

Current thoughts for my caching solution:

  • It needs to handle things like last-modified, etags, conditional gets (I'm not even sure what those are)
  • What about pages that can be mostly static except for a minor dynamic part?
  • How do I control the caching in a fine-grained matter, so that most pages can be cached for a long time and others possibly regenerated up to every 5 minutes or so?
  • "Who" in my CMS controls this? Is this a CMS-wide thing or do modules expose some kind of interface by which the system can determine what can and can't be cached?
  • How does the system do update notifications so that if new content is entered, the very next time the page loads that content can be shown, rather than waiting a few minutes for the cached copy to expire?
  • How can I integrate this with my CMS without having caching be so pervasive that it touches every piece of code?

One possible solution to some of these problems that I'd had in the back of my mind for some time has been an event-based system of some kind. So the CMS can have a set of event mappings set up so that whenever an event is fired, some code belonging to some module is run. An event would furthermore be specific to a module -- the only system-wide change that has to be made is that the system has to be the Ticktockman, running cron jobs or otherwise keeping track of events for the whole system by running them on the next page access, etc.

Since I assume the key for the cache for a particular page will be its URL, and each module "knows" the URL for any of its pieces, and as long as there's only one canonical url by which to access some piece of content (which is really how it should be), the module should know enough to handle this.

Events:

Events can be anything from "Invalidate cache for this item" to "Send subscribers an e-mail". Events should probably be represented in the CMS as either an object or a plain function. Each module, based on a certain event, will be able to say: $cms->fireEvent('event_name', $params); Events are similar to "actions" within my system, and I'm not totally sure right now that they're genuinely separate things.

Though, actions are really meant to handle forms and check user data (and therefore have extensive validation, data "coersion", and error handling facilities), while events will always be fired by the system and should need no parameter checking, validation, or error handling of their own. Also, events will tend to be more fine grained, and a single action will be likely to have multiple events associated with it. So an action which edits a weblog entry may invalidate the cache for that item, the daily, monthly, and yearly pages that reference that item, as well as the cache for the weblog home page, and e-mail subscribers to that post to boot. Oh yeah, and regenerate the RSS feed.

What's nice about my CMS, which may make it easier to do fine grained caching, is that each "section" is displayed individually, by a separate call to $cms->displaySection(). So, if an individual section can be invalidated, it may make it possible for me to have most of a page be static while still allowing some parts to be dynamic. However, this would probably mean that I still have to run the constructors for all of my modules, as well as display the main template and maybe nested templates until I finally get to the part that has to be dynamically generated. So, rather than just being able to dump out the content of a file which is the cache for a given request URL, I'd still have to execute large portions of my CMS even though the reason they normally have to run doesn't exist because the content they exist to generate is already cached.

Hmmmm....

Plus, I wonder what benefit I could get from Smarty, if any. Smarty's already done the caching thing, but I wonder if I'd be able to integrate it with my CMS and get all the features I want. I'll have to look into that more.

(discussion on Simon's site)

← Ninjai back onlineCSS3 Selectors →

Comments XML gif

Simon Willison (http://simon.incutio.com/) wrote:

My blog uses a ludicrously simple caching mechanism on the front page (the most heavily trafficed page of the site) at the moment: it simply saves the generated page in a file somewhere using output buffering and checks the timestamp on the page whenever it is served, regenerating it if it is over a minute old. It's simple and a bit of a hack but it works well, although I've been warned it could suffer problems with race conditions (need to fix that some time).

"It needs to handle things like last-modified, etags, conditional gets (I'm not even sure what those are)"

The best explanation of conditional GET I've seen is here: http://fishbowl.pastiche.org/archives/001132.html

How does the system do update notifications so that if new content is entered, the very next time the page loads that content can be shown, rather than waiting a few minutes for the cached copy to expire?

By far the easiest way of doing this is to implement caching as saving-a-file-somewhere, and regenerating the cache based on the file modified time AND whether or not the file exists. That way if you need to cached copy to expire right now you can just delete it and the system will regenerate it on the fly. My simple caching mecahnism for my blog works like that - whenever I post a new entry the "add entry" script deletes the front page cache causing it to be regenerated to include the new entry the next time someone visits it.

∴ Simon Willison | 21-Jun-2003 3:55am est | http://simon.incutio.com/ | #2237

Harry Fuecks (http://www.phppatterns.com) wrote:

Think if you're using a template engine there's actually three types of caching you can perform.

The first is the template cache, which gets updated every time you change a template. With Smarty this means actually taking the template and "compiling" into native PHP.

The second is the type that output buffering can give you which works with the compiled template, takes the output it generates and caches that for a certain time period. PEAR::Cache_Lite can be a real time save there.

The third is HTTP caching, between the server and the client, which PHP can get involved with (using header() ) to instruct the browser when the page expires. Good general tutorial here

∴ Harry Fuecks | 21-Jun-2003 11:31am est | http://www.phppatterns.com | #2241

Keith (http://www.keithdevens.com/) wrote:

By far the easiest way of doing this is to implement caching as saving-a-file-somewhere, and regenerating the cache based on the file modified time AND whether or not the file exists.

Yeah, that's exactly how I was planning on doing it. The only issue with that is how to store the files. Is each cache filename a hash of the actual Request URI, or do I actually mirror the directory structure of the Request URI...

Also, you just cache the home page, but when you want to cache any page in general you have to have a way to figure out which content is on what page so that the page cache can be deleted when content on that page changes. Or I suppose you could just cache every page for no longer than a minute, in which case it wouldn't really matter.

Thanks Harry, I wasn't aware of PEAR::Cache_Lite - I'll check it out.

Keith | 21-Jun-2003 11:38am est | http://www.keithdevens.com/ | #2242

Harry Fuecks (http://www.phppatterns.com) wrote:

One other thing, re-reading your post, on events. The May Edition of php|arch has a take on event handling (you have to buy it though) which I guess is similar to "actions" - the event is a GET variable.

Think there's another type of event (basically what MS have done with ASP.NET) which is effectively "internal" in that parts of a page are aware of their state. If there's a submit button on a page, for example, and it get's click, the page is POSTed perhaps then on the page view which received the post, the button is notified that it's state has changed and so emits an "onClick" event. Something like that is harder to implement effectively although PEAR::QuickForm does something like this when a form is submitted back to the script thats using QuickForm and say the form failed to validate.

Anyway - just ranting away on a Saturday. Would be real interested to hear how you do - this is still kind a grey area for PHP methinks.

∴ Harry Fuecks | 21-Jun-2003 12:09pm est | http://www.phppatterns.com | #2243

Sreejith wrote:

In ASP.Net when a page is cached the click event of a button control inside it can't work...how can this be solved?....

∴ Sreejith | 24-Mar-2008 11:08pm est | #10586

Feel free to post a comment below. Please see my comment policy.

Formatting Rules (No HTML):

  • **bold**, *italic*, _underlined_, --strikeout--
  • "text"="url" creates a link, and URLs are auto-highlighted
  • Blockquote: Like e-mail, begin paragraph with > (greater-than sign)
  • Lists: begin paragraph with *,-, or + (unordered), or # (ordered)
  • Code block: ?!code:language=perl|php|sql|javascript|etc.{\n}...{\n}?!/code

:
(will be your IP address if blank)
: (optional)
(Will not be shown on site)

: (optional)
:

March 2010
SunMonTueWedThuFriSat
 123456
78910111213
14151617181920
21222324252627
28293031 



RSS feed RSS feed for Keith's Weblog
Atom feed Atom feed for Keith's Weblog
Weblog archive
Recent comments
  on 2 posts

Recent comments XML

I hate ASP.NET

I hate ASP... I was doing wonders​with PHP, then suddenly one of my​clients...

Johnies: Mar 17, 6:14am

Quantum physics and free will

I knew you were going to say that....

Tom Massey: Mar 15, 9:26pm

Generated in about 0.162s.

(Used 8 db queries)