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

Documentation generated on Wed, 04 Jan 2017 22:57:10 +0100 by phpDocumentor 1.4.3