Merge pull request #2557 from camspiers/template-parser-configurable

Feature to allow changing the SSTemplateParser used in SSViewer
This commit is contained in:
Ingo Schommer 2013-10-22 17:00:03 -07:00
commit 77696e207a
5 changed files with 102 additions and 39 deletions

View File

@ -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
}

View File

@ -65,14 +65,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
*/
@ -1757,7 +1763,7 @@ class SSTemplateParser extends Parser {
/* CacheBlockArgument:
!( "if " | "unless " )
(
:DollarMarkedLookup |
:DollarMarkedLookup |
:QuotedString |
:Lookup
) */
@ -4548,7 +4554,8 @@ class SSTemplateParser extends Parser {
// 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,29 +4570,28 @@ 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'];
@ -4593,7 +4599,7 @@ class SSTemplateParser extends Parser {
// 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 @@ 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 File

@ -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,29 +1024,28 @@ 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'];
@ -1048,7 +1053,7 @@ class SSTemplateParser extends Parser {
// 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 File

@ -614,6 +614,11 @@ class SSViewer {
*/
protected $includeRequirements = true;
/**
* @var TemplateParser
*/
protected $parser;
/**
* Create a template from a string instead of a .ss file
*
@ -691,7 +696,9 @@ class SSViewer {
* 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 @@ class SSViewer {
);
}
}
/**
* 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 @@ class SSViewer {
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 @@ class SSViewer {
// 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 @@ class SSViewer {
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 @@ class SSViewer {
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 @@ class SSViewer_FromString extends SSViewer {
$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');

19
view/TemplateParser.php Normal file
View File

@ -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);
}