修改自定义标签加载方式

This commit is contained in:
TOP糯米 2019-07-28 16:24:27 +08:00
parent f63375ee08
commit 75a0127d60
7 changed files with 213 additions and 111 deletions
application/home
taglib
view/Index
framework/library/template/driver
public
index.php
runtime
cache/application/home
compile/application/home

View File

@ -2,22 +2,15 @@
namespace app\home\taglib; namespace app\home\taglib;
use top\library\template\driver\tags\Engine; class Extend
class Extend extends Engine
{ {
protected $tags = [ public $tags = [
'say' => ['attr' => 'what', 'close' => 0] 'say' => ['attr' => 'what', 'close' => 0]
]; ];
protected function _say_start($tag) public function _say($tag)
{ {
return 'echo \'' . $tag['what'] . '\';'; return '<?php echo \'' . $tag['what'] . '\'; ?>';
}
protected function _say_end($tag, $content)
{
return "echo '{$content}123';";
} }
} }

View File

@ -2,8 +2,8 @@
<block name="body"> <block name="body">
BODY BODY
{$num}
<assign name="b" value="1" /> <assign name="b" value="1" />
{$b}
<raw> <raw>
<volist name="b" id="vo"> <volist name="b" id="vo">
<if condition="$a == 1"> <if condition="$a == 1">
@ -13,5 +13,7 @@
</if> </if>
</volist> </volist>
</raw> </raw>
{:date('Y-m-d H:i:s', time())}
<include file="Base/a" /> <include file="Base/a" />
<say what="你好" />
</block> </block>

View File

@ -51,7 +51,7 @@ class Top implements TemplateIfs
public function run() public function run()
{ {
$this->engine = new Engine(); $this->engine = Engine::instance();
$this->config = Register::get('Config')->get('view'); $this->config = Register::get('Config')->get('view');
return $this; return $this;
} }
@ -68,14 +68,13 @@ class Top implements TemplateIfs
if (!is_dir($this->config['compileDir'])) { if (!is_dir($this->config['compileDir'])) {
mkdir($this->config['compileDir'], 0777, true); mkdir($this->config['compileDir'], 0777, true);
} }
$content = file_get_contents($filename);
$content = $this->engine->compile($content);
if (isset($this->config['tagLib']) && !empty($this->config['tagLib'])) { if (isset($this->config['tagLib']) && !empty($this->config['tagLib'])) {
foreach ($this->config['tagLib'] as $lib) { foreach ($this->config['tagLib'] as $lib) {
$object = new $lib(); $this->engine->loadTaglib($lib);
$content = $object->parseCustomizeTags($content);
} }
} }
$content = file_get_contents($filename);
$content = $this->engine->compile($content);
$content = $this->engine->returnRaw($content); $content = $this->engine->returnRaw($content);
file_put_contents($compileFileName, $content); file_put_contents($compileFileName, $content);
} }

View File

