Browse Source

Merge pull request #4187 from markstory/string-template-cache

Optimize StringTemplate a bit
José Lorenzo Rodríguez 11 years ago
parent
commit
56b02c53bb

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

@@ -64,7 +64,7 @@ trait StringTemplateTrait {
 	public function templater() {
 		if (empty($this->_templater)) {
 			$class = $this->config('templateClass') ?: 'Cake\View\StringTemplate';
-			$this->_templater = new $class;
+			$this->_templater = new $class();
 
 			$templates = $this->config('templates');
 			if ($templates) {
@@ -76,7 +76,6 @@ trait StringTemplateTrait {
 				}
 			}
 		}
-
 		return $this->_templater;
 	}
 

+ 58 - 51
src/View/StringTemplate.php

@@ -36,9 +36,26 @@ class StringTemplate {
  * @var array
  */
 	protected $_compactAttributes = array(
-		'compact', 'checked', 'declare', 'readonly', 'disabled', 'selected',
-		'defer', 'ismap', 'nohref', 'noshade', 'nowrap', 'multiple', 'noresize',
-		'autoplay', 'controls', 'loop', 'muted', 'required', 'novalidate', 'formnovalidate'
+		'compact' => true,
+		'checked' => true,
+		'declare' => true,
+		'readonly' => true,
+		'disabled' => true,
+		'selected' => true,
+		'defer' => true,
+		'ismap' => true,
+		'nohref' => true,
+		'noshade' => true,
+		'nowrap' => true,
+		'multiple' => true,
+		'noresize' => true,
+		'autoplay' => true,
+		'controls' => true,
+		'loop' => true,
+		'muted' => true,
+		'required' => true,
+		'novalidate' => true,
+		'formnovalidate' => true,
 	);
 
 /**
@@ -47,8 +64,6 @@ class StringTemplate {
  * @var array
  */
 	protected $_defaultConfig = [
-		'attribute' => '{{name}}="{{value}}"',
-		'compactAttribute' => '{{name}}="{{value}}"',
 	];
 
 /**
@@ -71,7 +86,7 @@ class StringTemplate {
  * @param array $config A set of templates to add.
  */
 	public function __construct(array $config = []) {
-		$this->config($config);
+		$this->add($config);
 	}
 
 /**
@@ -80,22 +95,22 @@ class StringTemplate {
  * @return void
  */
 	public function push() {
-		$this->_configStack[] = $this->_config;
+		$this->_configStack[] = [
+			$this->_config,
+			$this->_compiled
+		];
 	}
 
 /**
  * Restore the most recently pushed set of templates.
  *
- * Restoring templates will invalidate all compiled templates.
- *
  * @return void
  */
 	public function pop() {
 		if (empty($this->_configStack)) {
 			return;
 		}
-		$this->_config = array_pop($this->_configStack);
-		$this->_compiled = [];
+		list($this->_config, $this->_compiled) = array_pop($this->_configStack);
 	}
 
 /**
@@ -115,11 +130,34 @@ class StringTemplate {
  */
 	public function add(array $templates) {
 		$this->config($templates);
-		$this->_compiled = array_diff_key($this->_compiled, $templates);
+		$this->_compileTemplates(array_keys($templates));
 		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.
  *
  * Template files should define a `$config` variable containing
@@ -147,31 +185,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
  *
  * @param string $name The template name.
@@ -179,7 +192,10 @@ class StringTemplate {
  * @return string
  */
 	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) {
 			return '';
 		}
@@ -251,26 +267,17 @@ class StringTemplate {
 			$value = implode(' ', $value);
 		}
 		if (is_numeric($key)) {
-			return $this->format('compactAttribute', [
-				'name' => $value,
-				'value' => $value
-			]);
+			return "$value=\"$value\"";
 		}
 		$truthy = [1, '1', true, 'true', $key];
-		$isMinimized = in_array($key, $this->_compactAttributes);
+		$isMinimized = isset($this->_compactAttributes[$key]);
 		if ($isMinimized && in_array($value, $truthy, true)) {
-			return $this->format('compactAttribute', [
-				'name' => $key,
-				'value' => $key
-			]);
+			return "$key=\"$key\"";
 		}
 		if ($isMinimized) {
 			return '';
 		}
-		return $this->format('attribute', [
-			'name' => $key,
-			'value' => $escape ? h($value) : $value
-		]);
+		return $key . '="' . ($escape ? h($value) : $value) . '"';
 	}
 
 }

+ 1 - 5
tests/TestCase/View/Helper/StringTemplateTraitTest.php

@@ -65,12 +65,10 @@ class StringTemplateTraitTest extends TestCase {
 
 		$this->assertEquals(
 			[
-				'attribute' => '{{name}}="{{value}}"',
-				'compactAttribute' => '{{name}}="{{value}}"',
 				'text' => '<p>{{text}}</p>'
 			],
 			$this->Template->templates(),
-			'newly added template should be inlcuded in template list'
+			'newly added template should be included in template list'
 		);
 	}
 
@@ -87,8 +85,6 @@ class StringTemplateTraitTest extends TestCase {
 
 		$this->assertEquals(
 			[
-				'attribute' => '{{name}}="{{value}}"',
-				'compactAttribute' => '{{name}}="{{value}}"',
 				'text' => '<p>{{text}}</p>'
 			],
 			$this->Template->templates(),

+ 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.
  *
  * @return void