Browse Source

Add persistent caching to StringTemplate.

This in theory will remove the overhead around compiling templates on
each request.
mark_story 11 years ago
parent
commit
ebd24c408b

+ 2 - 1
src/View/Helper/StringTemplateTrait.php

@@ -64,7 +64,7 @@ trait StringTemplateTrait {
 	public function templater() {
 	public function templater() {
 		if (empty($this->_templater)) {
 		if (empty($this->_templater)) {
 			$class = $this->config('templateClass') ?: 'Cake\View\StringTemplate';
 			$class = $this->config('templateClass') ?: 'Cake\View\StringTemplate';
-			$this->_templater = new $class;
+			$this->_templater = new $class([], str_replace('\\', '_', __CLASS__));
 
 
 			$templates = $this->config('templates');
 			$templates = $this->config('templates');
 			if ($templates) {
 			if ($templates) {
@@ -74,6 +74,7 @@ trait StringTemplateTrait {
 				} else {
 				} else {
 					$this->_templater->add($templates);
 					$this->_templater->add($templates);
 				}
 				}
+				$this->_templater->writeCache();
 			}
 			}
 		}
 		}
 
 

+ 81 - 34
src/View/StringTemplate.php

@@ -14,6 +14,7 @@
  */
  */
 namespace Cake\View;
 namespace Cake\View;
 
 
+use Cake\Cache\Cache;
 use Cake\Configure\Engine\PhpConfig;
 use Cake\Configure\Engine\PhpConfig;
 use Cake\Core\InstanceConfigTrait;
 use Cake\Core\InstanceConfigTrait;
 
 
@@ -64,12 +65,57 @@ class StringTemplate {
 	protected $_compiled = [];
 	protected $_compiled = [];
 
 
 /**
 /**
+ * The persistent cache key for templates.
+ *
+ * @var string
+ */
+	protected $_cacheKey;
+
+/**
  * Constructor.
  * Constructor.
  *
  *
  * @param array $config A set of templates to add.
  * @param array $config A set of templates to add.
+ * @param string $cacheKey The cache key to load templates from
+ */
+	public function __construct(array $config = [], $key = null) {
+		if ($key) {
+			$this->_cacheKey = $key;
+			$this->loadCache();
+		}
+		$this->add($config);
+	}
+
+/**
+ * Loads templates and compiled results from the persistent cache.
+ *
+ * @return void
+ */
+	public function loadCache() {
+		if (!$this->_cacheKey) {
+			return;
+		}
+		$results = Cache::read($this->_cacheKey, '_cake_core_');
+		if (!$results) {
+			return;
+		}
+		$this->_templates = $results['templates'];
+		$this->_compiled = $results['compiled'];
+	}
+
+/**
+ * Save templates to the persistent cache.
+ *
+ * @return void
  */
  */
-	public function __construct(array $config = []) {
-		$this->config($config);
+	public function writeCache() {
+		if (empty($this->_cacheKey)) {
+			return;
+		}
+		$data = [
+			'templates' => $this->_config,
+			'compiled' => $this->_compiled
+		];
+		Cache::write($this->_cacheKey, '_cake_core_');
 	}
 	}
 
 
 /**
 /**
@@ -78,22 +124,22 @@ class StringTemplate {
  * @return void
  * @return void
  */
  */
 	public function push() {
 	public function push() {
-		$this->_configStack[] = $this->_config;
+		$this->_configStack[] = [
+			$this->_config,
+			$this->_compiled
+		];
 	}
 	}
 
 
 /**
 /**
  * Restore the most recently pushed set of templates.
  * Restore the most recently pushed set of templates.
  *
  *
- * Restoring templates will invalidate all compiled templates.
- *
  * @return void
  * @return void
  */
  */
 	public function pop() {
 	public function pop() {
 		if (empty($this->_configStack)) {
 		if (empty($this->_configStack)) {
 			return;
 			return;
 		}
 		}
-		$this->_config = array_pop($this->_configStack);
-		$this->_compiled = [];
+		list($this->_config, $this->_compiled) = array_pop($this->_configStack);
 	}
 	}
 
 
 /**
 /**
@@ -113,11 +159,34 @@ class StringTemplate {
  */
  */
 	public function add(array $templates) {
 	public function add(array $templates) {
 		$this->config($templates);
 		$this->config($templates);
-		$this->_compiled = array_diff_key($this->_compiled, $templates);
+		$this->_compileTemplates(array_keys($templates));
 		return $this;
 		return $this;
 	}
 	}
 
 
 /**
 /**
+ * Compile templates into a more efficient printf() compatible format.
+ *
+ * @param array $templates The template names to compile. If empty all templates will be compiled.
+ */
+	protected function _compileTemplates(array $templates = []) {
+		if (empty($templates)) {
+			$templates = array_keys($this->_config);
+		}
+		foreach ($templates as $name) {
+			$template = $this->get($name);
+			if ($template === null) {
+				$this->_compiled[$name] = [null, null];
+			}
+
+			preg_match_all('#\{\{(\w+)\}\}#', $template, $matches);
+			$this->_compiled[$name] = [
+				str_replace($matches[0], '%s', $template),
+				$matches[1]
+			];
+		}
+	}
+
+/**
  * Load a config file containing templates.
  * Load a config file containing templates.
  *
  *
  * Template files should define a `$config` variable containing
  * Template files should define a `$config` variable containing
@@ -145,31 +214,6 @@ class StringTemplate {
 	}
 	}
 
 
 /**
 /**
- * Returns an array containing the compiled template to be used with
- * the sprintf function and a list of placeholder names that were found
- * in the template in the order that they should be replaced.
- *
- * @param string $name The compiled template info
- * @return array
- */
-	public function compile($name) {
-		if (isset($this->_compiled[$name])) {
-			return $this->_compiled[$name];
-		}
-
-		$template = $this->get($name);
-		if ($template === null) {
-			return $this->_compiled[$name] = [null, null];
-		}
-
-		preg_match_all('#\{\{(\w+)\}\}#', $template, $matches);
-		return $this->_compiled[$name] = [
-			str_replace($matches[0], '%s', $template),
-			$matches[1]
-		];
-	}
-
-/**
  * Format a template string with $data
  * Format a template string with $data
  *
  *
  * @param string $name The template name.
  * @param string $name The template name.
@@ -177,7 +221,10 @@ class StringTemplate {
  * @return string
  * @return string
  */
  */
 	public function format($name, array $data) {
 	public function format($name, array $data) {
-		list($template, $placeholders) = $this->compile($name);
+		if (!isset($this->_compiled[$name])) {
+			return '';
+		}
+		list($template, $placeholders) = $this->_compiled[$name];
 		if ($template === null) {
 		if ($template === null) {
 			return '';
 			return '';
 		}
 		}

+ 0 - 15
tests/TestCase/View/StringTemplateTest.php

@@ -195,21 +195,6 @@ class StringTemplateTest extends TestCase {
 	}
 	}
 
 
 /**
 /**
- * Tests that compile information is refreshed on adds and removes
- *
- * @return void
- */
-	public function testCopiledInfoRefresh() {
-		$compilation = $this->template->compile('link');
-		$this->template->add([
-			'link' => '<a bar="{{foo}}">{{baz}}</a>'
-		]);
-		$this->assertNotEquals($compilation, $this->template->compile('link'));
-		$this->template->remove('link');
-		$this->assertEquals([null, null], $this->template->compile('link'));
-	}
-
-/**
  * test push/pop templates.
  * test push/pop templates.
  *
  *
  * @return void
  * @return void