@ -11,6 +11,11 @@ use top\library\Register;
*/ */
class Engine class Engine
{ {
/**
* @var null 单一实例
*/
private static $instance = null;
/** /**
* @var string 左定界符 * @var string 左定界符
*/ */
@ -31,10 +36,21 @@ class Engine
*/ */
protected $config = null; protected $config = null;
/**
* @var null 扩展标签库
*/
private $extend = [];
/**
* @var array 扩展标签库类实例
*/
private $extendInstance = [];
/** /**
* @var array 默认标签定义 * @var array 默认标签定义
*/ */
private $defaultTags = [ private $defaultTags = [
'php' => ['attr' => null, 'close' => 1],
'if' => ['attr' => 'condition', 'close' => 1], 'if' => ['attr' => 'condition', 'close' => 1],
'else' => ['attr' => 'condition', 'close' => 0], 'else' => ['attr' => 'condition', 'close' => 0],
'volist' => ['attr' => 'name,id,key', 'close' => 1], 'volist' => ['attr' => 'name,id,key', 'close' => 1],
@ -46,7 +62,7 @@ class Engine
* Engine constructor. * Engine constructor.
* @throws \Exception * @throws \Exception
*/ */
public function __construct() private function __construct()
{ {
$this->config = Register::get('Config')->get('view'); $this->config = Register::get('Config')->get('view');
if (isset($this->config['left']) && $this->config['left']) { if (isset($this->config['left']) && $this->config['left']) {
@ -58,12 +74,35 @@ class Engine
} }
/** /**
* 处理模板继承 * 获取类单一实例
* @return null|Engine
*/ */
private function parseExtend($tmpl) public static function instance()
{
if (!self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
/**
* 外部加载扩展标签
* @param $lib
*/
public function loadTaglib($lib)
{
$this->extend[] = $lib;
}
/**
* 处理模板继承
* @param $template
* @return mixed
*/
private function parseExtend($template)
{ {
$pattern = '#' . $this->left . 'extend +file=[\'"](.*?)[\'"] +/' . $this->right . '#'; $pattern = '#' . $this->left . 'extend +file=[\'"](.*?)[\'"] +/' . $this->right . '#';
preg_match($pattern, $tmpl, $matches); preg_match($pattern, $template, $matches);
if (!empty($matches)) { if (!empty($matches)) {
$blockPattern = '#' . $this->left . 'block +name=[\'"](.*?)[\'"]' . $this->right; $blockPattern = '#' . $this->left . 'block +name=[\'"](.*?)[\'"]' . $this->right;
$blockPattern .= '([\s\S]*?)' . $this->left . '\/block' . $this->right . '#'; $blockPattern .= '([\s\S]*?)' . $this->left . '\/block' . $this->right . '#';
@ -79,7 +118,7 @@ class Engine
// 被继承模板中的块 // 被继承模板中的块
preg_match_all($blockPattern, $extendFileContent, $extendResult); preg_match_all($blockPattern, $extendFileContent, $extendResult);
// 继承模板中的块 // 继承模板中的块
preg_match_all($blockPattern, $tmpl, $templateResult); preg_match_all($blockPattern, $template, $templateResult);
// 组合搜索的块数组 // 组合搜索的块数组
$search = []; $search = [];
$defaultContent = []; $defaultContent = [];
@ -103,160 +142,200 @@ class Engine
$replaceArray[] = $defaultContent[$key]; $replaceArray[] = $defaultContent[$key];
} }
} }
$tmpl = str_replace($searchArray, $replaceArray, $extendFileContent); $template = str_replace($searchArray, $replaceArray, $extendFileContent);
} }
return $tmpl; return $template;
} }
/** /**
* 处理include标签 * 处理include标签
* @return bool * @param $template
* @return null|string|string[]
*/ */
private function parseInclude($tmpl) private function parseInclude($template)
{ {
$pattern = '#' . $this->left . 'include +file=[\'"](.*?)[\'"] +/' . $this->right . '#'; $pattern = '#' . $this->left . 'include +file=[\'"](.*?)[\'"] +/' . $this->right . '#';
$tmpl = preg_replace_callback($pattern, function ($result) { $template = preg_replace_callback($pattern, function ($result) {
$str = null; $str = null;
$file = $this->config['dir'] . $result[1] . '.html'; $file = $this->config['dir'] . $result[1] . '.html';
if (file_exists($file)) { if (file_exists($file)) {
$str = file_get_contents($file); $str = file_get_contents($file);
} }
return $str; return $str;
}, $tmpl); }, $template);
// 处理多层include // 处理多层include
if ($this->hasInclude($tmpl)) { if ($this->hasInclude($template)) {
$tmpl = $this->parseInclude($tmpl); $template = $this->parseInclude($template);
} }
return $tmpl; return $template;
} }
/** /**
* 检测是否含有include * 检测是否含有include
* @param $tmpl * @param $template
* @return bool * @return bool
*/ */
private function hasInclude($tmpl) private function hasInclude($template)
{ {
$pattern = '#' . $this->left . 'include +file=[\'"](.*?)[\'"] +/' . $this->right . '#'; $pattern = '#' . $this->left . 'include +file=[\'"](.*?)[\'"] +/' . $this->right . '#';
preg_match($pattern, $tmpl, $matches); preg_match($pattern, $template, $matches);
return !empty($matches); return !empty($matches);
} }
/** /**
* 分析参数以及函数输出 * 分析参数以及函数输出
* @param $template
* @return mixed
*/ */
private function parseVars($tmpl) private function parseVars($template)
{ {
preg_match_all('#{(.*?)}#', $tmpl, $matches); preg_match_all('#{(.*?)}#', $template, $matches);
$search = []; $search = [];
$replace = []; $replace = [];
for ($i = 0; $i < count($matches[0]); $i++) { for ($i = 0; $i < count($matches[0]); $i++) {
$start = substr($matches[1][$i], 0, 1); $start = substr($matches[1][$i], 0, 1);
$search[] = $matches[0][$i];
if ($start == '$') { if ($start == '$') {
$search[] = $matches[0][$i]; $replace[] = '<?php echo (' . $matches[1][$i] . '); ?>';
$replace[] = '<?php echo ' . $matches[1][$i] . '; ?>';
} elseif ($start == ':') { } elseif ($start == ':') {
$search[] = $matches[0][$i]; $replace[] = '<?php echo (' . ltrim($matches[1][$i], ':') . '); ?>';
$replace[] = '<?php echo ' . ltrim($matches[1][$i], ':') . '; ?>'; } else {
$replace[] = $matches[0][$i];
} }
} }
$tmpl = str_replace($search, $replace, $tmpl); $template = str_replace($search, $replace, $template);
return $tmpl; return $template;
} }
/** /**
* 处理用户自定义标签 * 标签处理
* @param $tmpl * @param $template
* @return null|string|string[] * @return null|string|string[]
*/ */
public function parseCustomizeTags($tmpl) private function parseTags($template)
{ {
return $this->parseTags($tmpl, $this->tags); foreach ($this->extend as $lib) {
$this->extendInstance[$lib] = $object = new $lib;
foreach ($object->tags as $name => $tag) {
if (!isset($this->tags[$name]) && !isset($this->defaultTags[$name])) {
$this->tags[$name] = $tag;
}
}
}
$tags = array_merge($this->defaultTags, $this->tags);
return $this->_parseTags($template, $tags);
} }
/** /**
* 处理默认的标签 * 获取标签处理结果
* @param $tmpl * @param $name
* @return null|string|string[] * @param $tagContent
* @return mixed
*/ */
private function parseDefaultTags($tmpl) private function getTagParseResult($name, $tagContent = [])
{ {
return $this->parseTags($tmpl, $this->defaultTags); if (method_exists($this, $name)) {
return $this->{$name}($tagContent);
} else {
foreach ($this->extendInstance as $item) {
if (method_exists($item, $name)) {
return $item->{$name}($tagContent);
}
}
return null;
}
} }
/** /**
* 进行标签处理 * 进行标签处理
* @param $tmpl * @param $template
* @param $tags * @param $tags
* @return null|string|string[] * @return null|string|string[]
*/ */
private function parseTags($tmpl, $tags) private function _parseTags($template, $tags)
{ {
foreach ($tags as $name => $item) { foreach ($tags as $name => $item) {
$pattern = '#' . $this->left . $name . ' +(.*?)' . ($item['close'] ? $this->right : '\/' . $this->right . '#'); $pattern = '#' . $this->left . $name . '(.*?)' . ($item['close'] ? null : '\/') . $this->right . '#';
if ($item['close']) { preg_match_all($pattern, $template, $matches);
$pattern .= '([\s\S]*?)' . $this->left . '\/' . $name . $this->right . '#';
}
preg_match_all($pattern, $tmpl, $matches);
for ($i = 0; $i < count($matches[0]); $i++) { for ($i = 0; $i < count($matches[0]); $i++) {
$attrPattern = '#(.*?)=[\'"](.*?)[\'"]#';
preg_match_all($attrPattern, $matches[1][$i], $result);
$tag = []; $tag = [];
if (!empty($result)) { if ($item['attr']) {
foreach ($result[1] as $key => $value) { $attrPattern = '#(.*?)=[\'"](.*?)[\'"]#';
$tag[trim($value, ' ')] = $result[2][$key]; preg_match_all($attrPattern, $matches[1][$i], $result);
if (isset($result[0]) && !empty($result[0])) {
foreach ($result[1] as $key => $value) {
$tag[trim($value, ' ')] = $result[2][$key];
}
} }
} }
if ($item['close']) { $function = ($item['close']) ? '_' . $name . '_start' : '_' . $name;
$tagContent = $matches[2][$i]; $template = str_replace($matches[0][$i], $this->getTagParseResult($function, $tag), $template);
$content = $this->{'_' . $name . '_start'}($tag, $tagContent); }
if ($item['close']) { if ($item['close']) {
$content .= $this->{'_' . $name . '_end'}($tag, $tagContent); $closePattern = '#' . $this->left . '\/' . $name . $this->right . '#';
} $template = preg_replace_callback($closePattern, function () use ($name) {
} else { $function = '_' . $name . '_end';
$content = $this->{'_' . $name . '_start'}($tag); return $this->getTagParseResult($function);
} }, $template);
$tmpl = str_replace($matches[0][$i], $content, $tmpl);
} }
} }
return preg_replace('#\?>([\r|\n|\s]*?)<\?php#', '', $tmpl); return preg_replace('#\?>([\r|\n|\s]*?)<\?php#', '', $template);
} }
/** /**
* 处理raw标签 * 处理raw标签
* @param $tmpl * @param $template
* @return null|string|string[] * @return null|string|string[]
*/ */
private function parseRaw($tmpl) private function parseRaw($template)
{ {
$pattern = '#' . $this->left . 'raw' . $this->right . '([\s\S]*?)'; $pattern = '#' . $this->left . 'raw' . $this->right . '([\s\S]*?)';
$pattern .= $this->left . '\/raw' . $this->right . '#'; $pattern .= $this->left . '\/raw' . $this->right . '#';
$tmpl = preg_replace_callback($pattern, function ($matches) { $template = preg_replace_callback($pattern, function ($matches) {
return str_replace([ return str_replace([
$this->left, $this->right, $this->left, $this->right,
'{', '}' '{', '}'
], [ ], [
'<raw!--', '--raw>', '<raw!--', '--raw>',
'{raw!--', '--raw}' '<-raw!--', '--raw->'
], $matches[1]); ], $matches[1]);
}, $tmpl); }, $template);
return $tmpl; return $template;
} }
/** /**
* 还原raw * 还原raw
* @param $tmpl * @param $template
* @return null|string|string[] * @return mixed
*/ */
public function returnRaw($tmpl) public function returnRaw($template)
{ {
$pattern = '#[{|<]raw!--([\s\S]*?)--raw[>|}]#'; $template = str_replace([
$tmpl = preg_replace_callback($pattern, function ($matches) { '<raw!--', '--raw>',
$left = substr($matches[0], 0, 1); '<-raw!--', '--raw->'
$right = substr($matches[0], -1); ], [
return $left . $matches[1] . $right; $this->left, $this->right,
}, $tmpl); '{', '}'
return $tmpl; ], $template);
return $template;
}
/**
* php标签开始
* @return string
*/
private function _php_start()
{
return '<?php ';
}
/**
* php标签结束
* @return string
*/
private function _php_end()
{
return ' ?>';
} }
/** /**
@ -264,9 +343,9 @@ class Engine
* @param $tag * @param $tag
* @return string * @return string
*/ */
private function _if_start($tag, $content) private function _if_start($tag)
{ {
return '<?php if (' . $tag['condition'] . '): ?>' . $content; return '<?php if (' . $tag['condition'] . '): ?>';
} }
/** /**
@ -296,18 +375,18 @@ class Engine
/** /**
* volist标签 * volist标签
* @param $tag * @param $tag
* @return null|string * @return string
*/ */
private function _volist_start($tag, $content) private function _volist_start($tag)
{ {
if (substr($tag['name'], 0, 1) == ':') { if (substr($tag['name'], 0, 1) == ':') {
$name = substr($tag['name'], 1); $name = substr($tag['name'], 1);
} else { } else {
$name = '$' . $tag['name']; $name = '$' . $tag['name'];
} }
$parse = (empty($tag['key'])) ? null : '$' . $tag['key'] . ' = 0; '; $key = (empty($tag['key'])) ? null : '$' . $tag['key'] . ' = 0;';
$parse .= '<?php foreach (' . $name . ' as $' . $tag['id'] . '): ?>' . $content; $parse = '<?php ' . $key . ' foreach (' . $name . ' as $' . $tag['id'] . '): ';
$parse .= (empty($tag['key']) ? null : '$' . $tag['key'] . '++;'); $parse .= ($key ? '$' . $tag['key'] . '++;' : null) . ' ?>';
return $parse; return $parse;
} }
@ -319,33 +398,36 @@ class Engine
{ {
return '<?php endforeach; ?>'; return '<?php endforeach; ?>';
} }
/** /**
* assign标签 * assign标签
* @param $tag
* @return string * @return string
*/ */
private function _assign_start($tag) private function _assign($tag)
{ {
return '<?php $'. $tag['name'] .' = ' . $tag['value'] . '; ?>'; return '<?php $' . $tag['name'] . ' = ' . $tag['value'] . '; ?>';
} }
/** /**
* 获取编译后的内容 * 获取编译后的内容
* @return null|string|string[] * @param $template
* @return bool|mixed|null|string|string[]
*/ */
public function compile($tmpl) public function compile($template)
{ {
// 处理raw标签 // 处理raw标签
$tmpl = $this->parseRaw($tmpl); $template = $this->parseRaw($template);
// 处理模板继承标签 // 处理模板继承标签
$tmpl = $this->parseExtend($tmpl); $template = $this->parseExtend($template);
// 处理include标签 // 处理include标签
$tmpl = $this->parseInclude($tmpl); $template = $this->parseInclude($template);
// 处理定义的标签
$tmpl = $this->parseDefaultTags($tmpl);
// 处理变量以及函数 // 处理变量以及函数
$tmpl = $this->parseVars($tmpl); $template = $this->parseVars($template);
return $tmpl; // 处理定义的标签
$template = $this->parseTags($template);
return $template;
} }
} }

View File

@ -7,7 +7,7 @@ require '../framework/Framework.php';
// 可能你会使用到下面这些配置 // 可能你会使用到下面这些配置
// 调试模式缺省值false // 调试模式缺省值false
Framework::debug(true); // Framework::debug(true);
// 可使用常量DEBUG取得该值 // 可使用常量DEBUG取得该值
// 项目目录,缺省值:./application/ // 项目目录,缺省值:./application/

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
父级模板
BODY
1
<volist name="b" id="vo">
<if condition="$a == 1">
{$a}
<else condition="$a == 2" />
{$b}
</if>
</volist>
2019-07-28 16:22:50 a.html
b.html
你好
</body>
</html>

View File

@ -8,7 +8,7 @@
父级模板 父级模板
BODY BODY
<?php echo $num; $b = 1; ?> <?php $b = 1; echo ($b); ?>
<volist name="b" id="vo"> <volist name="b" id="vo">
<if condition="$a == 1"> <if condition="$a == 1">
@ -18,8 +18,10 @@
</if> </if>
</volist> </volist>
<?php echo (date('Y-m-d H:i:s', time())); ?>
a.html a.html
b.html b.html
<?php echo '你好'; ?>
</body> </body>
</html> </html>