Browse Source

Add cache options to Cell

The cached cell interface works the same as the element caching does.
I've intentionally omitted using options in the generated key name as
the element version only acts upon keys which is not helpful for cells
as the option keys will always exist.

Refs #5414
Mark Story 11 years ago
parent
commit
e27925e280
2 changed files with 104 additions and 10 deletions
  1. 57 10
      src/View/Cell.php
  2. 47 0
      tests/TestCase/View/CellTest.php

+ 57 - 10
src/View/Cell.php

@@ -116,6 +116,13 @@ abstract class Cell {
 	protected $_validCellOptions = [];
 
 /**
+ * Caching setup.
+ *
+ * @var array|bool
+ */
+	protected $_cache = false;
+
+/**
  * Constructor.
  *
  * @param \Cake\Network\Request $request the request to use in the cell
@@ -135,6 +142,9 @@ abstract class Cell {
 				$this->{$var} = $cellOptions[$var];
 			}
 		}
+		if (!empty($cellOptions['cache'])) {
+			$this->_cache = $cellOptions['cache'];
+		}
 	}
 
 /**
@@ -152,21 +162,58 @@ abstract class Cell {
 		if ($template === null) {
 			$template = $this->template;
 		}
-
 		$this->View = null;
 		$this->getView();
-
 		$this->View->layout = false;
-		$className = explode('\\', get_class($this));
-		$className = array_pop($className);
-		$name = substr($className, 0, strpos($className, 'Cell'));
-		$this->View->subDir = 'Cell' . DS . $name;
 
-		try {
-			return $this->View->render($template);
-		} catch (MissingTemplateException $e) {
-			throw new MissingCellViewException(['file' => $template, 'name' => $name]);
+		$cache = [];
+		if ($this->_cache) {
+			$cache = $this->_cacheConfig($template);
+		}
+
+		$render = function () use ($template) {
+			$className = explode('\\', get_class($this));
+			$className = array_pop($className);
+			$name = substr($className, 0, strpos($className, 'Cell'));
+			$this->View->subDir = 'Cell' . DS . $name;
+
+			try {
+				return $this->View->render($template);
+			} catch (MissingTemplateException $e) {
+				throw new MissingCellViewException(['file' => $template, 'name' => $name]);
+			}
+		};
+
+		if ($cache) {
+			return $this->View->cache(function() use ($render) {
+				echo $render();
+			}, $cache);
+		}
+		return $render();
+	}
+
+/**
+ * Generate the cache key to use for this cell.
+ *
+ * If the key is undefined, the cell class and template will be used.
+ *
+ * @param string $template The template being rendered.
+ * @return array The cache configuration.
+ */
+	protected function _cacheConfig($template) {
+		if (empty($this->_cache)) {
+			return [];
+		}
+		$key = 'cell_' . Inflector::underscore(get_class($this)) . '_' . $template;
+		$key = str_replace('\\', '_', $key);
+		$default = [
+			'config' => 'default',
+			'key' => $key
+		];
+		if ($this->_cache === true) {
+			return $default;
 		}
+		return $this->_cache + $default;
 	}
 
 /**

+ 47 - 0
tests/TestCase/View/CellTest.php

@@ -14,6 +14,7 @@
  */
 namespace Cake\Test\TestCase\View;
 
+use Cake\Cache\Cache;
 use Cake\Controller\Controller;
 use Cake\Core\Configure;
 use Cake\Core\Plugin;
@@ -247,4 +248,50 @@ class CellTest extends TestCase {
 		$this->assertSame('TestApp\View\CustomJsonView', $cell->viewClass);
 	}
 
+/**
+ * Test cached render.
+ *
+ * @return void
+ */
+	public function testCachedRenderSimple() {
+		$mock = $this->getMock('Cake\Cache\CacheEngine');
+		$mock->method('init')
+			->will($this->returnValue(true));
+		$mock->method('read')
+			->will($this->returnValue(false));
+		$mock->expects($this->once())
+			->method('write')
+			->with('cell_test_app_view_cell_articles_cell_display', "dummy\n");
+		Cache::config('default', $mock);
+
+		$cell = $this->View->cell('Articles', [], ['cache' => true]);
+		$result = $cell->render();
+		$this->assertEquals("dummy\n", $result);
+		Cache::drop('default');
+	}
+
+/**
+ * Test cached render array config
+ *
+ * @return void
+ */
+	public function testCachedRenderArrayConfig() {
+		$mock = $this->getMock('Cake\Cache\CacheEngine');
+		$mock->method('init')
+			->will($this->returnValue(true));
+		$mock->method('read')
+			->will($this->returnValue(false));
+		$mock->expects($this->once())
+			->method('write')
+			->with('my_key', "dummy\n");
+		Cache::config('cell', $mock);
+
+		$cell = $this->View->cell('Articles', [], [
+			'cache' => ['key' => 'my_key', 'config' => 'cell']
+		]);
+		$result = $cell->render();
+		$this->assertEquals("dummy\n", $result);
+		Cache::drop('cell');
+	}
+
 }