不灭的焱

革命尚未成功,同志仍须努力

作者:php-note.com  发布于:2014-01-06 14:35  分类:PHP库/系统/微信  编辑

由于工作的需要,用到了开源微博系统 ThinkSNS3.X ,它采用的是 ThinkPHP2.X 框架,当然也做了些修改,在二次开发过程中,感觉 ThinkSNS 的模板语法还是偏复杂,不够精简,最好能精简到连 美工/前端工程师 一眼就能看懂是怎么回事的程度,于是想到了Discuz模板语法,觉得它的语法是我想要的。按照它的语法思路自己写了个模板引擎,同时又不能对 ThinkSNS 自带的模板引擎产生干扰,即要做好兼容工作。

整体思路如下:

1、在 ThinkSNS 自带模板引擎对模板编译之前,先把 “新的模板语法标签”替换成一些“特殊的字符串”,即占位符,如:

  把 <!--{if xxx}--> 替换成 <!--IF_TAG_3-->

  把 <!--{elseif xxx}--> 替换成 <!--ELSEIF_TAG_4-->

  新产生的占位符是不会干扰旧模板引擎的编译的。

2、再把替换后的模板内容传给“旧模板引擎”去编译;

3、再把编译后的模板内容传给“新模板引擎”去编译,替换在第一步中产生的“特殊的字符串”,完成最终的编译过程;

 

新模板引擎语法(兼容ThinkSNS自带的模板引擎)

1、模板嵌套语法

