Source for file jTplCompiler.class.php

Documentation is available at jTplCompiler.class.php

  1. <?php
  2. /**
  3. @package     jelix
  4. @subpackage  jtpl
  5. @author      Laurent Jouanneau
  6. @contributor Loic Mathaud (standalone version), Dominique Papin, DSDenes, Christophe Thiriot, Julien Issler, Brice Tence
  7. @copyright   2005-2012 Laurent Jouanneau
  8. @copyright   2006 Loic Mathaud, 2007 Dominique Papin, 2009 DSDenes, 2010 Christophe Thiriot
  9. @copyright   2010 Julien Issler, 2010 Brice Tence
  10. @link        http://www.jelix.org
  11. @licence     GNU Lesser General Public Licence see LICENCE file or http://www.gnu.org/licenses/lgpl.html
  12. */
  13.  
  14. if (!defined('T_GOTO'))
  15.     define('T_GOTO',333);
  16. if (!defined('T_NAMESPACE'))
  17.     define('T_NAMESPACE',377);
  18. if (!defined('T_USE'))
  19.     define('T_USE',340);
  20.  
  21.  
  22. /**
  23.  * This is the compiler of templates: it converts a template into a php file.
  24.  * @package     jelix
  25.  * @subpackage  jtpl
  26.  */
  27. class jTplCompiler
  28.     implements jISimpleCompiler {
  29.     private $_literals;
  30.  
  31.     /**
  32.      * tokens of variable type
  33.      */
  34.     private  $_vartype array (T_CHARACTERT_CONSTANT_ENCAPSED_STRINGT_DNUMBER,
  35.             T_ENCAPSED_AND_WHITESPACET_LNUMBERT_OBJECT_OPERATORT_STRING,
  36.             T_WHITESPACET_ARRAY);
  37.  
  38.     /**
  39.      * tokens of operators for assignements
  40.      */
  41.     private  $_assignOp array (T_AND_EQUALT_DIV_EQUALT_MINUS_EQUAL,
  42.             T_MOD_EQUALT_MUL_EQUALT_OR_EQUALT_PLUS_EQUALT_PLUS_EQUAL,
  43.             T_SL_EQUALT_SR_EQUALT_XOR_EQUAL);
  44.  
  45.     /**
  46.      * tokens of operators for tests
  47.      */
  48.     private  $_op array (T_BOOLEAN_ANDT_BOOLEAN_ORT_EMPTYT_INCT_DEC,
  49.             T_ISSETT_IS_EQUALT_IS_GREATER_OR_EQUALT_IS_IDENTICAL,
  50.             T_IS_NOT_EQUALT_IS_NOT_IDENTICALT_IS_SMALLER_OR_EQUAL,
  51.             T_LOGICAL_ANDT_LOGICAL_ORT_LOGICAL_XORT_SRT_SL,
  52.             T_DOUBLE_ARROW);
  53.  
  54.     /**
  55.      * tokens authorized into locale names
  56.      */
  57.     private $_inLocaleOk array (T_STRINGT_ABSTRACTT_AST_BREAKT_CASE,
  58.             T_CATCHT_CLASST_CLONET_CONSTT_CONTINUET_DECLARET_DEFAULT,
  59.             T_DNUMBERT_DOT_ECHOT_ELSET_ELSEIFT_EMPTYT_ENDIFT_ENDFOR,
  60.             T_EVALT_EXITT_EXTENDST_FINALT_FORT_FOREACHT_FUNCTION,
  61.             T_GLOBALT_GOTOT_IFT_IMPLEMENTST_INCLUDET_INSTANCEOFT_INTERFACE,
  62.             T_LISTT_LNUMBERT_LOGICAL_ANDT_LOGICAL_ORT_LOGICAL_XOR,
  63.             T_NAMESPACET_NEWT_PRINTT_PRIVATET_PUBLICT_PROTECTEDT_REQUIRE,
  64.             T_RETURNT_STATICT_SWITCHT_THROWT_TRYT_USET_VART_WHILE);
  65.  
  66.     /**
  67.      * tokens allowed in output for variables
  68.      */
  69.     protected $_allowedInVar;
  70.  
  71.     /**
  72.      * tokens allowed into expressions
  73.      */
  74.     protected $_allowedInExpr;
  75.  
  76.     /**
  77.      * tokens allowed into assignements
  78.      */
  79.     protected $_allowedAssign;
  80.  
  81.     /**
  82.      * tokens allowed in foreach statements
  83.      */
  84.     protected $_allowedInForeach;
  85.  
  86.     /**
  87.      * tokens not allowed in variable
  88.      */
  89.     protected $_excludedInVar = array (';','=');
  90.  
  91.     protected $_allowedConstants = array ('TRUE','FALSE','NULL''M_1_PI',
  92.             'M_2_PI''M_2_SQRTPI''M_E''M_LN10''M_LN2''M_LOG10E',
  93.             'M_LOG2E''M_PI','M_PI_2','M_PI_4','M_SQRT1_2','M_SQRT2');
  94.  
  95.     /**
  96.      * list of plugins paths
  97.      */
  98.     private $_pluginPath array();
  99.  
  100.     protected $_metaBody = '';
  101.  
  102.     /**
  103.      * native modifiers
  104.      */
  105.     protected $_modifier = array ('upper'=>'strtoupper''lower'=>'strtolower',
  106.             'escxml'=>'htmlspecialchars''eschtml'=>'htmlspecialchars',
  107.             'strip_tags'=>'strip_tags''escurl'=>'rawurlencode',
  108.             'capitalize'=>'ucwords''stripslashes'=>'stripslashes',
  109.             'upperfirst'=>'ucfirst');
  110.  
  111.     /**
  112.      * stack of founded blocks
  113.      */
  114.     private $_blockStack array ();
  115.  
  116.     /**
  117.      * name of the template file
  118.      */
  119.     private $_sourceFile;
  120.  
  121.     /**
  122.      * current parsed jtpl tag
  123.      */
  124.     private $_currentTag;
  125.  
  126.     /**
  127.      * type of the output
  128.      */
  129.     public $outputType = '';
  130.  
  131.     /**
  132.      * true if the template doesn't come from an untrusted source.
  133.      * if it comes from an untrusted source, like a template uploaded by a user,
  134.      * you should set to false.
  135.      */
  136.     public $trusted = true;
  137.  
  138.     /**
  139.      * list of user functions
  140.      */
  141.     protected $_userFunctions = array ();
  142.  
  143.     protected $escapePI = false;
  144.  
  145.     protected $removeASPtags = true;
  146.  
  147.     /**
  148.      * Initialize some properties
  149.      */
  150.     function __construct ({
  151.         $this->_allowedInVar = array_merge($this->_vartypearray(T_INCT_DECT_DOUBLE_ARROW));
  152.         $this->_allowedInExpr = array_merge($this->_vartype$this->_op);
  153.         $this->_allowedAssign = array_merge($this->_vartype$this->_assignOp$this->_op);
  154.         $this->_allowedInForeach = array_merge($this->_vartypearray(T_AST_DOUBLE_ARROW));
  155.  
  156.         $this->escapePI = (ini_get("short_open_tag"== "1");
  157.         $this->removeASPtags = (ini_get("asp_tags"== "1");
  158.  
  159.     }
  160.  
  161.     /**
  162.      * Launch the compilation of a template
  163.      *
  164.      * Store the result (a php content) into a cache file given by the selector.
  165.      * @param jSelectorTpl $selector the template selector
  166.      * @return boolean true if ok
  167.      */
  168.     public function compile ($selector{
  169.         $this->_sourceFile $selector->getPath();
  170.         $this->outputType = $selector->outputType;
  171.         $this->trusted = $selector->trusted;
  172.         $md5 md5($selector->module.'_'.$selector->resource.'_'.$this->outputType.($this->trusted?'_t':''));
  173.  
  174.         jContext::push($selector->module);
  175.  
  176.         if (!file_exists($this->_sourceFile)) {
  177.             $this->doError0('errors.tpl.not.found');
  178.         }
  179.  
  180.         $this->compileString(file_get_contents($this->_sourceFile)$selector->getCompiledFilePath(),
  181.             $selector->userModifiers$selector->userFunctions$md5);
  182.  
  183.         jContext::pop();
  184.         return true;
  185.     }
  186.  
  187.     public function compileString($templatecontent$cachefile$userModifiers$userFunctions$md5{
  188.         $this->_modifier = array_merge($this->_modifier$userModifiers);
  189.         $this->_userFunctions = $userFunctions;
  190.  
  191.         $result $this->compileContent($templatecontent);
  192.  
  193.         $header "<?php \n";
  194.         foreach ($this->_pluginPath as $path=>$ok{
  195.             $header.=' require_once(\''.$path."');\n";
  196.         }
  197.         $header.='function template_meta_'.$md5.'($t){';
  198.         $header .="\n".$this->_metaBody."\n}\n";
  199.  
  200.         $header.='function template_'.$md5.'($t){'."\n?>";
  201.         $result $header.$result."<?php \n}\n?>";
  202.  
  203.         jFile::write($cachefile$result);
  204.  
  205.         return true;
  206.     }
  207.  
  208.     protected function _piCallback($matches{
  209.         return '<?php echo \''.str_replace("'","\\'",$matches[1]).'\'?>';
  210.     }
  211.  
  212.  
  213.     protected function compileContent ($tplcontent{
  214.         $this->_metaBody = '';
  215.         $this->_blockStack array();
  216.  
  217.         // we remove all php tags
  218.         $tplcontent preg_replace("!<\?((?:php|=|\s).*)\?>!s"''$tplcontent);
  219.         // we remove all template comments
  220.         $tplcontent preg_replace("!{\*(.*?)\*}!s"''$tplcontent);
  221.  
  222.         if ($this->escapePI{
  223.             $tplcontent preg_replace_callback("!(<\?.*\?>)!sm"array($this,'_piCallback')$tplcontent);
  224.         }
  225.         if ($this->removeASPtags{
  226.           // we remove all asp tags
  227.           $tplcontent preg_replace("!<%.*%>!s"''$tplcontent);
  228.         }
  229.  
  230.         preg_match_all("!{literal}(.*?){/literal}!s"$tplcontent$_match);
  231.  
  232.         $this->_literals $_match[1];
  233.  
  234.         $tplcontent preg_replace("!{literal}(.*?){/literal}!s"'{literal}'$tplcontent);
  235.  
  236.         $tplcontent preg_replace_callback("/{((.).*?)}(\n)/sm"array($this,'_callbackLineFeed')$tplcontent);
  237.         $tplcontent preg_replace_callback("/{((.).*?)}/sm"array($this,'_callback')$tplcontent);
  238.  
  239.         /*$tplcontent = preg_replace('/\?>\n?<\?php/', '', $tplcontent);*/
  240.         $tplcontent preg_replace('/<\?php\\s+\?>/'''$tplcontent);
  241.  
  242.         if (count($this->_blockStack))
  243.             $this->doError1('errors.tpl.tag.block.end.missing'end($this->_blockStack));
  244.  
  245.         return $tplcontent;
  246.     }
  247.  
  248.     /**
  249.      * function called during the parsing of the template by a preg_replace_callback function
  250.      * It is called to add line feeds where needed
  251.      * @param array $matches a matched item
  252.      * @return string the same tag with one more line feed
  253.      */
  254.     public function _callbackLineFeed($matches){
  255.         list($full, , $firstcar$lastcar$matches;
  256.         if ($firstcar == '=' || $firstcar == '$' || $firstcar == '@'{
  257.             return "$full\n";
  258.         }
  259.         else return $full;
  260.     }
  261.  
  262.     /**
  263.      * function called during the parsing of the template by a preg_replace_callback function
  264.      * It is called on each template tag {xxxx }
  265.      * @param array $matches a matched item
  266.      * @return string the corresponding php code of the tag (with php tag).
  267.      */
  268.     public function _callback ($matches{
  269.         list(,$tag$firstcar$matches;
  270.  
  271.         // check the first character
  272.         if (!preg_match('/^\$|@|=|[a-zA-Z\/]$/',$firstcar)) {
  273.             throw new jException('jelix~errors.tpl.tag.syntax.invalid',array($tag,$this->_sourceFile));
  274.         }
  275.  
  276.         $this->_currentTag $tag;
  277.         if ($firstcar == '='{
  278.             return  '<?php echo '.$this->_parseVariable(substr($tag,1)).'; ?>';
  279.         else if ($firstcar == '$' || $firstcar == '@'{
  280.             return  '<?php echo '.$this->_parseVariable($tag).'; ?>';
  281.         else {
  282.             if (!preg_match('/^(\/?[a-zA-Z0-9_]+)(?:(?:\s+(.*))|(?:\((.*)\)))?$/ms',$tag,$m)) {
  283.                 throw new jException('jelix~errors.tpl.tag.function.invalid',array($tag,$this->_sourceFile));
  284.             }
  285.             if (count($m== 4{
  286.                 $m[2$m[3];
  287.             }
  288.             if (!isset($m[2])) $m[2]='';
  289.             if ($m[1== 'ldelim'return '{';
  290.             if ($m[1== 'rdelim'return '}';
  291.             return '<?php '.$this->_parseFunction($m[1],$m[2]).'?>';
  292.         }
  293.     }
  294.  
  295.     /**
  296.     * analyse an "echo" tag : {$..} or {@..} 
  297.     * @param string $expr the content of the tag
  298.     * @return string the corresponding php instruction
  299.     */
  300.     protected function _parseVariable ($expr{
  301.         $tok explode('|',$expr);
  302.         $res $this->_parseFinal(array_shift($tok),$this->_allowedInVar$this->_excludedInVar);
  303.  
  304.         foreach ($tok as $modifier{
  305.             if (!preg_match('/^(\w+)(?:\:(.*))?$/',$modifier,$m)) {
  306.                 $this->doError2('errors.tpl.tag.modifier.invalid',$this->_currentTag$modifier);
  307.             }
  308.  
  309.             if (isset($m[2])) {
  310.                 $targs $this->_parseFinal($m[2],$this->_allowedInVar$this->_excludedInVartrue',',':');
  311.                 array_unshift($targs$res);
  312.             else {
  313.                 $targs array($res);
  314.             }
  315.  
  316.             if ($path $this->_getPlugin('cmodifier',$m[1])) {
  317.                 require_once($path[0]);
  318.                 $fct $path[1];
  319.                 $res $fct($this,$targs);
  320.  
  321.             else if ($path $this->_getPlugin('modifier',$m[1])) {
  322.                 $res $path[1].'('.implode(',',$targs).')';
  323.                 $this->_pluginPath[$path[0]] true;
  324.  
  325.             else {
  326.                 if (isset($this->_modifier[$m[1]])) {
  327.                     $res $this->_modifier[$m[1]].'('.$res.')';
  328.                 else {
  329.                     $this->doError2('errors.tpl.tag.modifier.unknown',$this->_currentTag$m[1]);
  330.                 }
  331.             }
  332.         }
  333.         return $res;
  334.     }
  335.  
  336.     /**
  337.      * analyse the tag which have a name
  338.      * @param string $name the name of the tag
  339.      * @param string $args the content that follow the name in the tag
  340.      * @return string the corresponding php instructions
  341.      */
  342.     protected function _parseFunction ($name$args{
  343.         $res='';
  344.         switch ($name{
  345.             case 'if':
  346.                 $res 'if('.$this->_parseFinal($args,$this->_allowedInExpr).'):';
  347.                 array_push($this->_blockStack,'if');
  348.                 break;
  349.  
  350.             case 'else':
  351.                 if (substr(end($this->_blockStack),0,2!='if')
  352.                     $this->doError1('errors.tpl.tag.block.end.missing'end($this->_blockStack));
  353.                 else
  354.                     $res 'else:';
  355.                 break;
  356.  
  357.             case 'elseif':
  358.                 if (end($this->_blockStack!='if')
  359.                     $this->doError1('errors.tpl.tag.block.end.missing'end($this->_blockStack));
  360.                 else
  361.                     $res 'elseif('.$this->_parseFinal($args,$this->_allowedInExpr).'):';
  362.                 break;
  363.  
  364.             case 'foreach':
  365.                 if ($this->trusted)
  366.                     $notallowed array(';','!');
  367.                 else
  368.                     $notallowed array(';','!','(');
  369.  
  370.                 if (preg_match("/^\s*\((.*)\)\s*$/",$args$m))
  371.                    $args $m[1];
  372.  
  373.                 $res 'foreach('.$this->_parseFinal($args,$this->_allowedInForeach$notallowed).'):';
  374.                 array_push($this->_blockStack,'foreach');
  375.                 break;
  376.  
  377.             case 'while':
  378.                 $res 'while('.$this->_parseFinal($args,$this->_allowedInExpr).'):';
  379.                 array_push($this->_blockStack,'while');
  380.                 break;
  381.  
  382.             case 'for':
  383.                 if ($this->trusted)
  384.                     $notallowed array();
  385.                 else
  386.                     $notallowed array('(');
  387.                 if (preg_match("/^\s*\((.*)\)\s*$/",$args$m))
  388.                    $args $m[1];
  389.                 $res 'for('$this->_parseFinal($args$this->_allowedInExpr$notallowed.'):';
  390.                 array_push($this->_blockStack,'for');
  391.                 break;
  392.  
  393.             case '/foreach':
  394.             case '/for':
  395.             case '/if':
  396.             case '/while':
  397.                 $short substr($name,1);
  398.                 if (end($this->_blockStack!=$short{
  399.                     $this->doError1('errors.tpl.tag.block.end.missing'end($this->_blockStack));
  400.                 else {
  401.                     array_pop($this->_blockStack);
  402.                     $res='end'.$short.';';
  403.                 }
  404.                 break;
  405.  
  406.             case 'assign':
  407.             case 'eval':
  408.                 $res $this->_parseFinal($args,$this->_allowedAssign).';';
  409.                 break;
  410.  
  411.             case 'literal':
  412.                 if (count($this->_literals))
  413.                     $res '?>'.array_shift($this->_literals).'<?php ';
  414.                 else
  415.                     $this->doError1('errors.tpl.tag.block.end.missing','literal');
  416.                 break;
  417.  
  418.             case '/literal':
  419.                 $this->doError1('errors.tpl.tag.block.begin.missing','literal');
  420.                 break;
  421.  
  422.             case 'meta':
  423.                 $this->_parseMeta($args);
  424.                 break;
  425.  
  426.             case 'meta_if':
  427.                 $metaIfArgs $this->_parseFinal($args,$this->_allowedInExpr);
  428.                 $this->_metaBody .= 'if('.$metaIfArgs.'):'."\n";
  429.                 array_push($this->_blockStack,'meta_if');
  430.                 break;
  431.  
  432.             case 'meta_else':
  433.                 if (substr(end($this->_blockStack),0,7!='meta_if'{
  434.                     $this->doError1('errors.tpl.tag.block.end.missing'end($this->_blockStack));
  435.                 else {
  436.                     $this->_metaBody .= "else:\n";
  437.                 }
  438.                 break;
  439.  
  440.             case 'meta_elseif':
  441.                 if (end($this->_blockStack!='meta_if'{
  442.                     $this->doError1('errors.tpl.tag.block.end.missing'end($this->_blockStack));
  443.                 else {
  444.                     $elseIfArgs $this->_parseFinal($args,$this->_allowedInExpr);
  445.                     $this->_metaBody .= 'elseif('.$elseIfArgs."):\n";
  446.                 }
  447.                 break;
  448.  
  449.             case '/meta_if':
  450.                 $short substr($name,1);
  451.                 if (end($this->_blockStack!= $short{
  452.                     $this->doError1('errors.tpl.tag.block.end.missing'end($this->_blockStack));
  453.                 else {
  454.                     array_pop($this->_blockStack);
  455.                     $this->_metaBody .= "endif;\n";
  456.                 }
  457.                 break;
  458.  
  459.             default:
  460.                 if (preg_match('!^/(\w+)$!',$name,$m)) {
  461.                     if (end($this->_blockStack!=$m[1]{
  462.                         $this->doError1('errors.tpl.tag.block.end.missing',end($this->_blockStack));
  463.                     else {
  464.                         array_pop($this->_blockStack);
  465.                         if (function_exists($fct 'jtpl_block_'.$this->outputType.'_'.$m[1])) {
  466.                             $res $fct($this,false,null);
  467.                         else if(function_exists($fct 'jtpl_block_common_'.$m[1])) {
  468.                             $res $fct($this,false,null);
  469.                         else
  470.                             $this->doError1('errors.tpl.tag.block.begin.missing',$m[1]);
  471.                     }
  472.  
  473.                 else if(preg_match('/^meta_(\w+)$/',$name,$m)) {
  474.                      if ($path $this->_getPlugin('meta',$m[1])) {
  475.                         $this->_parseMeta($args,$path[1]);
  476.                         $this->_pluginPath[$path[0]] true;
  477.                     else {
  478.                         $this->doError1('errors.tpl.tag.meta.unknown',$m[1]);
  479.                     }
  480.                     $res='';
  481.  
  482.                 else if ($path $this->_getPlugin('block',$name)) {
  483.                     require_once($path[0]);
  484.                     $argfct $this->_parseFinal($args,$this->_allowedAssignarray(';'),true);
  485.                     $fct $path[1];
  486.                     $res $fct($this,true,$argfct);
  487.                     array_push($this->_blockStack,$name);
  488.  
  489.                 else if ($path $this->_getPlugin('cfunction',$name)) {
  490.                     require_once($path[0]);
  491.                     $argfct $this->_parseFinal($args,$this->_allowedAssignarray(';'),true);
  492.                     $fct $path[1];
  493.                     $res $fct($this,$argfct);
  494.  
  495.                 else if ($path $this->_getPlugin('function',$name)) {
  496.                     $argfct $this->_parseFinal($args,$this->_allowedAssign);
  497.                     $res $path[1].'( $t'.(trim($argfct)!=''?','.$argfct:'').');';
  498.                     $this->_pluginPath[$path[0]] true;
  499.  
  500.                 else if (isset($this->_userFunctions[$name])) {
  501.                     $argfct $this->_parseFinal($args,$this->_allowedAssign);
  502.                     $res $this->_userFunctions[$name].'( $t'.(trim($argfct)!=''?','.$argfct:'').');';
  503.  
  504.                 else {
  505.                     $this->doError1('errors.tpl.tag.function.unknown',$name);
  506.                 }
  507.         }
  508.         return $res;
  509.     }
  510.  
  511.     /**
  512.      * for plugins, it says if the plugin is inside the given block
  513.      * @param string $blockName the block to search
  514.      * @param boolean $onlyUpper check only the upper block
  515.      * @return boolean  true if it is inside the block
  516.      */
  517.     public function isInsideBlock ($blockName$onlyUpper false{
  518.         if ($onlyUpper)
  519.             return (end($this->_blockStack== $blockName);
  520.         for ($i=count($this->_blockStack-1$i>=0$i--{
  521.             if ($this->_blockStack[$i== $blockName)
  522.                 return true;
  523.         }
  524.         return false;
  525.     }
  526.  
  527.     /**
  528.      * sub-function which analyse an expression
  529.      * @param string $string the expression
  530.      * @param array $allowed list of allowed php token
  531.      * @param array $exceptchar list of forbidden characters
  532.      * @param boolean $splitArgIntoArray true: split the results on coma
  533.      * @return array|string
  534.      */
  535.     protected function _parseFinal ($string$allowed array()$exceptchar array(';'),
  536.                                     $splitArgIntoArray false$sep1 ','$sep2 ','{
  537.         $tokens token_get_all('<?php '.$string.'?>');
  538.  
  539.         $results array();
  540.         $result ='';
  541.         $first true;
  542.         $inLocale false;
  543.         $locale '';
  544.         $bracketcount $sqbracketcount 0;
  545.         $firstok array_shift($tokens);
  546.  
  547.         // there is a bug, sometimes the first token isn't T_OPEN_TAG...
  548.         if ($firstok == '<' && $tokens[0== '?' && is_array($tokens[1])
  549.             && $tokens[1][0== T_STRING && $tokens[1][1== 'php'{
  550.             array_shift($tokens);
  551.             array_shift($tokens);
  552.         }
  553.  
  554.         $previousTok null;
  555.  
  556.         foreach ($tokens as $tok{
  557.             if (is_array($tok)) {
  558.                 list($type,$str$tok;
  559.                 $first false;
  560.                 if ($type == T_CLOSE_TAG{
  561.                     $previousTok $tok;
  562.                     continue;
  563.                 }
  564.                 if ($inLocale && in_array($type,$this->_inLocaleOk)) {
  565.                     $locale .= $str;
  566.                 elseif ($type == T_VARIABLE && $inLocale{
  567.                     $locale .= '\'.$t->_vars[\''.substr($str1).'\'].\'';
  568.                 elseif ($type == T_VARIABLE){
  569.                     if (is_array($previousTok&& $previousTok[0== T_OBJECT_OPERATOR)
  570.                         $result .= '{$t->_vars[\''.substr($str1).'\']}';
  571.                     else
  572.                         $result .= '$t->_vars[\''.substr($str1).'\']';
  573.                 elseif ($type == T_WHITESPACE || in_array($type$allowed)) {
  574.                     if (!$this->trusted && $type == T_STRING && defined($str)
  575.                         && !in_array(strtoupper($str)$this->_allowedConstants)) {
  576.                         $this->doError2('errors.tpl.tag.constant.notallowed'$this->_currentTag$str);
  577.                     }
  578.                     if ($type == T_WHITESPACE)
  579.                         $str preg_replace("/(\s+)/ms"," ",$str);
  580.                     $result .= $str;
  581.                 else {
  582.                     $this->doError2('errors.tpl.tag.phpsyntax.invalid'$this->_currentTag$str);
  583.                 }
  584.             else {
  585.                 if ($tok == '@'{
  586.                     if ($inLocale{
  587.                         $inLocale false;
  588.                         if ($locale == ''{
  589.                             $this->doError1('errors.tpl.tag.locale.invalid'$this->_currentTag);
  590.                         else {
  591.                             $result .= 'jLocale::get(\''.$locale.'\')';
  592.                             $locale '';
  593.                         }
  594.                     else {
  595.                         $inLocale true;
  596.                     }
  597.                 elseif ($inLocale && ($tok == '.' || $tok == '~')) {
  598.                     $locale .= $tok;
  599.                 elseif ($inLocale || in_array($tok$exceptchar)
  600.                           || ($first && $tok != '!' && $tok != '(')) {
  601.                     $this->doError2('errors.tpl.tag.character.invalid'$this->_currentTag$tok);
  602.                 elseif ($tok == '('{
  603.                     $bracketcount++;
  604.                     $result .= $tok;
  605.                 elseif ($tok == ')'{
  606.                     $bracketcount--;
  607.                     $result .= $tok;
  608.                 elseif ($tok == '['{
  609.                     $sqbracketcount++;
  610.                     $result .= $tok;
  611.                 elseif ($tok == ']'{
  612.                     $sqbracketcount--;
  613.                     $result .= $tok;
  614.                 elseif ($splitArgIntoArray && ($tok == $sep1 || $tok == $sep2)
  615.                           && $bracketcount == && $sqbracketcount == 0{
  616.                    $results[$result;
  617.                    $result '';
  618.                 else {
  619.                     $result .= $tok;
  620.                 }
  621.                 $first false;
  622.             }
  623.             $previousTok $tok;
  624.         }
  625.  
  626.         if ($inLocale{
  627.             $this->doError1('errors.tpl.tag.locale.end.missing'$this->_currentTag);
  628.         }
  629.  
  630.         if ($bracketcount != || $sqbracketcount != 0{
  631.             $this->doError1('errors.tpl.tag.bracket.error'$this->_currentTag);
  632.         }
  633.  
  634.         $last end($tokens);
  635.         if (!is_array($last|| $last[0!= T_CLOSE_TAG{
  636.             $this->doError1('errors.tpl.tag.syntax.invalid'$this->_currentTag);
  637.         }
  638.  
  639.         if ($splitArgIntoArray{
  640.             if ($result != ''$results[]=$result;
  641.             return $results;
  642.         else {
  643.             return $result;
  644.         }
  645.     }
  646.  
  647.     protected function _parseMeta ($args$fct ''{
  648.         if (preg_match('/^(\w+)(\s+(.*))?$/'$args$m)) {
  649.             if(isset($m[3]))
  650.                 $argfct $this->_parseFinal($m[3]$this->_allowedInExpr);
  651.             else
  652.                 $argfct 'null';
  653.             if ($fct != ''{
  654.                 $this->_metaBody.= $fct.'( $t,'."'".$m[1]."',".$argfct.");\n";
  655.             else {
  656.                 $this->_metaBody.= "\$t->_meta['".$m[1]."']=".$argfct.";\n";
  657.             }
  658.         else {
  659.             $this->doError1('errors.tpl.tag.meta.invalid'$this->_currentTag);
  660.         }
  661.     }
  662.  
  663.     public function addMetaContent ($content{
  664.         $this->_metaBody .= $content."\n";
  665.     }
  666.  
  667.     /**
  668.      * Try to find a plugin
  669.      * @param string $type type of plugin (function, modifier...)
  670.      * @param string $name the plugin name
  671.      * @return array|booleanan array containing the path of the plugin
  672.      *                       and the name of the plugin function, or false if not found
  673.      */
  674.     protected function _getPlugin ($type$name{
  675.         $foundPath '';
  676.  
  677.         $config jApp::config();
  678.         if (isset($config->{'_tplpluginsPathList_'.$this->outputType})) {
  679.             foreach ($config->{'_tplpluginsPathList_'.$this->outputTypeas $path{
  680.                 $foundPath $path.$type.'.'.$name.'.php';
  681.  
  682.                 if (file_exists($foundPath)) {
  683.                     return array($foundPath'jtpl_'.$type.'_'.$this->outputType.'_'.$name);
  684.                 }
  685.             }
  686.         }
  687.         if (isset($config->_tplpluginsPathList_common)) {
  688.             foreach ($config->_tplpluginsPathList_common as $path{
  689.                 $foundPath $path.$type.'.'.$name.'.php';
  690.                 if (file_exists($foundPath)) {
  691.                     return array($foundPath'jtpl_'.$type.'_common_'.$name);
  692.                 }
  693.             }
  694.         }
  695.         return false;
  696.     }
  697.  
  698.     public function doError0 ($err{
  699.         throw new jException('jelix~'.$err,array($this->_sourceFile));
  700.     }
  701.  
  702.     public function doError1 ($err$arg{
  703.         throw new jException('jelix~'.$err,array($arg$this->_sourceFile));
  704.     }
  705.  
  706.     public function doError2 ($err$arg1$arg2{
  707.         throw new jException('jelix~'.$errarray($arg1$arg2$this->_sourceFile));
  708.     }
  709. }

Documentation generated on Mon, 26 Oct 2015 21:56:39 +0100 by phpDocumentor 1.4.3