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(); 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) { public function Translate__construct(&$res) {
self::$currentEntity = array(null,null,null); //start with empty array 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 * Angle Bracket: angle brackets "<" and ">" are used to eat whitespace between template elements
* N: eats white space including newlines (using in legacy _t support) * 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 * @var bool - Set true by SSTemplateParser::compileString if the template should include comments intended
* for debugging (template source, included files, etc) * for debugging (template source, included files, etc)
*/ */
protected $includeDebuggingComments = false; 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 * 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: /* CacheBlockArgument:
!( "if " | "unless " ) !( "if " | "unless " )
( (
:DollarMarkedLookup | :DollarMarkedLookup |
:QuotedString | :QuotedString |
:Lookup :Lookup
) */ ) */
@ -4548,7 +4554,8 @@ class SSTemplateParser extends Parser {
// non-dynamically calculated // non-dynamically calculated
$text = preg_replace( $text = preg_replace(
'/href\s*\=\s*\"\#/', '/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 $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. * Compiles some passed template source code into the php code that will execute as per the template source.
* *
* @static
* @throws SSTemplateParseException * @throws SSTemplateParseException
* @param $string The source of the template * @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 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 * @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 * @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)) { if (!trim($string)) {
$code = ''; $code = '';
} }
else { else {
// Construct a parser instance parent::__construct($string);
$parser = new SSTemplateParser($string);
$parser->includeDebuggingComments = $includeDebuggingComments; $this->includeDebuggingComments = $includeDebuggingComments;
// Ignore UTF8 BOM at begining of string. TODO: Confirm this is needed, make sure SSViewer handles UTF // Ignore UTF8 BOM at begining of string. TODO: Confirm this is needed, make sure SSViewer handles UTF
// (and other encodings) properly // (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 // Match the source against the parser
$result = $parser->match_TopTemplate(); $result = $this->match_TopTemplate();
if(!$result) throw new SSTemplateParseException('Unexpected problem parsing template', $parser); if(!$result) throw new SSTemplateParseException('Unexpected problem parsing template', $this);
// Get the result // Get the result
$code = $result['php']; $code = $result['php'];
@ -4593,7 +4599,7 @@ class SSTemplateParser extends Parser {
// Include top level debugging comments if desired // Include top level debugging comments if desired
if($includeDebuggingComments && $templateName && stripos($code, "<?xml") === false) { if($includeDebuggingComments && $templateName && stripos($code, "<?xml") === false) {
$code = $parser->includeDebuggingComments($code, $templateName); $code = $this->includeDebuggingComments($code, $templateName);
} }
return $code; return $code;
@ -4640,7 +4646,7 @@ class SSTemplateParser extends Parser {
* @param $template - A file path that contains template source code * @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 * @return mixed|string - The php that, when executed (via include or exec) will behave as per the template source
*/ */
static function compileFile($template) { public function compileFile($template) {
return self::compileString(file_get_contents($template), $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 * Angle Bracket: angle brackets "<" and ">" are used to eat whitespace between template elements
* N: eats white space including newlines (using in legacy _t support) * 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 * @var bool - Set true by SSTemplateParser::compileString if the template should include comments intended
* for debugging (template source, included files, etc) * for debugging (template source, included files, etc)
*/ */
protected $includeDebuggingComments = false; 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 * 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: CacheBlockArgument:
!( "if " | "unless " ) !( "if " | "unless " )
( (
:DollarMarkedLookup | :DollarMarkedLookup |
:QuotedString | :QuotedString |
:Lookup :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. * Compiles some passed template source code into the php code that will execute as per the template source.
* *
* @static
* @throws SSTemplateParseException * @throws SSTemplateParseException
* @param $string The source of the template * @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 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 * @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 * @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)) { if (!trim($string)) {
$code = ''; $code = '';
} }
else { else {
// Construct a parser instance parent::__construct($string);
$parser = new SSTemplateParser($string);
$parser->includeDebuggingComments = $includeDebuggingComments; $this->includeDebuggingComments = $includeDebuggingComments;
// Ignore UTF8 BOM at begining of string. TODO: Confirm this is needed, make sure SSViewer handles UTF // Ignore UTF8 BOM at begining of string. TODO: Confirm this is needed, make sure SSViewer handles UTF
// (and other encodings) properly // (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 // Match the source against the parser
$result = $parser->match_TopTemplate(); $result = $this->match_TopTemplate();
if(!$result) throw new SSTemplateParseException('Unexpected problem parsing template', $parser); if(!$result) throw new SSTemplateParseException('Unexpected problem parsing template', $this);
// Get the result // Get the result
$code = $result['php']; $code = $result['php'];
@ -1048,7 +1053,7 @@ class SSTemplateParser extends Parser {
// Include top level debugging comments if desired // Include top level debugging comments if desired
if($includeDebuggingComments && $templateName && stripos($code, "<?xml") === false) { if($includeDebuggingComments && $templateName && stripos($code, "<?xml") === false) {
$code = $parser->includeDebuggingComments($code, $templateName); $code = $this->includeDebuggingComments($code, $templateName);
} }
return $code; return $code;
@ -1095,7 +1100,7 @@ class SSTemplateParser extends Parser {
* @param $template - A file path that contains template source code * @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 * @return mixed|string - The php that, when executed (via include or exec) will behave as per the template source
*/ */
static function compileFile($template) { public function compileFile($template) {
return self::compileString(file_get_contents($template), $template); return $this->compileString(file_get_contents($template), $template);
} }
} }

View File

@ -614,6 +614,11 @@ class SSViewer {
*/ */
protected $includeRequirements = true; protected $includeRequirements = true;
/**
* @var TemplateParser
*/
protected $parser;
/** /**
* Create a template from a string instead of a .ss file * Create a template from a string instead of a .ss file
* *
@ -691,7 +696,9 @@ class SSViewer {
* array('MySpecificPage', 'MyPage', 'Page') * array('MySpecificPage', 'MyPage', 'Page')
* </code> * </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 // flush template manifest cache if requested
if (isset($_GET['flush']) && $_GET['flush'] == 'all') { if (isset($_GET['flush']) && $_GET['flush'] == 'all') {
if(Director::isDev() || Director::is_cli() || Permission::check('ADMIN')) { 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. * 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'])) { if(!file_exists($cacheFile) || filemtime($cacheFile) < $lastEdited || isset($_GET['flush'])) {
$content = file_get_contents($template); $content = file_get_contents($template);
$content = SSViewer::parseTemplateContent($content, $template); $content = $this->parseTemplateContent($content, $template);
$fh = fopen($cacheFile,'w'); $fh = fopen($cacheFile,'w');
fwrite($fh, $content); fwrite($fh, $content);
@ -983,7 +1008,7 @@ class SSViewer {
// through $Content and $Layout placeholders. // through $Content and $Layout placeholders.
foreach(array('Content', 'Layout') as $subtemplate) { foreach(array('Content', 'Layout') as $subtemplate) {
if(isset($this->chosenTemplates[$subtemplate])) { if(isset($this->chosenTemplates[$subtemplate])) {
$subtemplateViewer = new SSViewer($this->chosenTemplates[$subtemplate]); $subtemplateViewer = new SSViewer($this->chosenTemplates[$subtemplate], $this->parser);
$subtemplateViewer->includeRequirements(false); $subtemplateViewer->includeRequirements(false);
$subtemplateViewer->setPartialCacheStore($this->getPartialCacheStore()); $subtemplateViewer->setPartialCacheStore($this->getPartialCacheStore());
@ -1028,10 +1053,10 @@ class SSViewer {
return $v->process($data, $arguments, $scope); return $v->process($data, $arguments, $scope);
} }
public static function parseTemplateContent($content, $template="") { public function parseTemplateContent($content, $template="") {
return SSTemplateParser::compileString( return $this->parser->compileString(
$content, $content,
$template, $template,
Director::isDev() && Config::inst()->get('SSViewer', 'source_file_comments') Director::isDev() && Config::inst()->get('SSViewer', 'source_file_comments')
); );
} }
@ -1079,7 +1104,8 @@ class SSViewer {
class SSViewer_FromString extends SSViewer { class SSViewer_FromString extends SSViewer {
protected $content; protected $content;
public function __construct($content) { public function __construct($content, TemplateParser $parser = null) {
$this->setParser($parser ?: Injector::inst()->get('SSTemplateParser'));
$this->content = $content; $this->content = $content;
} }
@ -1091,7 +1117,7 @@ class SSViewer_FromString extends SSViewer {
$arguments = 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,""); $tmpFile = tempnam(TEMP_FOLDER,"");
$fh = fopen($tmpFile, 'w'); $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);
}