Permalink
Browse files

Feature to allow that changing the SSTemplateParser through the Injec…

…tor system

The motivation for this was to allow module developers to change what parser is used to parse SilverStripe templates.
This change enables people to compile their own version of the SilverStripe template parser and use it without modifying core files.
  • Loading branch information...
1 parent b6c16fc commit ac418ce99e3efe242615660a02f15baecfab5dfd @camspiers camspiers committed Oct 17, 2013
Showing with 102 additions and 39 deletions.
  1. +7 −0 i18n/i18nTextCollector.php
  2. +21 −15 view/SSTemplateParser.php
  3. +19 −14 view/SSTemplateParser.php.inc
  4. +36 −10 view/SSViewer.php
  5. +19 −0 view/TemplateParser.php
@@ -634,6 +634,13 @@ class i18nTextCollector_Parser extends SSTemplateParser {
private static $currentEntity = array();
+ public function __construct($string) {
+ $this->string = $string;
+ $this->pos = 0;
+ $this->depth = 0;
+ $this->regexps = array();
+ }
+
public function Translate__construct(&$res) {
self::$currentEntity = array(null,null,null); //start with empty array
}
@@ -65,14 +65,20 @@ function __construct($message, $parser) {
* Angle Bracket: angle brackets "<" and ">" are used to eat whitespace between template elements
* N: eats white space including newlines (using in legacy _t support)
*/
-class SSTemplateParser extends Parser {
+class SSTemplateParser extends Parser implements TemplateParser {
/**
* @var bool - Set true by SSTemplateParser::compileString if the template should include comments intended
* for debugging (template source, included files, etc)
*/
protected $includeDebuggingComments = false;
-
+
+ /**
+ * Override the Parser constructor to change the requirement of setting a string
+ */
+ function __construct() {
+ }
+
/**
* Override the function that constructs the result arrays to also prepare a 'php' item in the array
*/
@@ -1757,7 +1763,7 @@ function Require_Call(&$res, $sub) {
/* CacheBlockArgument:
!( "if " | "unless " )
(
- :DollarMarkedLookup |
+ :DollarMarkedLookup |
:QuotedString |
:Lookup
) */
@@ -4548,7 +4554,8 @@ function Text__finalise(&$res) {
// non-dynamically calculated
$text = preg_replace(
'/href\s*\=\s*\"\#/',
- 'href="\' . (Config::inst()->get(\'SSViewer\', \'rewrite_hash_links\') ? strip_tags( $_SERVER[\'REQUEST_URI\'] ) : "") .
+ 'href="\' . (Config::inst()->get(\'SSViewer\', \'rewrite_hash_links\') ?' .
+ ' strip_tags( $_SERVER[\'REQUEST_URI\'] ) : "") .
\'#',
$text
);
@@ -4563,37 +4570,36 @@ function Text__finalise(&$res) {
/**
* Compiles some passed template source code into the php code that will execute as per the template source.
*
- * @static
* @throws SSTemplateParseException
* @param $string The source of the template
* @param string $templateName The name of the template, normally the filename the template source was loaded from
* @param bool $includeDebuggingComments True is debugging comments should be included in the output
* @return mixed|string The php that, when executed (via include or exec) will behave as per the template source
*/
- static function compileString($string, $templateName = "", $includeDebuggingComments=false) {
+ public function compileString($string, $templateName = "", $includeDebuggingComments=false) {
if (!trim($string)) {
$code = '';
}
else {
- // Construct a parser instance
- $parser = new SSTemplateParser($string);
- $parser->includeDebuggingComments = $includeDebuggingComments;
+ parent::__construct($string);
+
+ $this->includeDebuggingComments = $includeDebuggingComments;
// Ignore UTF8 BOM at begining of string. TODO: Confirm this is needed, make sure SSViewer handles UTF
// (and other encodings) properly
- if(substr($string, 0,3) == pack("CCC", 0xef, 0xbb, 0xbf)) $parser->pos = 3;
+ if(substr($string, 0,3) == pack("CCC", 0xef, 0xbb, 0xbf)) $this->pos = 3;
// Match the source against the parser
- $result = $parser->match_TopTemplate();
- if(!$result) throw new SSTemplateParseException('Unexpected problem parsing template', $parser);
+ $result = $this->match_TopTemplate();
+ if(!$result) throw new SSTemplateParseException('Unexpected problem parsing template', $this);
// Get the result
$code = $result['php'];
}
// Include top level debugging comments if desired
if($includeDebuggingComments && $templateName && stripos($code, "<?xml") === false) {
- $code = $parser->includeDebuggingComments($code, $templateName);
+ $code = $this->includeDebuggingComments($code, $templateName);
}
return $code;
@@ -4640,7 +4646,7 @@ protected function includeDebuggingComments($code, $templateName) {
* @param $template - A file path that contains template source code
* @return mixed|string - The php that, when executed (via include or exec) will behave as per the template source
*/
- static function compileFile($template) {
- return self::compileString(file_get_contents($template), $template);
+ public function compileFile($template) {
+ return $this->compileString(file_get_contents($template), $template);
}
}
@@ -86,14 +86,20 @@ class SSTemplateParseException extends Exception {
* Angle Bracket: angle brackets "<" and ">" are used to eat whitespace between template elements
* N: eats white space including newlines (using in legacy _t support)
*/
-class SSTemplateParser extends Parser {
+class SSTemplateParser extends Parser implements TemplateParser {
/**
* @var bool - Set true by SSTemplateParser::compileString if the template should include comments intended
* for debugging (template source, included files, etc)
*/
protected $includeDebuggingComments = false;
-
+
+ /**
+ * Override the Parser constructor to change the requirement of setting a string
+ */
+ function __construct() {
+ }
+
/**
* Override the function that constructs the result arrays to also prepare a 'php' item in the array
*/
@@ -462,7 +468,7 @@ class SSTemplateParser extends Parser {
CacheBlockArgument:
!( "if " | "unless " )
(
- :DollarMarkedLookup |
+ :DollarMarkedLookup |
:QuotedString |
:Lookup
)
@@ -1018,37 +1024,36 @@ class SSTemplateParser extends Parser {
/**
* Compiles some passed template source code into the php code that will execute as per the template source.
*
- * @static
* @throws SSTemplateParseException
* @param $string The source of the template
* @param string $templateName The name of the template, normally the filename the template source was loaded from
* @param bool $includeDebuggingComments True is debugging comments should be included in the output
* @return mixed|string The php that, when executed (via include or exec) will behave as per the template source
*/
- static function compileString($string, $templateName = "", $includeDebuggingComments=false) {
+ public function compileString($string, $templateName = "", $includeDebuggingComments=false) {
if (!trim($string)) {
$code = '';
}
else {
- // Construct a parser instance
- $parser = new SSTemplateParser($string);
- $parser->includeDebuggingComments = $includeDebuggingComments;
+ parent::__construct($string);
+
+ $this->includeDebuggingComments = $includeDebuggingComments;
// Ignore UTF8 BOM at begining of string. TODO: Confirm this is needed, make sure SSViewer handles UTF
// (and other encodings) properly
- if(substr($string, 0,3) == pack("CCC", 0xef, 0xbb, 0xbf)) $parser->pos = 3;
+ if(substr($string, 0,3) == pack("CCC", 0xef, 0xbb, 0xbf)) $this->pos = 3;
// Match the source against the parser
- $result = $parser->match_TopTemplate();
- if(!$result) throw new SSTemplateParseException('Unexpected problem parsing template', $parser);
+ $result = $this->match_TopTemplate();
+ if(!$result) throw new SSTemplateParseException('Unexpected problem parsing template', $this);
// Get the result
$code = $result['php'];
}
// Include top level debugging comments if desired
if($includeDebuggingComments && $templateName && stripos($code, "<?xml") === false) {
- $code = $parser->includeDebuggingComments($code, $templateName);
+ $code = $this->includeDebuggingComments($code, $templateName);
}
return $code;
@@ -1095,7 +1100,7 @@ class SSTemplateParser extends Parser {
* @param $template - A file path that contains template source code
* @return mixed|string - The php that, when executed (via include or exec) will behave as per the template source
*/
- static function compileFile($template) {
- return self::compileString(file_get_contents($template), $template);
+ public function compileFile($template) {
+ return $this->compileString(file_get_contents($template), $template);
}
}
View
@@ -615,6 +615,11 @@ public static function get_source_file_comments() {
protected $includeRequirements = true;
/**
+ * @var TemplateParser
+ */
+ protected $parser;
+
+ /**
* Create a template from a string instead of a .ss file
*
* @return SSViewer
@@ -691,7 +696,9 @@ public static function current_custom_theme(){
* array('MySpecificPage', 'MyPage', 'Page')
* </code>
*/
- public function __construct($templateList) {
+ public function __construct($templateList, TemplateParser $parser = null) {
+ $this->setParser($parser ?: Injector::inst()->get('SSTemplateParser'));
+
// flush template manifest cache if requested
if (isset($_GET['flush']) && $_GET['flush'] == 'all') {
if(Director::isDev() || Director::is_cli() || Permission::check('ADMIN')) {
@@ -728,7 +735,25 @@ public function __construct($templateList) {
);
}
}
-
+
+ /**
+ * Set the template parser that will be used in template generation
+ * @param \TemplateParser $parser
+ */
+ public function setParser(TemplateParser $parser)
+ {
+ $this->parser = $parser;
+ }
+
+ /**
+ * Returns the parser that is set for template generation
+ * @return \TemplateParser
+ */
+ public function getParser()
+ {
+ return $this->parser;
+ }
+
/**
* Returns true if at least one of the listed templates exists.
*
@@ -970,7 +995,7 @@ public function process($item, $arguments = null, $inheritedScope = null) {
if(!file_exists($cacheFile) || filemtime($cacheFile) < $lastEdited || isset($_GET['flush'])) {
$content = file_get_contents($template);
- $content = SSViewer::parseTemplateContent($content, $template);
+ $content = $this->parseTemplateContent($content, $template);
$fh = fopen($cacheFile,'w');
fwrite($fh, $content);
@@ -983,7 +1008,7 @@ public function process($item, $arguments = null, $inheritedScope = null) {
// through $Content and $Layout placeholders.
foreach(array('Content', 'Layout') as $subtemplate) {
if(isset($this->chosenTemplates[$subtemplate])) {
- $subtemplateViewer = new SSViewer($this->chosenTemplates[$subtemplate]);
+ $subtemplateViewer = new SSViewer($this->chosenTemplates[$subtemplate], $this->parser);
$subtemplateViewer->includeRequirements(false);
$subtemplateViewer->setPartialCacheStore($this->getPartialCacheStore());
@@ -1028,10 +1053,10 @@ public static function execute_template($template, $data, $arguments = null, $sc
return $v->process($data, $arguments, $scope);
}
- public static function parseTemplateContent($content, $template="") {
- return SSTemplateParser::compileString(
- $content,
- $template,
+ public function parseTemplateContent($content, $template="") {
+ return $this->parser->compileString(
+ $content,
+ $template,
Director::isDev() && Config::inst()->get('SSViewer', 'source_file_comments')
);
}
@@ -1079,7 +1104,8 @@ public static function get_base_tag($contentGeneratedSoFar) {
class SSViewer_FromString extends SSViewer {
protected $content;
- public function __construct($content) {
+ public function __construct($content, TemplateParser $parser = null) {
+ $this->setParser($parser ?: Injector::inst()->get('SSTemplateParser'));
$this->content = $content;
}
@@ -1091,7 +1117,7 @@ public function process($item, $arguments = null, $scope = null) {
$arguments = null;
}
- $template = SSViewer::parseTemplateContent($this->content, "string sha1=".sha1($this->content));
+ $template = $this->parseTemplateContent($this->content, "string sha1=".sha1($this->content));
$tmpFile = tempnam(TEMP_FOLDER,"");
$fh = fopen($tmpFile, 'w');
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * This interface needs to be implemented by any template parser that is used in SSViewer
+ *
+ * @package framework
+ * @subpackage view
+ */
+interface TemplateParser {
+ /**
+ * Compiles some passed template source code into the php code that will execute as per the template source.
+ *
+ * @param $string The source of the template
+ * @param string $templateName The name of the template, normally the filename the template source was loaded from
+ * @param bool $includeDebuggingComments True is debugging comments should be included in the output
+ * @return mixed|string The php that, when executed (via include or exec) will behave as per the template source
+ */
+ public function compileString($string, $templateName = "", $includeDebuggingComments = false);
+}

0 comments on commit ac418ce

Please sign in to comment.