Sharing the template engine development experience of MVC pattern in PHP

  • 2020-03-31 21:40:08
  • OfStack

Make the development and maintenance of Web system more convenient, so as to effectively save manpower and material resources, by more and more enterprises.

Template engine is important in the process of the MVC pattern based approach, developers will be able to design a set of given meaning, through technical analysis processing effective logic to handle the data extracted from the interface template, by interpreting the meaning of the tags to submit control for corresponding business logic processing program, so as to obtain the data needed to, in the form of template design, enables designers to focus more on performance forms. The following is my understanding and design method of template engine:

Template engines, to put it mildly, are the process of interpreting template data. Through my thinking and understanding of the site construction, the website can be summarized into two forms: single and multiple, so we can set two corresponding labels (such as data and list) to deal with these two cases. The key point is to solve the problem of multi-layer nesting of the two labels, which is basically suitable for the realization of 80% interface form.

Templates can be interpreted in a variety of ways, including string manipulation (a bit more trouble with nesting) and regular expressions. The regular expression I chose here, and the following is how I handled it (this article only provides ideas and reference code, which may not be used directly).

Template file resolution class:
 
<?php 
/* 
* class:  Template resolution class  
* author: 51JS.COM-ZMM 
* date: 2011.3.1 
* email: 304924248@qq.com 
* blog: http://www.cnblogs.com/cnzmm/ 
*/ 
class Template { 
public $html, $vars, $bTag, $eTag; 
public $bFlag='{', $eFlag='}', $pfix='zmm:'; 
private $folder, $file; 
function __construct($vars=array()) { 
!empty($vars) && $this->vars = $vars; 
!empty($GLOBALS['cfg_tag_prefix']) && 
$this->pfix = $GLOBALS['cfg_tag_prefix'].':'; 
$this->bTag = $this->bFlag.$this->pfix; 
$this->eTag = $this->bFlag.'/'.$this->pfix; 
empty(Tags::$vars) && Tags::$vars = &$this->vars; 
} 
public function LoadTpl($tpl) { 
$this->file = $this->GetTplPath($tpl); 
Tags::$file = &$this->file; 
if (is_file($this->file)) { 
if ($this->GetTplHtml()) { 
$this->SetTplTags(); 
} else { 
exit(' Template file load failed! '); 
} 
} else { 
exit(' Template file ['.$this->file.'] Does not exist! '); 
} 
} 
private function GetTplPath($tpl) { 
$this->folder = WEBSITE_DIRROOT. 
$GLOBALS['cfg_tpl_root']; 
return $this->folder.'/'.$tpl; 
} 
private function GetTplHtml() { 
$html = self::FmtTplHtml(file_get_contents($this->file)); 
if (!empty($html)) { 
$callFunc = Tags::$prefix.'Syntax'; 
$this->html = Tags::$callFunc($html, new Template()); 
} else { 
exit(' Template file content is empty! '); 
} return true; 
} 
static public function FmtTplHtml($html) { 
return preg_replace('/(r)|(n)|(t)|(s{2,})/is', '', $html); 
} 
public function Register($vars=array()) { 
if (is_array($vars)) { 
$this->vars = $vars; 
Tags::$vars = &$this->vars; 
} 
} 
public function Display($bool=false, $name="", $time=0) { 
if (!empty($this->html)) { 
if ($bool && !empty($name)) { 
if (!is_int($time)) $time = 600; 
$cache = new Cache($time); 
$cache->Set($name, $this->html); 
} 
echo $this->html; flush(); 
} else { 
exit(' Template file content is empty! '); 
} 
} 
public function SetAssign($souc, $info) { 
if (!empty($this->html)) { 
$this->html = str_ireplace($souc, self::FmtTplHtml($info), $this->html); 
} else { 
exit(' Template file content is empty! '); 
} 
} 
private function SetTplTags() { 
$this->SetPanelTags(); $this->SetTrunkTags(); $this->RegHatchVars(); 
} 
private function SetPanelTags() { 
$rule = $this->bTag.'([^'.$this->eFlag.']+)/'.$this->eFlag; 
preg_match_all('/'.$rule.'/ism', $this->html, $out_matches); 
$this->TransTag($out_matches, 'panel'); unset($out_matches); 
} 
private function SetTrunkTags() { 
$rule = $this->bTag.'(w+)s*([^'.$this->eFlag.']*?)'.$this->eFlag. 
'((?:(?!'.$this->bTag.')[Ss]*?|(?R))*)'.$this->eTag.'\1s*'.$this->eFlag; 
preg_match_all('/'.$rule.'/ism', $this->html, $out_matches); 
$this->TransTag($out_matches, 'trunk'); unset($out_matches); 
} 
private function TransTag($result, $type) { 
if (!empty($result[0])) { 
switch ($type) { 
case 'panel' : { 
for ($i = 0; $i < count($result[0]); $i ++) { 
$strTag = explode(' ', $result[1][$i], 2); 
if (strpos($strTag[0], '.')) { 
$itemArg = explode('.', $result[1][$i], 2); 
$callFunc = Tags::$prefix.ucfirst($itemArg[0]); 
if (method_exists('Tags', $callFunc)) { 
$html = Tags::$callFunc(chop($itemArg[1])); 
if ($html !== false) { 
$this->html = str_ireplace($result[0][$i], $html, $this->html); 
} 
} 
} else { 
$rule = '^([^s]+)s*([Ss]+)$'; 
preg_match_all('/'.$rule.'/is', trim($result[1][$i]), $tmp_matches); 
$callFunc = Tags::$prefix.ucfirst($tmp_matches[1][0]); 
if (method_exists('Tags', $callFunc)) { 
$html = Tags::$callFunc($tmp_matches[2][0]); 
if ($html !== false) { 
$this->html = str_ireplace($result[0][$i], $html, $this->html); 
} 
} unset($tmp_matches); 
} 
} break; 
} 
case 'trunk' : { 
for ($i = 0; $i < count($result[0]); $i ++) { 
$callFunc = Tags::$prefix.ucfirst($result[1][$i]); 
if (method_exists('Tags', $callFunc)) { 
$html = Tags::$callFunc($result[2][$i], $result[3][$i]); 
$this->html = str_ireplace($result[0][$i], $html, $this->html); 
} 
} break; 
} 
default: break; 
} 
} else { 
return false; 
} 
} 
private function RegHatchVars() { 
$this->SetPanelTags(); 
} 
function __destruct() {} 
} 
?> 

