CakePHPのキャッシュ時間をコントロールする

CakePHP1.2.5を使ってます。
特に情報が一定期間変わらないのにDBアクセスが走るページが、TOPページだったり、アクセスが多いページだった場合、キャッシュはパフォーマンス改善に抜群の効果があります。

Cakeのキャッシュを使うと、app/tmp/cache以下にキャッシュファイルを作って、それを参照してDBアクセスを回避するなんてことが簡単にできます。CakeのキャッシュはAPCを使ってメモリ上に載せるとかも簡単です。

今回は、複数ポイントで、異なるキャッシュ時間を持たせたいときのTips。

core.phpにキャッシュを使う定義(デフォルトのまま)

Cache::config('default', array('engine' => 'File'));

ここの定義を、FileからApcにすればメモリに載せたりできます。


あるコントローラで、モデルを使ってDBから読み込んだ結果(配列データ)を60秒キャッシュする場合

<?php

class PostController extends AppController {

  var $uses = array('Post');

  function index() {

    $return_data = null;
    Cache::set(array('duration' => '+60 seconds'));
    if( ($return_data = Cache::read('PostController-index') ) === false ){

      $return_data = $this->Post->find('all');
      Cache::set(array('duration' => '+60 seconds'));
      Cache::write('PostController-index' , $return_data);
    }

    $this->set('data',$return_data);
  }
}

こうすると1回目のアクセスでDBからデータを取得し、その結果の配列データを、app/tmp/cache/PostController-indexというファイルにシリアライズして出力します。60秒以内にアクセスすればキャッシュデータがあるので、キャッシュファイルの内容を、$return_dataに入れます。

基本はこれだけです。超簡単、便利! 注意点は、Cache::readの前と、Cache::writeの前に、それぞれCache::setでキャッシュ時間をセットする必要があることです。これをしないとデフォルトの値がキャッシュ時間にセットされてしまいます。
参照: http://book.cakephp.org/ja/view/773/Cache-set

CakeのCacheは、コントローラじゃなくても、モデルでもどこでも使えますし、配列データでも何でも突っ込めるので、とても便利です。 他の場所で、1時間のキャッシュを使う場合は、

      Cache::set(array('duration' => '+3600 seconds'));
      Cache::write('HogeModel-getData' , $return_data);

こうすればOK。注意点は、キャッシュファイル名が重複しないようにすること。例えばモデル/コントローラ名-メソッド名-パラメータみたいな。
durationの指定は、秒じゃなくても、+1 dayとか、+2 hoursとかでもいけます


余談ですが、Cache::read,writeメソッドには、引数でconfigの値をセットできます。
http://book.cakephp.org/ja/view/766/Cache-read
http://book.cakephp.org/ja/view/767/Cache-write

これを使うと、core.phpに

Cache::config('default', array('engine' => 'File'));
Cache::config('onemin', array('engine' => 'File','duration'=> 60,));
Cache::config('onehour', array('engine' => 'File','duration'=> 3600,));

として、複数定義をしておけば、Cache::read,write時にそれを指定するだけでいけます。

Cache::read('PostController-index', 'onemin')
Cache::write('PostController-index' , $return_data,'onemin');


追記:
英語ブログの方で同じ記事を投稿したら、コメントがありました。
http://cake.eizoku.com/blog/?p=93#comments
キャッシュのファイル名の重複を避けたかったら、findのパラメータ配列をserializeしてmd5にかけて、それをつけると良いよというもの。キャッシュファイル名は、
PostController-index-9e107d9d372bb6826bd81d3542a419d6
こんな感じになる。

コメントくれた二人は、CakeFestに来てた人。