// +---------------------------------------------------------------------- namespace Think\Template\Driver; use Think\TagLib; /** * CX标签库解析类 * @category Think * @package Think * @subpackage Driver.Taglib * @author liu21st */ class Cx extends TagLib { // 标签定义 protected $tags = array( // 标签定义: attr 属性列表 close 是否闭合(0 或者1 默认1) alias 标签别名 level 嵌套层次 'php' => array(), 'volist' => array('attr'=>'name,id,offset,length,key,mod','level'=>3,'alias'=>'iterate'), 'foreach' => array('attr'=>'name,item,key','level'=>3), 'if' => array('attr'=>'condition','level'=>2), 'elseif' => array('attr'=>'condition','close'=>0), 'else' => array('attr'=>'','close'=>0), 'switch' => array('attr'=>'name','level'=>2), 'case' => array('attr'=>'value,break'), 'default' => array('attr'=>'','close'=>0), 'compare' => array('attr'=>'name,value,type','level'=>3,'alias'=>'eq,equal,notequal,neq,gt,lt,egt,elt,heq,nheq'), 'range' => array('attr'=>'name,value,type','level'=>3,'alias'=>'in,notin,between,notbetween'), 'empty' => array('attr'=>'name','level'=>3), 'notempty' => array('attr'=>'name','level'=>3), 'present' => array('attr'=>'name','level'=>3), 'notpresent'=> array('attr'=>'name','level'=>3), 'defined' => array('attr'=>'name','level'=>3), 'notdefined'=> array('attr'=>'name','level'=>3), 'import' => array('attr'=>'file,href,type,value,basepath','close'=>0,'alias'=>'load,css,js'), 'assign' => array('attr'=>'name,value','close'=>0), 'define' => array('attr'=>'name,value','close'=>0), 'for' => array('attr'=>'start,end,name,comparison,step', 'level'=>3), ); /** * php标签解析 * @access public * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ public function _php($tag,$content) { $parseStr = ''; return $parseStr; } /** * volist标签解析 循环输出数据集 * 格式: * * {user.username} * {user.email} * * @access public * @param array $tag 标签属性 * @param string $content 标签内容 * @return string|void */ public function _volist($tag,$content) { $name = $tag['name']; $id = $tag['id']; $empty = isset($tag['empty'])?$tag['empty']:''; $key = !empty($tag['key'])?$tag['key']:'i'; $mod = isset($tag['mod'])?$tag['mod']:'2'; // 允许使用函数设定数据集 {$vo.name} $parseStr = 'autoBuildVar($name); } $parseStr .= 'if(is_array('.$name.')): $'.$key.' = 0;'; if(isset($tag['length']) && '' !=$tag['length'] ) { $parseStr .= ' $__LIST__ = array_slice('.$name.','.$tag['offset'].','.$tag['length'].',true);'; }elseif(isset($tag['offset']) && '' !=$tag['offset']){ $parseStr .= ' $__LIST__ = array_slice('.$name.','.$tag['offset'].',null,true);'; }else{ $parseStr .= ' $__LIST__ = '.$name.';'; } $parseStr .= 'if( count($__LIST__)==0 ) : echo "'.$empty.'" ;'; $parseStr .= 'else: '; $parseStr .= 'foreach($__LIST__ as $key=>$'.$id.'): '; $parseStr .= '$mod = ($'.$key.' % '.$mod.' );'; $parseStr .= '++$'.$key.';?>'; $parseStr .= ($content); $parseStr .= ''; if(!empty($parseStr)) { return $parseStr; } return ; } /** * foreach标签解析 循环输出数据集 * @access public * @param array $tag 标签属性 * @param string $content 标签内容 * @return string|void */ public function _foreach($tag,$content) { $name = $tag['name']; $item = $tag['item']; $key = !empty($tag['key'])?$tag['key']:'key'; $name = $this->autoBuildVar($name); $parseStr = '$'.$item.'): ?>'; $parseStr .= ($content); $parseStr .= ''; if(!empty($parseStr)) { return $parseStr; } return ; } /** * if标签解析 * 格式: * * * * * 表达式支持 eq neq gt egt lt elt == > >= < <= or and || && * @access public * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ public function _if($tag,$content) { $condition = $this->parseCondition($tag['condition']); $parseStr = ''.$content.''; return $parseStr; } /** * else标签解析 * 格式:见if标签 * @access public * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ public function _elseif($tag,$content) { $condition = $this->parseCondition($tag['condition']); $parseStr = ''; return $parseStr; } /** * else标签解析 * @access public * @param array $tag 标签属性 * @return string */ public function _else($tag) { $parseStr = ''; return $parseStr; } /** * switch标签解析 * 格式: * * 1 * 2 * other * * @access public * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ public function _switch($tag,$content) { $name = $tag['name']; $varArray = explode('|',$name); $name = array_shift($varArray); $name = $this->autoBuildVar($name); if(count($varArray)>0) $name = $this->parseVarFunction($name,$varArray); $parseStr = ''.$content.''; return $parseStr; } /** * case标签解析 需要配合switch才有效 * @access public * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ public function _case($tag,$content) { $value = $tag['value']; if('$' == substr($value,0,1)) { $varArray = explode('|',$value); $value = array_shift($varArray); $value = $this->autoBuildVar(substr($value,1)); if(count($varArray)>0) $value = $this->parseVarFunction($value,$varArray); $value = 'case '.$value.': '; }elseif(strpos($value,'|')){ $values = explode('|',$value); $value = ''; foreach ($values as $val){ $value .= 'case "'.addslashes($val).'": '; } }else{ $value = 'case "'.$value.'": '; } $parseStr = ''.$content; $isBreak = isset($tag['break']) ? $tag['break'] : ''; if('' ==$isBreak || $isBreak) { $parseStr .= ''; } return $parseStr; } /** * default标签解析 需要配合switch才有效 * 使用: ddfdf * @access public * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ public function _default($tag) { $parseStr = ''; return $parseStr; } /** * compare标签解析 * 用于值的比较 支持 eq neq gt lt egt elt heq nheq 默认是eq * 格式: content * @access public * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ public function _compare($tag,$content,$type='eq') { $name = $tag['name']; $value = $tag['value']; $type = isset($tag['type'])?$tag['type']:$type; $type = $this->parseCondition(' '.$type.' '); $varArray = explode('|',$name); $name = array_shift($varArray); $name = $this->autoBuildVar($name); if(count($varArray)>0) $name = $this->parseVarFunction($name,$varArray); if('$' == substr($value,0,1)) { $value = $this->autoBuildVar(substr($value,1)); }else { $value = '"'.$value.'"'; } $parseStr = ''.$content.''; return $parseStr; } public function _eq($tag,$content) { return $this->_compare($tag,$content,'eq'); } public function _equal($tag,$content) { return $this->_compare($tag,$content,'eq'); } public function _neq($tag,$content) { return $this->_compare($tag,$content,'neq'); } public function _notequal($tag,$content) { return $this->_compare($tag,$content,'neq'); } public function _gt($tag,$content) { return $this->_compare($tag,$content,'gt'); } public function _lt($tag,$content) { return $this->_compare($tag,$content,'lt'); } public function _egt($tag,$content) { return $this->_compare($tag,$content,'egt'); } public function _elt($tag,$content) { return $this->_compare($tag,$content,'elt'); } public function _heq($tag,$content) { return $this->_compare($tag,$content,'heq'); } public function _nheq($tag,$content) { return $this->_compare($tag,$content,'nheq'); } /** * range标签解析 * 如果某个变量存在于某个范围 则输出内容 type= in 表示在范围内 否则表示在范围外 * 格式: content * example: content * @access public * @param array $tag 标签属性 * @param string $content 标签内容 * @param string $type 比较类型 * @return string */ public function _range($tag,$content,$type='in') { $name = $tag['name']; $value = $tag['value']; $varArray = explode('|',$name); $name = array_shift($varArray); $name = $this->autoBuildVar($name); if(count($varArray)>0) $name = $this->parseVarFunction($name,$varArray); $type = isset($tag['type'])?$tag['type']:$type; if('$' == substr($value,0,1)) { $value = $this->autoBuildVar(substr($value,1)); $str = 'is_array('.$value.')?'.$value.':explode(\',\','.$value.')'; }else{ $value = '"'.$value.'"'; $str = 'explode(\',\','.$value.')'; } if($type=='between') { $parseStr = '= $_RANGE_VAR_[0] && '.$name.'<= $_RANGE_VAR_[1]):?>'.$content.''; }elseif($type=='notbetween'){ $parseStr = '$_RANGE_VAR_[1]):?>'.$content.''; }else{ $fun = ($type == 'in')? 'in_array' : '!in_array'; $parseStr = ''.$content.''; } return $parseStr; } // range标签的别名 用于in判断 public function _in($tag,$content) { return $this->_range($tag,$content,'in'); } // range标签的别名 用于notin判断 public function _notin($tag,$content) { return $this->_range($tag,$content,'notin'); } public function _between($tag,$content){ return $this->_range($tag,$content,'between'); } public function _notbetween($tag,$content){ return $this->_range($tag,$content,'notbetween'); } /** * present标签解析 * 如果某个变量已经设置 则输出内容 * 格式: content * @access public * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ public function _present($tag,$content) { $name = $tag['name']; $name = $this->autoBuildVar($name); $parseStr = ''.$content.''; return $parseStr; } /** * notpresent标签解析 * 如果某个变量没有设置,则输出内容 * 格式: content * @access public * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ public function _notpresent($tag,$content) { $name = $tag['name']; $name = $this->autoBuildVar($name); $parseStr = ''.$content.''; return $parseStr; } /** * empty标签解析 * 如果某个变量为empty 则输出内容 * 格式: content * @access public * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ public function _empty($tag,$content) { $name = $tag['name']; $name = $this->autoBuildVar($name); $parseStr = ''.$content.''; return $parseStr; } public function _notempty($tag,$content) { $name = $tag['name']; $name = $this->autoBuildVar($name); $parseStr = ''.$content.''; return $parseStr; } /** * 判断是否已经定义了该常量 * 已定义 * @param $tag * @param $content * @return string */ public function _defined($tag,$content) { $name = $tag['name']; $parseStr = ''.$content.''; return $parseStr; } public function _notdefined($tag,$content) { $name = $tag['name']; $parseStr = ''.$content.''; return $parseStr; } /** * import 标签解析 * * @access public * @param array $tag 标签属性 * @param string $content 标签内容 * @param boolean $isFile 是否文件方式 * @param string $type 类型 * @return string */ public function _import($tag,$content,$isFile=false,$type='') { $file = isset($tag['file'])?$tag['file']:$tag['href']; $parseStr = ''; $endStr = ''; // 判断是否存在加载条件 允许使用函数判断(默认为isset) if (isset($tag['value'])) { $varArray = explode('|',$tag['value']); $name = array_shift($varArray); $name = $this->autoBuildVar($name); if (!empty($varArray)) $name = $this->parseVarFunction($name,$varArray); else $name = 'isset('.$name.')'; $parseStr .= ''; $endStr = ''; } if($isFile) { // 根据文件名后缀自动识别 $type = $type?$type:(!empty($tag['type'])?strtolower($tag['type']):null); // 文件方式导入 $array = explode(',',$file); foreach ($array as $val){ if (!$type || isset($reset)) { $type = $reset = strtolower(substr(strrchr($val, '.'),1)); } switch($type) { case 'js': $parseStr .= ''; break; case 'css': $parseStr .= ''; break; case 'php': $parseStr .= ''; break; } } }else{ // 命名空间导入模式 默认是js $type = $type?$type:(!empty($tag['type'])?strtolower($tag['type']):'js'); $basepath = !empty($tag['basepath'])?$tag['basepath']:__ROOT__.'/Public'; // 命名空间方式导入外部文件 $array = explode(',',$file); foreach ($array as $val){ list($val,$version) = explode('?',$val); switch($type) { case 'js': $parseStr .= ''; break; case 'css': $parseStr .= ''; break; case 'php': $parseStr .= ''; break; } } } return $parseStr.$endStr; } // import别名 采用文件方式加载(要使用命名空间必须用import) 例如 public function _load($tag,$content) { return $this->_import($tag,$content,true); } // import别名使用 导入css文件 public function _css($tag,$content) { return $this->_import($tag,$content,true,'css'); } // import别名使用 导入js文件 public function _js($tag,$content) { return $this->_import($tag,$content,true,'js'); } /** * assign标签解析 * 在模板中给某个变量赋值 支持变量赋值 * 格式: * @access public * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ public function _assign($tag,$content) { $name = $this->autoBuildVar($tag['name']); if('$'==substr($tag['value'],0,1)) { $value = $this->autoBuildVar(substr($tag['value'],1)); }else{ $value = '\''.$tag['value']. '\''; } $parseStr = ''; return $parseStr; } /** * define标签解析 * 在模板中定义常量 支持变量赋值 * 格式: * @access public * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ public function _define($tag,$content) { $name = '\''.$tag['name']. '\''; if('$'==substr($tag['value'],0,1)) { $value = $this->autoBuildVar(substr($tag['value'],1)); }else{ $value = '\''.$tag['value']. '\''; } $parseStr = ''; return $parseStr; } /** * for标签解析 * 格式: * @access public * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ public function _for($tag, $content){ //设置默认值 $start = 0; $end = 0; $step = 1; $comparison = 'lt'; $name = 'i'; $rand = rand(); //添加随机数,防止嵌套变量冲突 //获取属性 foreach ($tag as $key => $value){ $value = trim($value); if(':'==substr($value,0,1)) $value = substr($value,1); elseif('$'==substr($value,0,1)) $value = $this->autoBuildVar(substr($value,1)); switch ($key){ case 'start': $start = $value; break; case 'end' : $end = $value; break; case 'step': $step = $value; break; case 'comparison': $comparison = $value; break; case 'name': $name = $value; break; } } $parseStr = 'parseCondition('$'.$name.' '.$comparison.' $__FOR_END_'.$rand.'__').';$'.$name.'+='.$step.'){ ?>'; $parseStr .= $content; $parseStr .= ''; return $parseStr; } }