CakePHPでViewのElementでキャッシュが利用できます。
利用できますが、キャッシュ生成処理の処理上、入れ子になったElementで親と子の両方でCacheを使うとCacheがおかしくなります。
親のElement(ここではAとします)で、Elementの処理時にCacheのconfigを生成するのですが、render時に子のElement(ここではB)の処理時にAのCacheConfigが上書きされます。
そのため、Aのrender後、Cacheに書き込みますが、書き込み先がBのElementのキャッシュとなり、Aのキャッシュは生成されません。
次回(キャッシュの期限が有効の場合)、Aのrender時にAのキャッシュはありませんので、再びrenderが行われます。
よって、Aが呼ばれるたび、この書き込みがループしますので、A(B(A(B(...)))) と処理が行われるたびループします。
<?php // lib/Cake/View/View.php#L398 public function element($name, $data = array(), $options = array()) { (略) // キャッシュを利用する場合はキャッシュから読み込んでみる if (isset($options['cache'])) { $contents = $this->_elementCache($name, $data, $options); if ($contents !== false) { return $contents; } } $file = $this->_getElementFilename($name); if ($file) { // elementファイルを読み込んで処理する return $this->_renderElement($file, $data, $options); } (略) }
<?php protected function _elementCache($name, $data, $options) { (略) $keys = array_merge(array($underscored, $name), array_keys($options), array_keys($data)); $this->elementCacheSettings = array( 'config' => $this->elementCache, 'key' => implode('_', $keys) ); if (is_array($options['cache'])) { $defaults = array( 'config' => $this->elementCache, 'key' => $this->elementCacheSettings['key'] ); $this->elementCacheSettings = array_merge($defaults, $options['cache']); } // Cacheのkeyを設定しているが、格納先がViewクラスのインスタンス変数になっている $this->elementCacheSettings['key'] = 'element_' . $this->elementCacheSettings['key']; return Cache::read($this->elementCacheSettings['key'], $this->elementCacheSettings['config']); }
<?php protected function _renderElement($file, $data, $options) { (略) $element = $this->_render($file, array_merge($this->viewVars, $data)); (略) if (isset($options['cache'])) { Cache::write($this->elementCacheSettings['key'], $element, $this->elementCacheSettings['config']); } return $element; }
この $this->_render()
内部から $this->_evaluate()
が呼ばれているが、そこでElementファイルがincludeされている。
この時、Elementファイル内でCacheを利用する $this->element()
があると一連の処理が再び呼ばれ、 $this->elementCacheSettings['key']
が上書きされてしまう。
<?php protected function _evaluate($viewFile, $dataForView) { $this->__viewFile = $viewFile; extract($dataForView); ob_start(); include $this->__viewFile; unset($this->__viewFile); return ob_get_clean(); }
3.x系のView では処理が変わっているので、この問題は起きないと思われます。
2.x系を使っている環境では、入れ子になったElementでCacheを利用する際には親か子のどちらかでのみCacheを利用するように気をつけましょう。