<!--{template bolglist}-->                        // 包含 当前应用模块下的 bloglist.html
<!--{template http://php-note.com/public/default/blog/hearder}-->         // 包含 当前应用下的 header.html·
<!--{template http://php-note.com/public/default/footer}-->      // 包含 当前主题下的 footer.html

2、逻辑判断 if...else

<!--{if $_G['uid']}-->
    任意html语句 
<!--{/if}-->

<!--{if $_G['uid']}-->
    任意html语句 
<!--{else}-->
    任意html语句 
<!--{/if}-->

<!--{if $_G['uid']}-->
    任意 html 语句
<!--{elseif $_G[connectguest]}-->
    任意html语句
<!--{/if}-->

<!--{if empty($_G['forum']['picstyle']) && $_GET['orderby'] == 'lastpost' && empty($_GET['filter']) }-->
    任意 html 语句
<!--{elseif 条件2}-->
    任意html语句
<!--{elseif 条件3}-->
    任意html语句
<!--{else}-->
    任意html语句
<!--{/if}-->

3、循环语法(可以多重循环)

带有数组键的循环写法
<!--{loop $arr $key $val}-->
    循环输出的HTML语句
<!--{/loop}-->

没有数组键的循环写法
<!--{loop $arr $val}-->
    循环输出的HTML语句
<!--{/loop}-->

4、输出某个函数的结果

<!--{call widget('comment', array('xxx', 'yyy'))}-->
<!--{call get_user_name(59)}-->

5、直接执行 PHP 代码行

<!--{eval echo $my_var;}-->
<!--{eval $my_arr = array(1, 2, 3);}-->
<!--{eval print_r($my_arr);}-->
<!--{eval output();}-->
<!--{eval exit();}-->

6、直接执行 PHP 代码块

<!--{eval}-->
    PHP代码块
<!--{/eval}--> 

7、输出变量

<!--{$var}--> 或  {$var}

8、输出常量

<!--{CONST}-->

 

 

第一步:把 TemplateNew.class.php 拷贝到 /core/OpenSociax/ 目录下

新模板引擎类(TemplateNew.class.php),内容如下:

<?php
/**
 * 新模板解析类(兼容ThinkSNS自带的模板引擎)
 *
 * @author snsgou.com
 */
class TemplateNew {

	protected $index = 0;
	protected $search = array();
	protected $replace = array();

	/**
	 * 编译模板(查找)
	 *
	 * @param string $template 模板内容
	 */
	public function compileSearch($template) {

		// 子模板
		for ($i = 1; $i < 3; $i++) {
			$template = preg_replace("/\<\!\-\-\{template\s+(.+?)\}\-\-\>/e", "\$this->readSubTpl('\\1')", $template);
		}

		// call标签(输出某个函数的结果)
		$template = preg_replace("/\<\!\-\-\{call\s+(.+?)\}\-\-\>/e", "\$this->callTag('\\1')", $template);

		// PHP代码块
		$template = preg_replace("/\<\!\-\-\{eval\}\-\-\>(.+?)\<\!\-\-\{\/eval\}\-\-\>/se", "\$this->evalTag('\\1')", $template);
		$template = preg_replace("/\<\!\-\-\{eval\s+(.+?)\}\-\-\>/e", "\$this->evalTag(' \\1; ')", $template);

		// 逻辑
		$template = preg_replace("/\<\!\-\-\{if\s+(.+?)\}\-\-\>/e", "\$this->ifTag('\\1')", $template);
		$template = preg_replace("/\<\!\-\-\{elseif\s+(.+?)\}\-\-\>/e", "\$this->elseifTag('\\1')", $template);
		$template = preg_replace("/\<\!\-\-\{else\}\-\-\>/e", "\$this->elseTag()", $template);
		$template = preg_replace("/\<\!\-\-\{\/if\}\-\-\>/e", "\$this->endifTag()", $template);

		// 循环
		$template = preg_replace("/\<\!\-\-\{loop\s+(\S+)\s+(\S+)\s+(\S+)\}\-\-\>/e", "\$this->loopkeyvalueTag('\\1', '\\2', '\\3')", $template);
		$template = preg_replace("/\<\!\-\-\{loop\s+(\S+)\s+(\S+)\}\-\-\>/e", "\$this->loopvalueTag('\\1', '\\2')", $template);
		$template = preg_replace("/\<\!\-\-\{\/loop\}\-\-\>/e", "\$this->endloopTag()", $template);

		// 变量
		$varRegexp = "((\\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(\[[a-zA-Z0-9_\-\.\"\'\[\]\$\x7f-\xff]+\])*)";
		$template = preg_replace("/\<\!\-\-\{$varRegexp\}\-\-\>/e", "\$this->varTag('\\1')", $template);
		//$template = preg_replace("/(?<!\<\!\-\-)\{$varRegexp\}(?!\-\-\>)/e", "\$this->varTag('\\1')", $template);

		// 常量
		$constRegexp = "([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)";
		$template = preg_replace("/\<\!\-\-\{$constRegexp\}\-\-\>/e", "\$this->constTag('\\1')", $template);
		//$template = preg_replace("/(?<!\<\!\-\-)\{$constRegexp\}(?!\-\-\>)/e", "\$this->constTag('\\1')", $template);

		return $template;
	}

	/**
	 * 编译模板(替换)
	 *
	 * @param string $template 模板内容
	 */
	public function compileReplace($template) {
		if (!empty($this->search)) {
			$template = str_replace($this->search, $this->replace, $template);
		}

		return $template;
	}

	/**
	 * 读取子模板
	 */
	protected function readSubTpl($tplFile) {

		$tplFile = $this->getTplPath($tplFile);

		if (!file_exists($tplFile)) {
			die('Template file : ' . str_replace(SITE_PATH, '', $tplFile) . ' not found!');
		}
		$content = file_get_contents($tplFile);
		if (empty($content)) {
			die('Template file : ' . str_replace(SITE_PATH, '', $tplFile) . ' have no access!');
		}

		return $content;
	}

	/**
	 * 获取模板路径(绝对物理路径)
	 */
	protected function getTplPath($tplFile) {
		if (preg_match("/\.html$/i", $tplFile)) {
			return $tplFile;
		} elseif (empty($tplFile)) {
			$tplFile = APP_TPL_PATH . '/' . MODULE_NAME . '/' . ACTION_NAME . '.html';
		} elseif (preg_match("/(http://php-note.com/public/default|http://php-note.com/public/default/blog)/", $tplFile)) {
			// 路径魔术变量替换
			$replace = array(
				'http://php-note.com/public/default' => THEME_PATH,
				'http://php-note.com/public/default/blog' => APP_TPL_PATH
			);
			$tplFile = str_replace(array_keys($replace), array_values($replace), $tplFile) . '.html';
		} else {
			$tplFile = APP_TPL_PATH . '/' . MODULE_NAME . '/' . $tplFile . '.html';
		}

		return $tplFile;
	}

	/**
	 * call标签
	 */
	protected function callTag($str) {
		$search = '<!--CALL_TAG_' . $this->index . '-->';
		$this->index++;
		$this->search[$this->index] = $search;
		$this->replace[$this->index] = "<?php echo $str; ?>";

		return $search;
	}

	/**
	 * eval标签
	 */
	protected function evalTag($str) {
		$search = '<!--EVAL_TAG_' . $this->index . '-->';
		$this->index++;
		$this->search[$this->index] = $search;
		$this->replace[$this->index] = "<?php$str?>";

		return $search;
	}

	/**
	 * if标签
	 */
	protected function ifTag($str) {
		$search = '<!--IF_TAG_' . $this->index . '-->';
		$this->index++;
		$this->search[$this->index] = $search;
		$this->replace[$this->index] = "<?php if ($str) { ?>";

		return $search;
	}

	/**
	 * elseif标签
	 */
	protected function elseifTag($str) {
		$search = '<!--ELSEIF_TAG_' . $this->index . '-->';
		$this->index++;
		$this->search[$this->index] = $search;
		$this->replace[$this->index] = "<?php } elseif ($str) { ?>";

		return $search;
	}

	/**
	 * else标签
	 */
	protected function elseTag() {
		$search = '<!--ELSE_TAG_' . $this->index . '-->';
		$this->index++;
		$this->search[$this->index] = $search;
		$this->replace[$this->index] = "<?php } else { ?>";

		return $search;
	}

	/**
	 * endif标签
	 */
	protected function endifTag() {
		$search = '<!--ENDIF_TAG_' . $this->index . '-->';
		$this->index++;
		$this->search[$this->index] = $search;
		$this->replace[$this->index] = "<?php } ?>";

		return $search;
	}

	/**
	 * loop key value 标签
	 */
	protected function loopkeyvalueTag($arr, $key, $value) {
		$search = '<!--LOOPKEYVALUE_TAG_' . $this->index . '-->';
		$this->index++;
		$this->search[$this->index] = $search;
		$this->replace[$this->index] = "<?php if (is_array($arr)) { foreach ($arr as $key=>$value) { ?>";

		return $search;
	}

	/**
	 * loop value 标签
	 */
	protected function loopvalueTag($arr, $value) {
		$search = '<!--LOOPVALUE_TAG_' . $this->index . '-->';
		$this->index++;
		$this->search[$this->index] = $search;
		$this->replace[$this->index] = "<?php if (is_array($arr)) { foreach ($arr as $value) { ?>";

		return $search;
	}

	/**
	 * endloop标签
	 */
	protected function endloopTag() {
		$search = '<!--ENDLOOP_TAG_' . $this->index . '-->';
		$this->index++;
		$this->search[$this->index] = $search;
		$this->replace[$this->index] = "<?php }} ?>";

		return $search;
	}

	/**
	 * var标签
	 */
	protected function varTag($str) {
		$search = '<!--VAR_TAG_' . $this->index . '-->';
		$this->index++;
		$this->search[$this->index] = $search;
		$this->replace[$this->index] = "<?php echo $str; ?>";

		return $search;
	}

	/**
	 * const标签
	 */
	protected function constTag($str) {
		$search = '<!--CONST_TAG_' . $this->index . '-->';
		$this->index++;
		$this->search[$this->index] = $search;
		$this->replace[$this->index] = "<?php echo $str; ?>";

		return $search;
	}
}
?>

 

第二步:找到 ThinkSNS 的模板引擎文件 /core/OpenSociax/Template.class.php

把 “public function loadTemplate($tmplTemplateFile = '') {...}”方法中的

// 需要更新模版 读出原模板内容
$tmplContent = file_get_contents($tmplTemplateFile);
//编译模板内容
$tmplContent = $this->compiler($tmplContent);

替换成

// 新模板解析类(兼容TS自带的模板引擎) // by snsgou.com
tsload(CORE_LIB_PATH . '/TemplateNew.class.php');
$tplNew = new TemplateNew();

// 需要更新模版 读出原模板内容
$tmplContent = file_get_contents($tmplTemplateFile);

// 编译模板内容
$tmplContent = $tplNew->compileSearch($tmplContent); // by snsgou.com
$tmplContent = $this->compiler($tmplContent);
$tmplContent = $tplNew->compileReplace($tmplContent); // by snsgou.com

即可。整个改造过程完毕!!!