Tag parsing class :(at present, we temporarily provide the parsing of data and list tags to illustrate the idea)
 
<?php 
/* 
* class:  Tag parsing class  
* author: 51JS.COM-ZMM 
* date: 2011.3.2 
* email: 304924248@qq.com 
* blog: http://www.cnblogs.com/cnzmm/ 
*/ 
class Tags { 
static private $attrs=null; 
static public $file, $vars, $rule, $prefix='TAG_'; 
static public function TAG_Syntax($html, $that) { 
$rule = $that->bTag.'ifs+([^'.$that->eFlag.']+)s*'.$that->eFlag; 
$html = preg_replace('/'.$rule.'/ism', '<?php if (\1) { ?>', $html); 
$rule = $that->bTag.'elseifs+([^'.$that->eFlag.']+)s*'.$that->eFlag; 
$html = preg_replace('/'.$rule.'/ism', '<?php } elseif (\1) { ?>', $html); 
$rule = $that->bTag.'elses*'.$that->eFlag; 
$html = preg_replace('/'.$rule.'/ism', '<?php } else { ?>', $html); 
$rule = $that->bTag.'loops+(S+)s+(S+)s*'.$that->eFlag; 
$html = preg_replace('/'.$rule.'/ism', '<?php foreach (\1 as \2) { ?>', $html); 
$rule = $that->bTag.'loops+(S+)s+(S+)s+(S+)s*'.$that->eFlag; 
$html = preg_replace('/'.$rule.'/ism', '<?php foreach (\1 as \2 => \3) { ?>', $html); 
$rule = $that->eTag.'(if|loop)s*'.$that->eFlag; 
$html = preg_replace('/'.$rule.'/ism', '<?php } ?>', $html); 
$rule = $that->bTag.'phps*'.$that->eFlag.'((?:(?!'. 
$that->bTag.')[Ss]*?|(?R))*)'.$that->eTag.'phps*'.$that->eFlag; 
$html = preg_replace('/'.$rule.'/ism', '<?php \1 ?>', $html); 
return self::TAG_Execute($html); 
} 
static public function TAG_List($attr, $html) { 
if (!empty($html)) { 
if (self::TAG_HaveTag($html)) { 
return self::TAG_DealTag($attr, $html, true); 
} else { 
return self::TAG_GetData($attr, $html, true); 
} 
} else { 
exit(' The label {list} The content is empty! '); 
} 
} 
static public function TAG_Data($attr, $html) { 
if (!empty($html)) { 
if (self::TAG_HaveTag($html)) { 
return self::TAG_DealTag($attr, $html, false); 
} else { 
return self::TAG_GetData($attr, $html, false); 
} 
} else { 
exit(' The label {data} The content is empty! '); 
} 
} 
static public function TAG_Execute($html) { 
ob_clean(); ob_start(); 
if (!empty(self::$vars)) { 
is_array(self::$vars) && 
extract(self::$vars, EXTR_OVERWRITE); 
} 
$file_inc = WEBSITE_DIRINC.'/buffer/'. 
md5(uniqid(rand(), true)).'.php'; 
if ($fp = fopen($file_inc, 'xb')) { 
fwrite($fp, $html); 
if (fclose($fp)) { 
include($file_inc); 
$html = ob_get_contents(); 
} unset($fp); 
} else { 
exit(' Template parsing file generation failed! '); 
} ob_end_clean(); @unlink($file_inc); 
return $html; 
} 
static private function TAG_HaveTag($html) { 
$bool_has = false; 
$tpl_ins = new Template(); 
self::$rule = $tpl_ins->bTag.'([^'.$tpl_ins->eFlag.']+)/'.$tpl_ins->eFlag; 
$bool_has = $bool_has || preg_match('/'.self::$rule.'/ism', $html); 
self::$rule = $tpl_ins->bTag.'(w+)s*([^'.$tpl_ins->eFlag.']*?)'.$tpl_ins->eFlag. 
'((?:(?!'.$tpl_ins->bTag.')[Ss]*?|(?R))*)'.$tpl_ins->eTag.'\1s*'.$tpl_ins->eFlag; 
$bool_has = $bool_has || preg_match('/'.self::$rule.'/ism', $html); 
unset($tpl_ins); 
return $bool_has; 
} 
static private function TAG_DealTag($attr, $html, $list) { 
preg_match_all('/'.self::$rule.'/ism', $html, $out_matches); 
if (!empty($out_matches[0])) { 
$child_node = array(); 
for ($i = 0; $i < count($out_matches[0]); $i ++) { 
$child_node[] = $out_matches[3][$i]; 
$html = str_ireplace($out_matches[3][$i], '{-->>child_node_'.$i.'<<--}', $html); 
} 
$html = self::TAG_GetData($attr, $html, $list); 
for ($i = 0; $i < count($out_matches[0]); $i ++) { 
$html = str_ireplace('{-->>child_node_'.$i.'<<--}', $child_node[$i], $html); 
} 
preg_match_all('/'.self::$rule.'/ism', $html, $tmp_matches); 
if (!empty($tmp_matches[0])) { 
for ($i = 0; $i < count($tmp_matches[0]); $i ++) { 
$callFunc = self::$prefix.ucfirst($tmp_matches[1][$i]); 
if (method_exists('Tags', $callFunc)) { 
$temp = self::$callFunc($tmp_matches[2][$i], $tmp_matches[3][$i]); 
$html = str_ireplace($tmp_matches[0][$i], $temp, $html); 
} 
} 
} 
unset($tmp_matches); 
} 
unset($out_matches); return $html; 
} 
static private function TAG_GetData($attr, $html, $list=false) { 
if (!empty($attr)) { 
$attr_ins = new Attbt($attr); 
$attr_arr = $attr_ins->attrs; 
if (is_array($attr_arr)) { 
extract($attr_arr, EXTR_OVERWRITE); 
$source = table_name($source, $column); 
$rule = '[field:s*(w+)s*([^]]*?)s*/?]'; 
preg_match_all('/'.$rule.'/is', $html, $out_matches); 
$data_str = ''; 
$data_ins = new DataSql(); 
$attr_where = $attr_order = ''; 
if (!empty($where)) { 
$where = str_replace(',', ' and ', $where); 
$attr_where = ' where '. $where; 
} 
if (!empty($order)) { 
$attr_order = ' order by '.$order; 
} else { 
$fed_name = ''; 
$fed_ins = $data_ins->GetFedNeedle($source); 
$fed_cnt = $data_ins->GetFedCount($fed_ins); 
for ($i = 0; $i < $fed_cnt; $i ++) { 
$fed_flag = $data_ins->GetFedFlag($fed_ins, $i); 
if (preg_match('/auto_increment/ism', $fed_flag)) { 
$fed_name = $data_ins->GetFedName($fed_ins, $i); 
break; 
} 
} 
if (!empty($fed_name)) 
$attr_order = ' order by '.$fed_name.' desc'; 
} 
if ($list == true) { 
if (empty($source) && empty($sql)) { 
exit(' The label {list} You must specify source Attributes as well! '); 
} 
$attr_rows = $attr_page = ''; 
if ($rows > 0) { 
$attr_rows = ' limit 0,'.$rows; 
} 
if (!empty($sql)) { 
$data_sql = $sql; 
} else { 
$data_sql = 'select * from `'.$source.'`'. 
$attr_where.$attr_order.$attr_rows; 
} 
if ($pages=='true' && !empty($size)) { 
$data_num = $data_ins->GetRecNum($data_sql); 
$page_cnt = ceil($data_num / $size); 
global $page; 
if (!isset($page) || $page < 1) $page = 1; 
if ($page > $page_cnt) $page = $page_cnt; 
$data_sql = 'select * from `'.$source.'`'.$attr_where. 
$attr_order.' limit '.($page-1) * $size.','.$size; 
$GLOBALS['cfg_page_curr'] = $page; 
$GLOBALS['cfg_page_prev'] = $page - 1; 
$GLOBALS['cfg_page_next'] = $page + 1; 
$GLOBALS['cfg_page_nums'] = $page_cnt; 
if (function_exists('list_pagelink')) { 
$GLOBALS['cfg_page_list'] = list_pagelink($page, $page_cnt, 2); 
} 
} 
$data_idx = 0; 
$data_ret = $data_ins->SqlCmdExec($data_sql); 
while ($row = $data_ins->GetRecArr($data_ret)) { 
if ($skip > 0 && !empty($flag)) { 
$data_idx != 0 && 
$data_idx % $skip == 0 && 
$data_str .= $flag; 
} 
$data_tmp = $html; 
$data_tmp = str_ireplace('@idx', $data_idx, $data_tmp); 
for ($i = 0; $i < count($out_matches[0]); $i ++) { 
$data_tmp = str_ireplace($out_matches[0][$i], 
$row[$out_matches[1][$i]], $data_tmp); 
} 
$data_str .= $data_tmp; $data_idx ++; 
} 
} else { 
if (empty($source)) { 
exit(' The label {data} You must specify source Attributes as well! '); 
} 
$data_sql = 'select * from `'.$source. 
'`'.$attr_where.$attr_order; 
$row = $data_ins->GetOneRec($data_sql); 
if (is_array($row)) { 
$data_tmp = $html; 
for ($i = 0; $i < count($out_matches[0]); $i ++) { 
$data_val = $row[$out_matches[1][$i]]; 
if (empty($out_matches[2][$i])) { 
$data_tmp = str_ireplace($out_matches[0][$i], $data_val, $data_tmp); 
} else { 
$attr_str = $out_matches[2][$i]; 
$attr_ins = new Attbt($attr_str); 
$func_txt = $attr_ins->attrs['function']; 
if (!empty($func_txt)) { 
$func_tmp = explode('(', $func_txt); 
if (function_exists($func_tmp[0])) { 
eval('$func_ret ='.str_ireplace('@me', 
'''.$data_val.''', $func_txt)); 
$data_tmp = str_ireplace($out_matches[0][$i], $func_ret, $data_tmp); 
} else { 
exit(' Called a function that doesn't exist! '); 
} 
} else { 
exit(' TAB setting property invalid! '); 
} 
} 
} 
$data_str .= $data_tmp; 
} 
} 
unset($data_ins); 
return $data_str; 
} else { 
exit(' TAB setting property invalid! '); 
} 
} else { 
exit(' No TAB properties set! '); 
} 
} 
static public function __callStatic($name, $args) { 
exit(' The label {'.$name.'} Does not exist! '); 
} 
} 
?> 

Related articles: