|
// +----------------------------------------------------------------------+
//
// $Id$
//
// Base Compiler Class
// Standard 'Original Flavour' Flexy compiler
// this does the main conversion, (eg. for {vars and methods})
// it relays into Compiler/Tag & Compiler/Flexy for tags and namespace handling.
require_once 'HTML/Template/Flexy/Tokenizer.php';
require_once 'HTML/Template/Flexy/Token.php';
class HTML_Template_Flexy_Compiler_Flexy extends HTML_Template_Flexy_Compiler {
/**
* The current template (Full path)
*
* @var string
* @access public
*/
var $currentTemplate;
/**
* The compile method.
*
* @params object HTML_Template_Flexy
* @params string|false string to compile of false to use a file.
* @return string filename of template
* @access public
*/
function compile(&$flexy, $string=false)
{
// read the entire file into one variable
// note this should be moved to new HTML_Template_Flexy_Token
// and that can then manage all the tokens in one place..
global $_HTML_TEMPLATE_FLEXY_COMPILER;
$this->currentTemplate = $flexy->currentTemplate;
$gettextStrings = &$_HTML_TEMPLATE_FLEXY_COMPILER['gettextStrings'];
$gettextStrings = array(); // reset it.
if (@$this->options['debug']) {
echo "compiling template $flexy->currentTemplate
";
}
// reset the elements.
$flexy->_elements = array();
// replace this with a singleton??
$GLOBALS['_HTML_TEMPLATE_FLEXY']['currentOptions'] = $this->options;
$GLOBALS['_HTML_TEMPLATE_FLEXY']['elements'] = array();
$GLOBALS['_HTML_TEMPLATE_FLEXY']['filename'] = $flexy->currentTemplate;
$GLOBALS['_HTML_TEMPLATE_FLEXY']['prefixOutput'] = '';
$GLOBALS['_HTML_TEMPLATE_FLEXY']['compiledTemplate']= $flexy->compiledTemplate;
// initialize Translation 2, and
$this->initializeTranslator();
// load the template!
$data = $string;
$res = false;
if ($string === false) {
$data = file_get_contents($flexy->currentTemplate);
}
// PRE PROCESS {_(.....)} translation markers.
if (strpos($data, '{_(') !== false) {
$data = $this->preProcessTranslation($data);
}
// Tree generation!!!
if (!$this->options['forceCompile'] && isset($_HTML_TEMPLATE_FLEXY_COMPILER['cache'][md5($data)])) {
$res = $_HTML_TEMPLATE_FLEXY_COMPILER['cache'][md5($data)];
} else {
$tokenizer = new HTML_Template_Flexy_Tokenizer($data);
$tokenizer->fileName = $flexy->currentTemplate;
//$tokenizer->debug=1;
$tokenizer->options['ignore_html'] = $this->options['nonHTML'];
require_once 'HTML/Template/Flexy/Token.php';
$res = HTML_Template_Flexy_Token::buildTokens($tokenizer);
if (is_a($res, 'PEAR_Error')) {
return $res;
}
$_HTML_TEMPLATE_FLEXY_COMPILER['cache'][md5($data)] = $res;
}
// technically we shouldnt get here as we dont cache errors..
if (is_a($res, 'PEAR_Error')) {
return $res;
}
// turn tokens into Template..
$data = $res->compile($this);
if (is_a($data, 'PEAR_Error')) {
return $data;
}
$data = $GLOBALS['_HTML_TEMPLATE_FLEXY']['prefixOutput'] . $data;
if ( $flexy->options['debug'] > 1) {
echo "Result:
".htmlspecialchars($data)."
';print_r($matches); // we may need to do some house cleaning here... $_HTML_TEMPLATE_FLEXY_COMPILER['gettextStrings'] = $matches; // replace them now.. // ** leaving in the tag (which should be ignored by the parser.. // we then get rid of the tags during the toString method in this class. foreach($matches as $v) { $data = str_replace('{_('.$v.')_}', '{_('.$this->translateString($v).')_}', $data); } return $data; } /** * Flag indicating compiler is inside {_( .... )_} block, and should not * add to the gettextstrings array. * * @var boolean * @access public */ var $inGetTextBlock = false; /** * This is the base toString Method, it relays into toString{TokenName} * * @param object HTML_Template_Flexy_Token_* * * @return string string to build a template * @access public * @see toString* */ function toString($element) { static $len = 26; // strlen('HTML_Template_Flexy_Token_'); if ($this->options['debug'] > 1) { $x = $element; unset($x->children); //echo htmlspecialchars(print_r($x,true))."
\n"; } if ($element->token == 'GetTextStart') { $this->inGetTextBlock = true; return ''; } if ($element->token == 'GetTextEnd') { $this->inGetTextBlock = false; return ''; } $class = get_class($element); if (strlen($class) >= $len) { $type = substr($class, $len); return $this->{'toString'.$type}($element); } $ret = $element->value; $add = $element->compileChildren($this); if (is_a($add, 'PEAR_Error')) { return $add; } $ret .= $add; if ($element->close) { $add = $element->close->compile($this); if (is_a($add, 'PEAR_Error')) { return $add; } $ret .= $add; } return $ret; } /** * HTML_Template_Flexy_Token_Else toString * * @param object HTML_Template_Flexy_Token_Else * * @return string string to build a template * @access public * @see toString* */ function toStringElse($element) { // pushpull states to make sure we are in an area.. - should really check to see // if the state it is pulling is a if... if ($element->pullState() === false) { return $this->appendHTML( "Unmatched {else:} on line: {$element->line}" ); } $element->pushState(); return $this->appendPhp("} else {"); } /** * HTML_Template_Flexy_Token_End toString * * @param object HTML_Template_Flexy_Token_Else * * @return string string to build a template * @access public * @see toString* */ function toStringEnd($element) { // pushpull states to make sure we are in an area.. - should really check to see // if the state it is pulling is a if... if ($element->pullState() === false) { return $this->appendHTML( "Unmatched {end:} on line: {$element->line}" ); } return $this->appendPhp("}"); } /** * HTML_Template_Flexy_Token_EndTag toString * * @param object HTML_Template_Flexy_Token_EndTag * * @return string string to build a template * @access public * @see toString* */ function toStringEndTag($element) { return $this->toStringTag($element); } /** * HTML_Template_Flexy_Token_Foreach toString * * @param object HTML_Template_Flexy_Token_Foreach * * @return string string to build a template * @access public * @see toString* */ function toStringForeach($element) { $loopon = $element->toVar($element->loopOn); if (is_a($loopon, 'PEAR_Error')) { return $loopon; } $ret = 'if ($this->options[\'strict\'] || ('. 'is_array('. $loopon. ') || ' . 'is_object(' . $loopon . '))) ' . 'foreach(' . $loopon . " "; $ret .= "as \${$element->key}"; if ($element->value) { $ret .= " => \${$element->value}"; } $ret .= ") {"; $element->pushState(); $element->pushVar($element->key); $element->pushVar($element->value); return $this->appendPhp($ret); } /** * HTML_Template_Flexy_Token_If toString * * @param object HTML_Template_Flexy_Token_If * * @return string string to build a template * @access public * @see toString* */ function toStringIf($element) { $var = $element->toVar($element->condition); if (is_a($var, 'PEAR_Error')) { return $var; } $ret = "if (".$element->isNegative . $var .") {"; $element->pushState(); return $this->appendPhp($ret); } /** * get Modifier Wrapper * * converts :h, :u, :r , ..... * @param object HTML_Template_Flexy_Token_Method|Var * * @return array prefix,suffix * @access public * @see toString* */ function getModifierWrapper($element) { $prefix = 'echo '; $suffix = ''; $modifier = strlen(trim($element->modifier)) ? $element->modifier : ' '; switch ($modifier) { case 'h': break; case 'u': $prefix = 'echo urlencode('; $suffix = ')'; break; case 'r': $prefix = 'echo \'\'; echo htmlspecialchars(print_r('; $suffix = ',true)); echo \'\';'; break; case 'n': // blank or value.. $numberformat = @$GLOBALS['_HTML_TEMPLATE_FLEXY']['currentOptions']['numberFormat']; $prefix = 'echo number_format('; $suffix = $GLOBALS['_HTML_TEMPLATE_FLEXY']['currentOptions']['numberFormat'] . ')'; break; case 'b': // nl2br + htmlspecialchars $prefix = 'echo nl2br(htmlspecialchars('; // add language ? $suffix = '))'; break; case 'e': $prefix = 'echo htmlentities('; // add language ? $suffix = ')'; break; case ' ': $prefix = 'echo htmlspecialchars('; // add language ? $suffix = ')'; break; default: $prefix = 'echo $this->plugin("'.trim($element->modifier) .'",'; $suffix = ')'; } return array($prefix, $suffix); } /** * HTML_Template_Flexy_Token_Var toString * * @param object HTML_Template_Flexy_Token_Method * * @return string string to build a template * @access public * @see toString* */ function toStringVar($element) { // ignore modifier at present!! $var = $element->toVar($element->value); if (is_a($var, 'PEAR_Error')) { return $var; } list($prefix, $suffix) = $this->getModifierWrapper($element); return $this->appendPhp( $prefix . $var . $suffix .';'); } /** * HTML_Template_Flexy_Token_Method toString * * @param object HTML_Template_Flexy_Token_Method * * @return string string to build a template * @access public * @see toString* */ function toStringMethod($element) { // set up the modifier at present!! list($prefix, $suffix) = $this->getModifierWrapper($element); // add the '!' to if if ($element->isConditional) { $prefix = 'if ('.$element->isNegative; $element->pushState(); $suffix = ')'; } // check that method exists.. // if (method_exists($object,'method'); $bits = explode('.', $element->method); $method = array_pop($bits); $object = implode('.', $bits); $var = $element->toVar($object); if (is_a($var, 'PEAR_Error')) { return $var; } if (($object == 'GLOBALS') && $GLOBALS['_HTML_TEMPLATE_FLEXY']['currentOptions']['globalfunctions']) { // we should check if they something weird like: GLOBALS.xxxx[sdf](....) $var = $method; } else { $prefix = 'if ($this->options[\'strict\'] || (isset('.$var. ') && method_exists('.$var .", '{$method}'))) " . $prefix; $var = $element->toVar($element->method); } if (is_a($var, 'PEAR_Error')) { return $var; } $ret = $prefix; $ret .= $var . "("; $s =0; foreach($element->args as $a) { if ($s) { $ret .= ","; } $s =1; if ($a{0} == '#') { if (is_numeric(substr($a, 1, -1))) { $ret .= substr($a, 1, -1); } else { $ret .= '"'. addslashes(substr($a, 1, -1)) . '"'; } continue; } $var = $element->toVar($a); if (is_a($var, 'PEAR_Error')) { return $var; } $ret .= $var; } $ret .= ")" . $suffix; if ($element->isConditional) { $ret .= ' { '; } else { $ret .= ";"; } return $this->appendPhp($ret); } /** * HTML_Template_Flexy_Token_Processing toString * * @param object HTML_Template_Flexy_Token_Processing * * @return string string to build a template * @access public * @see toString* */ function toStringProcessing($element) { // if it's XML then quote it.. if (strtoupper(substr($element->value, 2, 3)) == 'XML') { return $this->appendPhp("echo '" . str_replace("'", "\\"."'", $element->value) . "';"); } // otherwise it's PHP code - so echo it.. return $element->value; } /** * HTML_Template_Flexy_Token_Text toString * * @param object HTML_Template_Flexy_Token_Text * * @return string string to build a template * @access public * @see toString* */ function toStringText($element) { // first get rid of stuff thats not translated etc. // empty strings => output. // comments -> just output // our special tags -> output.. if (!strlen(trim($element->value) )) { return $this->appendHtml($element->value); } // dont add comments to translation lists. if (substr($element->value, 0, 4) == '