1<?php 2/** 3 * Smarty Internal Plugin Smarty Template Compiler Base 4 * This file contains the basic classes and methods for compiling Smarty templates with lexer/parser 5 * 6 * @package Smarty 7 * @subpackage Compiler 8 * @author Uwe Tews 9 */ 10 11/** 12 * Class SmartyTemplateCompiler 13 * 14 * @package Smarty 15 * @subpackage Compiler 16 */ 17class Smarty_Internal_SmartyTemplateCompiler extends Smarty_Internal_TemplateCompilerBase 18{ 19 /** 20 * Lexer class name 21 * 22 * @var string 23 */ 24 public $lexer_class; 25 26 /** 27 * Parser class name 28 * 29 * @var string 30 */ 31 public $parser_class; 32 33 /** 34 * array of vars which can be compiled in local scope 35 * 36 * @var array 37 */ 38 public $local_var = array(); 39 40 /** 41 * array of callbacks called when the normal compile process of template is finished 42 * 43 * @var array 44 */ 45 public $postCompileCallbacks = array(); 46 47 /** 48 * prefix code 49 * 50 * @var string 51 */ 52 public $prefixCompiledCode = ''; 53 54 /** 55 * postfix code 56 * 57 * @var string 58 */ 59 public $postfixCompiledCode = ''; 60 61 /** 62 * Initialize compiler 63 * 64 * @param string $lexer_class class name 65 * @param string $parser_class class name 66 * @param Smarty $smarty global instance 67 */ 68 public function __construct($lexer_class, $parser_class, Smarty $smarty) 69 { 70 parent::__construct($smarty); 71 // get required plugins 72 $this->lexer_class = $lexer_class; 73 $this->parser_class = $parser_class; 74 } 75 76 /** 77 * method to compile a Smarty template 78 * 79 * @param mixed $_content template source 80 * @param bool $isTemplateSource 81 * 82 * @return bool true if compiling succeeded, false if it failed 83 * @throws \SmartyCompilerException 84 */ 85 protected function doCompile($_content, $isTemplateSource = false) 86 { 87 /* here is where the compiling takes place. Smarty 88 tags in the templates are replaces with PHP code, 89 then written to compiled files. */ 90 // init the lexer/parser to compile the template 91 $this->parser = 92 new $this->parser_class(new $this->lexer_class(str_replace(array("\r\n", "\r"), "\n", $_content), $this), 93 $this); 94 if ($isTemplateSource && $this->template->caching) { 95 $this->parser->insertPhpCode("<?php\n\$_smarty_tpl->compiled->nocache_hash = '{$this->nocache_hash}';\n?>\n"); 96 } 97 if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) { 98 $mbEncoding = mb_internal_encoding(); 99 mb_internal_encoding('ASCII'); 100 } else { 101 $mbEncoding = null; 102 } 103 104 if ($this->smarty->_parserdebug) { 105 $this->parser->PrintTrace(); 106 $this->parser->lex->PrintTrace(); 107 } 108 // get tokens from lexer and parse them 109 while ($this->parser->lex->yylex()) { 110 if ($this->smarty->_parserdebug) { 111 echo "<pre>Line {$this->parser->lex->line} Parsing {$this->parser->yyTokenName[$this->parser->lex->token]} Token " . 112 htmlentities($this->parser->lex->value) . "</pre>"; 113 } 114 $this->parser->doParse($this->parser->lex->token, $this->parser->lex->value); 115 } 116 117 // finish parsing process 118 $this->parser->doParse(0, 0); 119 if ($mbEncoding) { 120 mb_internal_encoding($mbEncoding); 121 } 122 // check for unclosed tags 123 if (count($this->_tag_stack) > 0) { 124 // get stacked info 125 list($openTag, $_data) = array_pop($this->_tag_stack); 126 $this->trigger_template_error("unclosed {$this->smarty->left_delimiter}" . $openTag . 127 "{$this->smarty->right_delimiter} tag"); 128 } 129 // call post compile callbacks 130 foreach ($this->postCompileCallbacks as $cb) { 131 $parameter = $cb; 132 $parameter[0] = $this; 133 call_user_func_array($cb[0], $parameter); 134 } 135 // return compiled code 136 return $this->prefixCompiledCode . $this->parser->retvalue . $this->postfixCompiledCode; 137 } 138 139 /** 140 * Register a post compile callback 141 * - when the callback is called after template compiling the compiler object will be inserted as first parameter 142 * 143 * @param callback $callback 144 * @param array $parameter optional parameter array 145 * @param string $key optional key for callback 146 * @param bool $replace if true replace existing keyed callback 147 */ 148 public function registerPostCompileCallback($callback, $parameter = array(), $key = null, $replace = false) 149 { 150 array_unshift($parameter, $callback); 151 if (isset($key)) { 152 if ($replace || !isset($this->postCompileCallbacks[$key])) { 153 $this->postCompileCallbacks[$key] = $parameter; 154 } 155 } else { 156 $this->postCompileCallbacks[] = $parameter; 157 } 158 } 159 160 /** 161 * Remove a post compile callback 162 * 163 * @param string $key callback key 164 */ 165 public function unregisterPostCompileCallback($key) 166 { 167 unset($this->postCompileCallbacks[$key]); 168 } 169} 170