『CakePHP』を使ってみる 〜13〜 Cache を使う

今回は RSSHelper について試したことを書こうかと思ったけど
あまり思い通りの結果にならなくなってしまったので諦めて Cache についてメモ。

RSSHelper について良さそうな感じでまとまっていたのは以下です。

ブログのエントリをキャッシュしてみる

リファレンスの付録で作ったブログの個別エントリをキャッシュしてみるテスト。

ここで作った entry という アクションをコピーして cache というアクションを作ってみる。

<?php
class PostsController extends AppController {

	var $name = 'Posts';
	var $uses = array('Tag','Post');

	function cache($id)
	{
		$post = $this->Post->findById($id);
		$this->postTitle = h($post['Post']['title']);
		$this->set('post', $post);
	}
}
?>

とりあえずこれがベース。ここに手を加えていく。

Cache を使うための設定

CAKEPHP.jpのドキュメント和訳を参考にしよう、と思ったら 1.2 では早速設定項目が変わっていた。

  • 1.1系 - define ('CACHE_CHECK', true);
  • 1.2系 - Configure::write('Cache.check', true);

こんなカンジっぽい。

1.特定のエントリだけキャッシュ

エントリの id が 1 と 3 のものだけキャッシュするようにしてみる。
unixタイムを表示させて動作を確認してみることに。
とりあえず1時間キャッシュ。

  • /home/theworld/cake/project/tutorial/controllers/posts_controller.php
<?php
class PostsController extends AppController {

	var $name = 'Posts';
	var $uses = array('Tag','Post');
	var $helpers = array('Cache');  // 追加
	var $cacheAction = array(		// 追加
		'posts/cache/1/' => 3600,
		'posts/cache/3/' => 3600
	);
	
	function cache($id)
	{
		$time = time();
		$post = $this->Post->findById($id);
		$this->postTitle = h($post['Post']['title']);
		$time = time();
		$this->set('time', $time);
		$this->set('post', $post);
	}
}
?>

3600のところは秒数での指定。60*60にしたらエラーになってしまった。

  • /home/theworld/cake/project/tutorial/views/posts
<h1><?php echo $post['Post']['title']?></h1>

<p>created on <?php echo $post['Post']['created']?></p>

<p><?php echo $post['Post']['body']?></p>

<p>now:<?php echo $time?> <p>

アクセスしてもらえればわかりますけど、それぞれうまくいきました。
キャッシュありの方は、「now」の項目が変化しますが、なしの方は変化しません。

キャッシュファイルは、tmpに作られています。

  • /home/theworld/cake/project/tutorial/tmp/cache/views

作られたキャッシュファイルを開いてみると以下のような風になっていました。
ちょっと長いです。

<!--cachetime:1205505639--><?php
			App::import('Controller', 'Posts');
			App::import('Model');
			$this->controller = new PostsController();
        			$this->controller->plugin = '';
        			$this->controller->_initComponents();
					$this->helpers = unserialize('a:3:{i:0;s:5:"Cache";i:1;s:4:"Html";i:2;s:4:"Form";}');
					$this->base = '/cakephp/tutorial';
					$this->layout = 'default';
					$this->webroot = '/cakephp/tutorial/';
					$this->here = '/cakephp/tutorial/posts/cache/1/';
					$this->namedArgs  = '';
					$this->argSeparator = '';
					$this->params = unserialize(stripslashes('a:10:{s:4:\"pass\";a:1:{i:0;s:1:\"1\";}s:5:\"named\";a:0:{}s:10:\"controller\";s:5:\"posts\";s:6:\"action\";s:5:\"cache\";s:6:\"plugin\";N;s:4:\"form\";a:0:{}s:3:\"url\";a:1:{s:3:\"url\";s:14:\"posts/cache/1/\";}s:4:\"bare\";i:0;s:11:\"webservices\";N;s:6:\"models\";a:2:{i:0;s:3:\"Tag\";i:1;s:4:\"Post\";}}'));
					$this->action = unserialize('s:5:"cache";');
					$this->data = unserialize(stripslashes('N;'));
					$this->themeWeb = '';
					$this->plugin = '';
					Router::setRequestInfo(array($this->params, array('base' => $this->base, 'webroot' => $this->webroot)));
					$loadedHelpers = array();
					$loadedHelpers = $this->_loadHelpers($loadedHelpers, $this->helpers);
					foreach (array_keys($loadedHelpers) as $helper)
					{
						$replace = strtolower(substr($helper, 0, 1));
						$camelBackedHelper = preg_replace('/\w/', $replace, $helper, 1);
						${$camelBackedHelper} =& $loadedHelpers[$helper];

						if (isset(${$camelBackedHelper}->helpers) && is_array(${$camelBackedHelper}->helpers))
						{
							foreach (${$camelBackedHelper}->helpers as $subHelper)
							{
								${$camelBackedHelper}->{$subHelper} =& $loadedHelpers[$subHelper];
							}
						}
						$this->loaded[$camelBackedHelper] = (${$camelBackedHelper});
					}
					?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>
		CakePHP: the rapid development php framework:		Posts	</title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><link href="/cakephp/tutorial/favicon.ico" type="image/x-icon" rel="icon"/><link href="/cakephp/tutorial/favicon.ico" type="image/x-icon" rel="shortcut icon"/><link rel="stylesheet" type="text/css" href="/cakephp/tutorial/css/cake.generic.css" /></head>
