From 7aee02640379f723775c88218f5d9c86f792995d Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Thu, 26 Jun 2014 22:22:07 -0700 Subject: [PATCH] Add default pragma option to Mustache_Engine. Pragmas specified in the Mustache_Engine constructor will be enabled in all templates, regardless of the presence of pragma tags in individual templates. --- src/Mustache/Compiler.php | 20 +++++++- src/Mustache/Engine.php | 42 ++++++++++++++-- src/Mustache/Parser.php | 23 +++++++++ test/Mustache/Test/EngineTest.php | 2 + .../Test/FiveThree/Functional/EngineTest.php | 50 +++++++++++++++++++ 5 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 test/Mustache/Test/FiveThree/Functional/EngineTest.php diff --git a/src/Mustache/Compiler.php b/src/Mustache/Compiler.php index 579c392..c34f992 100644 --- a/src/Mustache/Compiler.php +++ b/src/Mustache/Compiler.php @@ -18,6 +18,7 @@ class Mustache_Compiler { private $pragmas; + private $defaultPragmas = array(); private $sections; private $source; private $indentNextLine; @@ -41,7 +42,7 @@ class Mustache_Compiler */ public function compile($source, array $tree, $name, $customEscape = false, $charset = 'UTF-8', $strictCallables = false, $entityFlags = ENT_COMPAT) { - $this->pragmas = array(); + $this->pragmas = $this->defaultPragmas; $this->sections = array(); $this->source = $source; $this->indentNextLine = true; @@ -53,6 +54,23 @@ class Mustache_Compiler return $this->writeCode($tree, $name); } + /** + * Enable pragmas across all templates, regardless of the presence of pragma + * tags in the individual templates. + * + * @internal Users should set global pragmas in Mustache_Engine, not here :) + * + * @param array $pragmas + */ + public function setPragmas(array $pragmas) + { + $this->pragmas = array(); + foreach ($pragmas as $pragma) { + $this->pragmas[$pragma] = true; + } + $this->defaultPragmas = $this->pragmas; + } + /** * Helper function for walking the Mustache token parse tree. * diff --git a/src/Mustache/Engine.php b/src/Mustache/Engine.php index 01a1a30..cbfe77a 100644 --- a/src/Mustache/Engine.php +++ b/src/Mustache/Engine.php @@ -28,6 +28,11 @@ class Mustache_Engine const PRAGMA_FILTERS = 'FILTERS'; + // Known pragmas + private static $knownPragmas = array( + self::PRAGMA_FILTERS => true, + ); + // Template cache private $templates = array(); @@ -44,6 +49,7 @@ class Mustache_Engine private $charset = 'UTF-8'; private $logger; private $strictCallables = false; + private $pragmas = array(); // Services private $tokenizer; @@ -110,6 +116,10 @@ class Mustache_Engine * // helps protect against arbitrary code execution when user input is passed directly into the template. * // This currently defaults to false, but will default to true in v3.0. * 'strict_callables' => true, + * + * // Enable pragmas across all templates, regardless of the presence of pragma tags in the individual + * // templates. + * 'pragmas' => [Mustache_Engine::PRAGMA_FILTERS], * ); * * @throws Mustache_Exception_InvalidArgumentException If `escape` option is not callable. @@ -176,6 +186,15 @@ class Mustache_Engine if (isset($options['strict_callables'])) { $this->strictCallables = $options['strict_callables']; } + + if (isset($options['pragmas'])) { + foreach ($options['pragmas'] as $pragma) { + if (!isset(self::$knownPragmas[$pragma])) { + throw new Mustache_Exception_InvalidArgumentException(sprintf('Unknown pragma: "%s".', $pragma)); + } + $this->pragmas[$pragma] = true; + } + } } /** @@ -226,6 +245,16 @@ class Mustache_Engine return $this->charset; } + /** + * Get the current globally enabled pragmas. + * + * @return array + */ + public function getPragmas() + { + return array_keys($this->pragmas); + } + /** * Set the Mustache template Loader instance. * @@ -563,12 +592,13 @@ class Mustache_Engine public function getTemplateClassName($source) { return $this->templateClassPrefix . md5(sprintf( - 'version:%s,escape:%s,entity_flags:%i,charset:%s,strict_callables:%s,source:%s', + 'version:%s,escape:%s,entity_flags:%i,charset:%s,strict_callables:%s,pragmas:%s,source:%s', self::VERSION, isset($this->escape) ? 'custom' : 'default', $this->entityFlags, $this->charset, $this->strictCallables ? 'true' : 'false', + implode(' ', array_keys($this->pragmas)), $source )); } @@ -705,7 +735,10 @@ class Mustache_Engine */ private function parse($source) { - return $this->getParser()->parse($this->tokenize($source)); + $parser = $this->getParser(); + $parser->setPragmas($this->getPragmas()); + + return $parser->parse($this->tokenize($source)); } /** @@ -728,7 +761,10 @@ class Mustache_Engine array('className' => $name) ); - return $this->getCompiler()->compile($source, $tree, $name, isset($this->escape), $this->charset, $this->strictCallables, $this->entityFlags); + $compiler = $this->getCompiler(); + $compiler->setPragmas($this->getPragmas()); + + return $compiler->compile($source, $tree, $name, isset($this->escape), $this->charset, $this->strictCallables, $this->entityFlags); } /** diff --git a/src/Mustache/Parser.php b/src/Mustache/Parser.php index bea2dcd..a056dfc 100644 --- a/src/Mustache/Parser.php +++ b/src/Mustache/Parser.php @@ -18,6 +18,8 @@ class Mustache_Parser { private $lineNum; private $lineTokens; + private $pragmas; + private $defaultPragmas = array(); /** * Process an array of Mustache tokens and convert them into a parse tree. @@ -30,10 +32,28 @@ class Mustache_Parser { $this->lineNum = -1; $this->lineTokens = 0; + $this->pragmas = $this->defaultPragmas; return $this->buildTree($tokens); } + /** + * Enable pragmas across all templates, regardless of the presence of pragma + * tags in the individual templates. + * + * @internal Users should set global pragmas in Mustache_Engine, not here :) + * + * @param array $pragmas + */ + public function setPragmas(array $pragmas) + { + $this->pragmas = array(); + foreach ($pragmas as $pragma) { + $this->pragmas[$pragma] = true; + } + $this->defaultPragmas = $this->pragmas; + } + /** * Helper method for recursively building a parse tree. * @@ -121,6 +141,9 @@ class Mustache_Parser break; case Mustache_Tokenizer::T_PRAGMA: + $this->pragmas[$token[Mustache_Tokenizer::NAME]] = true; + // no break + case Mustache_Tokenizer::T_COMMENT: $this->clearStandaloneLines($nodes, $tokens); $nodes[] = $token; diff --git a/test/Mustache/Test/EngineTest.php b/test/Mustache/Test/EngineTest.php index 6904d18..6aca877 100644 --- a/test/Mustache/Test/EngineTest.php +++ b/test/Mustache/Test/EngineTest.php @@ -36,6 +36,7 @@ class Mustache_Test_EngineTest extends Mustache_Test_FunctionalTestCase 'escape' => 'strtoupper', 'entity_flags' => ENT_QUOTES, 'charset' => 'ISO-8859-1', + 'pragmas' => array(Mustache_Engine::PRAGMA_FILTERS), )); $this->assertSame($logger, $mustache->getLogger()); @@ -50,6 +51,7 @@ class Mustache_Test_EngineTest extends Mustache_Test_FunctionalTestCase $this->assertTrue($mustache->hasHelper('bar')); $this->assertFalse($mustache->hasHelper('baz')); $this->assertInstanceOf('Mustache_Cache_FilesystemCache', $mustache->getCache()); + $this->assertEquals(array(Mustache_Engine::PRAGMA_FILTERS), $mustache->getPragmas()); } public static function getFoo() diff --git a/test/Mustache/Test/FiveThree/Functional/EngineTest.php b/test/Mustache/Test/FiveThree/Functional/EngineTest.php new file mode 100644 index 0000000..3c80b2b --- /dev/null +++ b/test/Mustache/Test/FiveThree/Functional/EngineTest.php @@ -0,0 +1,50 @@ + $pragmas, + 'helpers' => $helpers, + )); + + $this->assertEquals($expect, $mustache->render($tpl, $data)); + } + + public function pragmaData() + { + $helpers = array( + 'longdate' => function (\DateTime $value) { + return $value->format('Y-m-d h:m:s'); + } + ); + + $data = array( + 'date' => new DateTime('1/1/2000', new DateTimeZone('UTC')), + ); + + $tpl = '{{ date | longdate }}'; + + return array( + array(array(Mustache_Engine::PRAGMA_FILTERS), $helpers, $data, $tpl, '2000-01-01 12:01:00'), + array(array(), $helpers, $data, $tpl, '' ), + ); + } +}