<body>
	<div id="container">
		<div id="header">
			<h1><a href="http://cakephp.org">CakePHP: the rapid development php framework</a></h1>
		</div>
		<div id="content">
			
			<h1>The title</h1>

<p>created on 2008-02-27 11:21:08</p>

<p>This is the post body.</p>

<p>now:1205502039 <p>

		</div>
		<div id="footer">
			<a href="http://www.cakephp.org/" target="_new"><img src="/cakephp/tutorial/img/cake.power.gif" alt="CakePHP: the rapid development php framework" border="0" /></a>		</div>
	</div>
	</body>
</html>

2.特定のアクションをキャッシュ

引数で分けずにそのアクションを全てキャッシュする場合。
とりあえず、キャッシュフォルダのデータは消しておく。

  • /home/theworld/cake/project/tutorial/controllers/posts_controller.php
<?php
class PostsController extends AppController {

	var $name = 'Posts';
	var $uses = array('Tag','Post');
	var $helpers = array('Cache');  // 追加
	var $cacheAction = array(		// 追加
		'posts/cache/' => 3600,
	);
	
	function cache($id)
	{
		$time = time();
		$post = $this->Post->findById($id);
		$this->postTitle = h($post['Post']['title']);
		$time = time();
		$this->set('time', $time);
		$this->set('post', $post);
	}
}
?>

両方ともキャッシュされた。

3.全てのアクションをキャッシュ

全てのアクションをキャッシュすることもできるとのこと。
でも、自分の使い方だとそういうことはしなそう。

var $cacheAction = 3600;

こんなカンジでアクションを指定せず時間だけ指定すれば OK。

4.テンプレートの一部分だけキャッシュ

テンプレートの一部分だけキャッシュすることも可能とのこと。
逆に言えば、一部だけ動的にできるということ。
このような使い方は、例えばエントリのカウンタだけはキャッシュしないみたいなことが想定できるかな。


キャッシュさせたくない部分をでくくればよいらしい。
作ったthtmlに手を加えてみる。

<h1><?php echo $post['Post']['title']?></h1>

<p>created on <?php echo $post['Post']['created']?></p>

<p><?php echo $post['Post']['body']?></p>

<p>now:<cake:nocache><?php echo $time?></cake:nocache> <p>

これで、nowの項目だけ動的に動いていれば OK。
コントローラの記述は「2.特定のアクションをキャッシュ」のものに戻す。

できた!と思いきや、2回目のアクセスではエラーになってしまう。

Notice (8): Undefined variable: time [APP/tmp/cache/views/_cakephp_tutorial_posts_cache_1_.php, line 56]

うーん、なんでだろう?
$time のデータが定義されてないっていわれているけど…。


また後で検証してみる。