更新默认模板引擎
This commit is contained in:
parent
7a1647e220
commit
3f52362430
|
@ -25,8 +25,8 @@ return [
|
||||||
'dir' => APP_PATH . 'home/view/',
|
'dir' => APP_PATH . 'home/view/',
|
||||||
'cacheDir' => './runtime/cache/application/home/',
|
'cacheDir' => './runtime/cache/application/home/',
|
||||||
'compileDir' => './runtime/compile/application/home/',
|
'compileDir' => './runtime/compile/application/home/',
|
||||||
'left' => '{',
|
'left' => '<',
|
||||||
'right' => '}',
|
'right' => '>',
|
||||||
'cacheTime' => 5
|
'cacheTime' => 5
|
||||||
],
|
],
|
||||||
];
|
];
|
|
@ -10,7 +10,7 @@ class Index extends Common
|
||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
return request()->module();
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hello()
|
public function hello()
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
父级模板
|
||||||
|
<block name="body"></block>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1 +0,0 @@
|
||||||
<h1>Hello</h1>
|
|
|
@ -1,14 +1,6 @@
|
||||||
<!DOCTYPE html>
|
<extend file="Base/common" />
|
||||||
<html lang="en">
|
|
||||||
<head>
|
<block name="body">
|
||||||
<meta charset="UTF-8">
|
BODY
|
||||||
<title>Title</title>
|
{$num}
|
||||||
<script src="/resource/jquery.min.js"></script>
|
</block>
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{view name="Index/hello"}
|
|
||||||
{loop $lists as $value}
|
|
||||||
{$value}
|
|
||||||
{/loop}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport"
|
|
||||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
||||||
<title>Document</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -49,8 +49,5 @@ class App
|
||||||
// 输出内容
|
// 输出内容
|
||||||
echo $responseData;
|
echo $responseData;
|
||||||
|
|
||||||
if (function_exists('fastcgi_finish_request')) {
|
|
||||||
fastcgi_finish_request();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ use top\library\Register;
|
||||||
use top\library\route\driver\Command;
|
use top\library\route\driver\Command;
|
||||||
use top\library\route\driver\Pathinfo;
|
use top\library\route\driver\Pathinfo;
|
||||||
use top\library\Router;
|
use top\library\Router;
|
||||||
|
use top\middleware\View;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求类
|
* 请求类
|
||||||
|
@ -397,7 +398,7 @@ class Request
|
||||||
private function runAction()
|
private function runAction()
|
||||||
{
|
{
|
||||||
$userMiddleware = Register::get('Config')->get('middleware');
|
$userMiddleware = Register::get('Config')->get('middleware');
|
||||||
$systemMiddleware = [Init::class];
|
$systemMiddleware = [Init::class, View::class];
|
||||||
|
|
||||||
$middleware = array_merge($systemMiddleware, $userMiddleware);
|
$middleware = array_merge($systemMiddleware, $userMiddleware);
|
||||||
foreach ($middleware as $key => $value) {
|
foreach ($middleware as $key => $value) {
|
||||||
|
|
|
@ -46,9 +46,9 @@ class Smarty implements TemplateIfs
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function fetch($file, $param, $cache)
|
public function fetch($file, $params, $cache)
|
||||||
{
|
{
|
||||||
foreach ($param as $k => $v) {
|
foreach ($params as $k => $v) {
|
||||||
$this->smarty->assign($k, $v);
|
$this->smarty->assign($k, $v);
|
||||||
}
|
}
|
||||||
$templateFile = $this->config['dir'] . $file . '.' . $this->config['ext'];
|
$templateFile = $this->config['dir'] . $file . '.' . $this->config['ext'];
|
||||||
|
|
|
@ -2,27 +2,24 @@
|
||||||
|
|
||||||
namespace top\library\template\driver;
|
namespace top\library\template\driver;
|
||||||
|
|
||||||
use top\library\template\ifs\TemplateIfs;
|
|
||||||
use top\library\Register;
|
use top\library\Register;
|
||||||
use top\library\template\driver\tags\Tags;
|
use top\library\template\driver\tags\Engine;
|
||||||
|
use top\library\template\ifs\TemplateIfs;
|
||||||
|
|
||||||
/**
|
|
||||||
* 默认的视图驱动
|
|
||||||
* @author topnuomi 2018年11月22日
|
|
||||||
*/
|
|
||||||
class Top implements TemplateIfs
|
class Top implements TemplateIfs
|
||||||
{
|
{
|
||||||
|
|
||||||
private static $instance;
|
private static $instance = null;
|
||||||
|
|
||||||
// 标签类实例
|
private $engine = null;
|
||||||
private $tags;
|
|
||||||
|
|
||||||
// 视图配置
|
private $config = null;
|
||||||
private $config;
|
|
||||||
|
|
||||||
// 缓存状态
|
private $cache = false;
|
||||||
private $cacheStatus = false;
|
|
||||||
|
private function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public static function instance()
|
public static function instance()
|
||||||
{
|
{
|
||||||
|
@ -32,56 +29,45 @@ class Top implements TemplateIfs
|
||||||
return self::$instance;
|
return self::$instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return $this
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
// TODO: Implement run() method.
|
$this->engine = new Engine();
|
||||||
$this->tags = Tags::instance();
|
|
||||||
$this->config = Register::get('Config')->get('view');
|
$this->config = Register::get('Config')->get('view');
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function __construct()
|
private function compile($filename)
|
||||||
{
|
{
|
||||||
}
|
$compileFileName = $this->config['compileDir'] . md5($filename) . '.php';
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理模板标签
|
|
||||||
* @param $file
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function processing($file)
|
|
||||||
{
|
|
||||||
$compileFileName = $this->config['compileDir'] . md5($file) . '.php';
|
|
||||||
if (!file_exists($compileFileName) || DEBUG === true) {
|
if (!file_exists($compileFileName) || DEBUG === true) {
|
||||||
$compileFileName = $this->tags->processing($file);
|
if (!is_dir($this->config['compileDir'])) {
|
||||||
|
mkdir($this->config['compileDir'], 0777, true);
|
||||||
|
}
|
||||||
|
$content = file_get_contents($filename);
|
||||||
|
$content = $this->engine->compile($content);
|
||||||
|
file_put_contents($compileFileName, $content);
|
||||||
}
|
}
|
||||||
return $compileFileName;
|
return $compileFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function cache($status)
|
||||||
* 缓存为文件
|
|
||||||
* @param $file
|
|
||||||
* @param $param
|
|
||||||
* @return string
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function cacheFile($file, $param)
|
|
||||||
{
|
{
|
||||||
|
$this->cache = $status;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function cacheFile($filename, $params)
|
||||||
|
{
|
||||||
|
|
||||||
if (isset($_SERVER['REQUEST_URI'])) {
|
if (isset($_SERVER['REQUEST_URI'])) {
|
||||||
$fileIdent = md5($_SERVER['REQUEST_URI']);
|
$fileIdent = md5($_SERVER['REQUEST_URI']);
|
||||||
} else {
|
} else {
|
||||||
$route = Register::get('Route');
|
$fileIdent = request()->module() . request()->controller() . request()->method();
|
||||||
$fileIdent = $route->module . $route->ctrl . $route->action;
|
|
||||||
}
|
}
|
||||||
$filePath = $this->config['cacheDir'] . $fileIdent;
|
$filePath = $this->config['cacheDir'] . $fileIdent;
|
||||||
$cache = Register::get('ViewCache');
|
$cache = Register::get('FileCache');
|
||||||
extract($param);
|
extract($params);
|
||||||
ob_start();
|
ob_start();
|
||||||
require $file;
|
require $filename;
|
||||||
$content = ob_get_clean();
|
$content = ob_get_clean();
|
||||||
ob_clean();
|
ob_clean();
|
||||||
if ($cache->set($filePath, $content)) {
|
if ($cache->set($filePath, $content)) {
|
||||||
|
@ -91,35 +77,16 @@ class Top implements TemplateIfs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function fetch($file, $params, $cache)
|
||||||
* 是否开启页面静态缓存
|
|
||||||
* @param bool $status
|
|
||||||
*/
|
|
||||||
public function cache($status)
|
|
||||||
{
|
{
|
||||||
$this->cacheStatus = $status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取最终的视图文件
|
|
||||||
* @param $file
|
|
||||||
* @param $param
|
|
||||||
* @param $cache
|
|
||||||
* @return false|mixed|string
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function fetch($file, $param, $cache)
|
|
||||||
{
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
$filename = $this->config['dir'] . $file . '.' . $this->config['ext'];
|
$filename = $this->config['dir'] . $file . '.' . $this->config['ext'];
|
||||||
if (file_exists($filename)) {
|
if (file_exists($filename)) {
|
||||||
$filename = $this->processing($filename);
|
$filename = $this->compile($filename);
|
||||||
if ($this->cacheStatus || $cache) {
|
if ($this->cache || $cache) {
|
||||||
$filename = $this->cacheFile($filename, $param);
|
$filename = $this->cacheFile($filename, $params);
|
||||||
|
return file_get_contents($filename);
|
||||||
} else {
|
} else {
|
||||||
extract($param);
|
extract($params);
|
||||||
}
|
|
||||||
if (file_exists($filename)) {
|
|
||||||
ob_start();
|
ob_start();
|
||||||
require $filename;
|
require $filename;
|
||||||
$content = ob_get_contents();
|
$content = ob_get_contents();
|
||||||
|
@ -127,7 +94,8 @@ class Top implements TemplateIfs
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new \Exception('视图文件 \'' . $file . '\' 不存在');
|
throw new \Exception("模板文件 $file 不存在");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ class Twig implements TemplateIfs
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function fetch($file, $param, $cache)
|
public function fetch($file, $params, $cache)
|
||||||
{
|
{
|
||||||
$baseViewDir = rtrim($this->config['dir'], '/') . '/';
|
$baseViewDir = rtrim($this->config['dir'], '/') . '/';
|
||||||
$loader = new FilesystemLoader($baseViewDir);
|
$loader = new FilesystemLoader($baseViewDir);
|
||||||
|
@ -52,6 +52,6 @@ class Twig implements TemplateIfs
|
||||||
'debug' => DEBUG
|
'debug' => DEBUG
|
||||||
]);
|
]);
|
||||||
$templateFile = '@base/' . $file . '.' . $this->config['ext'];
|
$templateFile = '@base/' . $file . '.' . $this->config['ext'];
|
||||||
return $template->render($templateFile, $param);
|
return $template->render($templateFile, $params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,332 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace top\library\template\driver\tags;
|
||||||
|
|
||||||
|
use top\library\Register;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板标签库(支持模板继承)
|
||||||
|
* Class Template
|
||||||
|
* @package lib
|
||||||
|
*/
|
||||||
|
class Engine
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string 左定界符
|
||||||
|
*/
|
||||||
|
private $left = '<';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string 右定界符
|
||||||
|
*/
|
||||||
|
private $right = '>';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array 标签定义
|
||||||
|
*/
|
||||||
|
protected $tags = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var null 模板配置
|
||||||
|
*/
|
||||||
|
protected $config = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array 默认标签定义
|
||||||
|
*/
|
||||||
|
private $defaultTags = [
|
||||||
|
'if' => ['attr' => 'condition', 'close' => 1],
|
||||||
|
'else' => ['attr' => 'condition', 'close' => 0],
|
||||||
|
'volist' => ['attr' => 'name,id,key', 'close' => 1],
|
||||||
|
];
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->config = Register::get('Config')->get('view');
|
||||||
|
if (isset($this->config['left']) && $this->config['left']) {
|
||||||
|
$this->left = $this->config['left'];
|
||||||
|
}
|
||||||
|
if (isset($this->config['right']) && $this->config['right']) {
|
||||||
|
$this->right = $this->config['right'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理模板继承
|
||||||
|
*/
|
||||||
|
private function parseExtend($tmpl)
|
||||||
|
{
|
||||||
|
$pattern = '#' . $this->left . 'extend +file=[\'"](.*?)[\'"] +/' . $this->right . '#';
|
||||||
|
preg_match($pattern, $tmpl, $matches);
|
||||||
|
if (!empty($matches)) {
|
||||||
|
$blockPattern = '#' . $this->left . 'block +name=[\'"](.*?)[\'"]' . $this->right;
|
||||||
|
$blockPattern .= '([\s\S]*?)' . $this->left . '\/block' . $this->right . '#';
|
||||||
|
// 获得被继承的模板内容
|
||||||
|
$file = $this->config['dir'] . $matches[1] . '.html';
|
||||||
|
$extendFileContent = null;
|
||||||
|
if (file_exists($file)) {
|
||||||
|
$extendFileContent = file_get_contents($file);
|
||||||
|
}
|
||||||
|
// 处理继承中的include标签
|
||||||
|
$tempContent = $this->parseInclude($extendFileContent);
|
||||||
|
$extendFileContent = $tempContent !== false ? $tempContent : $extendFileContent;
|
||||||
|
// 被继承模板中的块
|
||||||
|
preg_match_all($blockPattern, $extendFileContent, $extendResult);
|
||||||
|
// 继承模板中的块
|
||||||
|
preg_match_all($blockPattern, $tmpl, $templateResult);
|
||||||
|
// 组合搜索的块数组
|
||||||
|
$search = [];
|
||||||
|
$defaultContent = [];
|
||||||
|
for ($i = 0; $i < count($extendResult[0]); $i++) {
|
||||||
|
$search[$extendResult[1][$i]] = $extendResult[0][$i];
|
||||||
|
$defaultContent[$extendResult[1][$i]] = $extendResult[2][$i];
|
||||||
|
}
|
||||||
|
// 组合替换的块数组
|
||||||
|
$replace = [];
|
||||||
|
for ($j = 0; $j < count($templateResult[0]); $j++) {
|
||||||
|
$replace[$templateResult[1][$j]] = $templateResult[2][$j];
|
||||||
|
}
|
||||||
|
// 块是否在继承模板中存在
|
||||||
|
$searchArray = [];
|
||||||
|
$replaceArray = [];
|
||||||
|
foreach ($search as $key => $value) {
|
||||||
|
$searchArray[] = $value;
|
||||||
|
if (isset($replace[$key])) {
|
||||||
|
$replaceArray[] = $replace[$key];
|
||||||
|
} else {
|
||||||
|
$replaceArray[] = $defaultContent[$key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$tmpl = str_replace($searchArray, $replaceArray, $extendFileContent);
|
||||||
|
}
|
||||||
|
return $tmpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理include标签
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function parseInclude($tmpl)
|
||||||
|
{
|
||||||
|
$pattern = '#' . $this->left . 'include +file=[\'"](.*?)[\'"] +/' . $this->right . '#';
|
||||||
|
$tmpl = preg_replace_callback($pattern, function ($result) {
|
||||||
|
$str = null;
|
||||||
|
$file = $this->config['dir'] . $result[1] . '.html';
|
||||||
|
if (file_exists($file)) {
|
||||||
|
$str = file_get_contents($file);
|
||||||
|
}
|
||||||
|
return $str;
|
||||||
|
}, $tmpl);
|
||||||
|
// 处理多层include
|
||||||
|
if ($this->hasInclude($tmpl)) {
|
||||||
|
$tmpl = $this->parseInclude($tmpl);
|
||||||
|
}
|
||||||
|
return $tmpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检测是否含有include
|
||||||
|
* @param $tmpl
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function hasInclude($tmpl)
|
||||||
|
{
|
||||||
|
$pattern = '#' . $this->left . 'include +file=[\'"](.*?)[\'"] +/' . $this->right . '#';
|
||||||
|
preg_match($pattern, $tmpl, $matches);
|
||||||
|
return !empty($matches);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分析参数以及函数输出
|
||||||
|
*/
|
||||||
|
private function parseVars($tmpl)
|
||||||
|
{
|
||||||
|
preg_match_all('#{(.*?)}#', $tmpl, $matches);
|
||||||
|
$search = [];
|
||||||
|
$replace = [];
|
||||||
|
for ($i = 0; $i < count($matches[0]); $i++) {
|
||||||
|
$start = substr($matches[1][$i], 0, 1);
|
||||||
|
if ($start == '$') {
|
||||||
|
$search[] = $matches[0][$i];
|
||||||
|
$replace[] = '<?php echo ' . $matches[1][$i] . '; ?>';
|
||||||
|
} elseif ($start == ':') {
|
||||||
|
$search[] = $matches[0][$i];
|
||||||
|
$replace[] = '<?php echo ' . ltrim($matches[1][$i], ':') . '; ?>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$tmpl = str_replace($search, $replace, $tmpl);
|
||||||
|
return $tmpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理用户自定义标签
|
||||||
|
* @param $tmpl
|
||||||
|
* @return null|string|string[]
|
||||||
|
*/
|
||||||
|
public function parseCustomizeTags($tmpl)
|
||||||
|
{
|
||||||
|
return $this->parseTags($tmpl, $this->tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理默认的标签
|
||||||
|
* @param $tmpl
|
||||||
|
* @return null|string|string[]
|
||||||
|
*/
|
||||||
|
private function parseDefaultTags($tmpl)
|
||||||
|
{
|
||||||
|
return $this->parseTags($tmpl, $this->defaultTags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 进行标签处理
|
||||||
|
* @param $tmpl
|
||||||
|
* @param $tags
|
||||||
|
* @return null|string|string[]
|
||||||
|
*/
|
||||||
|
private function parseTags($tmpl, $tags)
|
||||||
|
{
|
||||||
|
foreach ($tags as $name => $item) {
|
||||||
|
$pattern = '#' . $this->left . $name . ' +(.*?)';
|
||||||
|
$pattern .= ((!$item['close']) ? '\/' . $this->right : $this->right) . '#';
|
||||||
|
$tmpl = preg_replace_callback($pattern, function ($matches) use ($name, $item) {
|
||||||
|
$function = '_' . $name . '_start';
|
||||||
|
$pattern = '#(.*?)=[\'"](.*?)[\'"]#';
|
||||||
|
preg_match_all($pattern, $matches[1], $result);
|
||||||
|
$tag = [];
|
||||||
|
if (!empty($result)) {
|
||||||
|
foreach ($result[1] as $key => $value) {
|
||||||
|
$tag[trim($value, ' ')] = $result[2][$key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '<?php ' . $this->{$function}($tag) . ' ?>';
|
||||||
|
}, $tmpl);
|
||||||
|
// 处理闭合标签
|
||||||
|
if ($item['close']) {
|
||||||
|
$pattern = '#' . $this->left . '\/' . $name . '' . $this->right . '#';
|
||||||
|
$tmpl = preg_replace_callback($pattern, function ($matches) use ($name) {
|
||||||
|
$function = '_' . $name . '_end';
|
||||||
|
return '<?php ' . $this->{$function}() . ' ?>';
|
||||||
|
}, $tmpl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return preg_replace('#\?>([\r|\n|\s]*?)<\?php#', '', $tmpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理raw标签
|
||||||
|
* @param $tmpl
|
||||||
|
* @return null|string|string[]
|
||||||
|
*/
|
||||||
|
private function parseRaw($tmpl)
|
||||||
|
{
|
||||||
|
$pattern = '#' . $this->left . 'raw' . $this->right . '([\s\S]*?)';
|
||||||
|
$pattern .= $this->left . '\/raw' . $this->right . '#';
|
||||||
|
$tmpl = preg_replace_callback($pattern, function ($matches) {
|
||||||
|
return str_replace([
|
||||||
|
$this->left, $this->right,
|
||||||
|
'{', '}'
|
||||||
|
], [
|
||||||
|
'<raw!--', '--raw>',
|
||||||
|
'{raw!--', '--raw}'
|
||||||
|
], $matches[1]);
|
||||||
|
}, $tmpl);
|
||||||
|
return $tmpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 还原raw
|
||||||
|
* @param $tmpl
|
||||||
|
* @return null|string|string[]
|
||||||
|
*/
|
||||||
|
public function returnRaw($tmpl)
|
||||||
|
{
|
||||||
|
$pattern = '#[{|<]raw!--([\s\S]*?)--raw[>|}]#';
|
||||||
|
$tmpl = preg_replace_callback($pattern, function ($matches) {
|
||||||
|
$left = substr($matches[0], 0, 1);
|
||||||
|
$right = substr($matches[0], -1);
|
||||||
|
return $left . $matches[1] . $right;
|
||||||
|
}, $tmpl);
|
||||||
|
return $tmpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if标签
|
||||||
|
* @param $tag
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function _if_start($tag)
|
||||||
|
{
|
||||||
|
return 'if (' . $tag['condition'] . '):';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if标签结束
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function _if_end()
|
||||||
|
{
|
||||||
|
return 'endif;';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* else标签(支持条件)
|
||||||
|
* @param $tag
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function _else_start($tag)
|
||||||
|
{
|
||||||
|
if (isset($tag['condition'])) {
|
||||||
|
$content = 'elseif (' . $tag['condition'] . '):';
|
||||||
|
} else {
|
||||||
|
$content = 'else:';
|
||||||
|
}
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* volist标签
|
||||||
|
* @param $tag
|
||||||
|
* @return null|string
|
||||||
|
*/
|
||||||
|
private function _volist_start($tag)
|
||||||
|
{
|
||||||
|
if (substr($tag['name'], 0, 1) == ':') {
|
||||||
|
$name = substr($tag['name'], 1);
|
||||||
|
} else {
|
||||||
|
$name = '$' . $tag['name'];
|
||||||
|
}
|
||||||
|
$str = (empty($tag['key'])) ? null : '$' . $tag['key'] . ' = 0; ';
|
||||||
|
$str .= 'foreach (' . $name . ' as $' . $tag['id'] . '):';
|
||||||
|
$str .= (empty($tag['key']) ? null : '$' . $tag['key'] . '++;');
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* volist标签结束
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function _volist_end()
|
||||||
|
{
|
||||||
|
return 'endforeach;';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取编译后的内容
|
||||||
|
* @return null|string|string[]
|
||||||
|
*/
|
||||||
|
public function compile($tmpl)
|
||||||
|
{
|
||||||
|
$tmpl = $this->parseRaw($tmpl);
|
||||||
|
// 处理模板继承标签
|
||||||
|
$tmpl = $this->parseExtend($tmpl);
|
||||||
|
// 处理include标签
|
||||||
|
$tmpl = $this->parseInclude($tmpl);
|
||||||
|
// 处理定义的标签
|
||||||
|
$tmpl = $this->parseDefaultTags($tmpl);
|
||||||
|
// 处理变量以及函数
|
||||||
|
$tmpl = $this->parseVars($tmpl);
|
||||||
|
return $tmpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,174 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace top\library\template\driver\tags;
|
|
||||||
|
|
||||||
use top\library\Register;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 模板标签处理类
|
|
||||||
* @author topnuomi 2018年11月21日
|
|
||||||
*/
|
|
||||||
class Tags
|
|
||||||
{
|
|
||||||
|
|
||||||
public static $instance;
|
|
||||||
|
|
||||||
private $processing;
|
|
||||||
|
|
||||||
private $tags;
|
|
||||||
|
|
||||||
public $left;
|
|
||||||
|
|
||||||
public $right;
|
|
||||||
|
|
||||||
private $selfTags = [
|
|
||||||
// 注释
|
|
||||||
'//(.*?)' => '/*\\1*/',
|
|
||||||
'/\*(.*?)\*/' => '/*\\1*/',
|
|
||||||
// 原生php代码
|
|
||||||
'php' => '<?php ',
|
|
||||||
'/php' => ' ?>',
|
|
||||||
// 变量直接输出
|
|
||||||
'\$(.*?)' => 'echo \$\\1;',
|
|
||||||
':(.*?)' => 'echo \\1;',
|
|
||||||
// 模板中变量赋值
|
|
||||||
'assign:name,value' => '$name = value;',
|
|
||||||
// if
|
|
||||||
'empty:name' => 'if (empty(name)):',
|
|
||||||
'notempty:name' => 'if (!empty(name)):',
|
|
||||||
'if (.*?)' => 'if (\\1):',
|
|
||||||
'elseif (.*?) /' => 'elseif (\\1):',
|
|
||||||
'else /' => 'else:',
|
|
||||||
'/(if|empty|notempty)' => 'endif;',
|
|
||||||
// foreach
|
|
||||||
'loop (.*?)' => '$i = 0; foreach (\\1): $i++;',
|
|
||||||
'/loop' => 'endforeach;',
|
|
||||||
// for
|
|
||||||
'for (.*?)' => 'for (\\1):',
|
|
||||||
'/for' => 'endfor;',
|
|
||||||
// switch
|
|
||||||
'switch:name' => 'switch (\\1):',
|
|
||||||
'case:value' => 'case \\1:',
|
|
||||||
'/case' => 'break;',
|
|
||||||
'default /' => 'default:',
|
|
||||||
'/switch' => 'endswitch;'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前类实例
|
|
||||||
* @return Tags
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public static function instance()
|
|
||||||
{
|
|
||||||
if (!self::$instance) {
|
|
||||||
self::$instance = new self();
|
|
||||||
}
|
|
||||||
return self::$instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tags constructor.
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
private function __construct()
|
|
||||||
{
|
|
||||||
$config = Register::get('Config')->get('view');
|
|
||||||
$this->left = (isset($config['left']) && $config['left']) ? $config['left'] : '{';
|
|
||||||
$this->right = (isset($config['right']) && $config['right']) ? $config['right'] : '}';
|
|
||||||
$this->compileDir = (isset($config['compileDir']) && $config['compileDir']) ? $config['compileDir'] : './runtime/';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置模板标签
|
|
||||||
* @param array $array
|
|
||||||
*/
|
|
||||||
private function setTags($array)
|
|
||||||
{
|
|
||||||
foreach ($array as $key => $value) {
|
|
||||||
$tagsInfo = explode(':', $key);
|
|
||||||
$tag = $tagsInfo[0];
|
|
||||||
// 第一个值不是为空(不是{:xxx}语法)
|
|
||||||
if ($tagsInfo[0]) {
|
|
||||||
// 存在除标签外的其他属性
|
|
||||||
if (isset($tagsInfo[1])) {
|
|
||||||
$attrArr = explode(',', $tagsInfo[1]);
|
|
||||||
// 拼接正则表达式
|
|
||||||
$processingArr = [];
|
|
||||||
for ($i = 0; $i < count($attrArr); $i++) {
|
|
||||||
$processingArr[$attrArr[$i]] = '\\' . ($i + 1);
|
|
||||||
$tag .= '\s' . $attrArr[$i] . '="(.*?)"';
|
|
||||||
}
|
|
||||||
$keys = array_keys($processingArr);
|
|
||||||
$vals = array_values($processingArr);
|
|
||||||
$value = str_replace($keys, $vals, $value);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// {:xxx}语法则保持原样
|
|
||||||
$tag = $key;
|
|
||||||
}
|
|
||||||
// 正则界定符使用#号,避免过多的转义字符
|
|
||||||
$this->tags[] = '#' . $this->left . $tag . $this->right . '#i';
|
|
||||||
// 不拼接原生脚本开始结束标记符
|
|
||||||
$this->processing[] = ($value != '<?php ' && $value != ' ?>') ? '<?php ' . $value . ' ?>' : $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 预处理引入视图标签(为了保证require进来的文件中的模板标签可用,必须先进行预处理)
|
|
||||||
* @param string $filename
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function processingViewTag($filename)
|
|
||||||
{
|
|
||||||
$tags = [
|
|
||||||
'view:name' => '$__view__config = \\top\\library\\Register::get(\'Config\')->get(\'view\'); require \'./\' . $__view__config[\'dir\'] . \'name\' . \'.\' . $__view__config[\'ext\'];'
|
|
||||||
];
|
|
||||||
$this->setTags($tags);
|
|
||||||
$content = file_get_contents($filename);
|
|
||||||
$result = preg_replace($this->tags, $this->processing, $content);
|
|
||||||
$tempFileName = $this->compileDir . md5($filename) . '_temp.php';
|
|
||||||
if (!is_dir($this->compileDir)) {
|
|
||||||
mkdir($this->compileDir, 0777, true);
|
|
||||||
}
|
|
||||||
// 创建临时文件
|
|
||||||
file_put_contents($tempFileName, $result);
|
|
||||||
ob_start();
|
|
||||||
require $tempFileName;
|
|
||||||
// 拿到临时创建的文件内容
|
|
||||||
$content = ob_get_contents();
|
|
||||||
ob_clean();
|
|
||||||
// 删除临时文件
|
|
||||||
@unlink($tempFileName);
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理模板文件中的标签(插件模板不解析view标签)
|
|
||||||
* @param $filename
|
|
||||||
* @return string
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function processing($filename)
|
|
||||||
{
|
|
||||||
$content = $this->processingViewTag($filename);
|
|
||||||
// 加载预设模板标签
|
|
||||||
$this->setTags($this->selfTags);
|
|
||||||
// 加载自定义模板标签
|
|
||||||
// 文件位置固定
|
|
||||||
$tagsFile = APP_PATH . request()->module() . '/config/tags.php';
|
|
||||||
if (file_exists($tagsFile)) {
|
|
||||||
$tags = require $tagsFile;
|
|
||||||
$this->setTags($tags);
|
|
||||||
}
|
|
||||||
$result = preg_replace($this->tags, $this->processing, $content);
|
|
||||||
if (!is_dir($this->compileDir)) {
|
|
||||||
mkdir($this->compileDir, 0777, true);
|
|
||||||
}
|
|
||||||
// 最终过滤内容中?\>与<?php中间的内容
|
|
||||||
$result = preg_replace('#\?>([\r|\n|\s]*?)<\?php#', '', $result);
|
|
||||||
$filename = $this->compileDir . md5($filename) . '.php';
|
|
||||||
file_put_contents($filename, "<?php /* topnuomi */ (!defined('APP_PATH')) && exit(0); ?>" . $result);
|
|
||||||
return $filename;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -16,9 +16,9 @@ interface TemplateIfs
|
||||||
/**
|
/**
|
||||||
* 处理模板
|
* 处理模板
|
||||||
* @param $file
|
* @param $file
|
||||||
* @param $param
|
* @param $params
|
||||||
* @param $cache
|
* @param $cache
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function fetch($file, $param, $cache);
|
public function fetch($file, $params, $cache);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,9 +35,9 @@ class Init implements MiddlewareIfs
|
||||||
});
|
});
|
||||||
|
|
||||||
// 视图文件缓存
|
// 视图文件缓存
|
||||||
/*Register::set('ViewCache', function () {
|
Register::set('FileCache', function () {
|
||||||
return File::instance();
|
return File::instance();
|
||||||
});*/
|
});
|
||||||
|
|
||||||
// 配置文件中配置的注册
|
// 配置文件中配置的注册
|
||||||
$initRegister = Register::get('Config')->get('register');
|
$initRegister = Register::get('Config')->get('register');
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace top\middleware;
|
||||||
|
|
||||||
|
use top\library\http\Response;
|
||||||
|
use top\library\Register;
|
||||||
|
use top\middleware\ifs\MiddlewareIfs;
|
||||||
|
|
||||||
|
class View implements MiddlewareIfs
|
||||||
|
{
|
||||||
|
|
||||||
|
public function before()
|
||||||
|
{
|
||||||
|
// TODO: Implement before() method.
|
||||||
|
if (!DEBUG) {
|
||||||
|
if (isset($_SERVER['REQUEST_URI'])) {
|
||||||
|
$fileIdent = md5($_SERVER['REQUEST_URI']);
|
||||||
|
} else {
|
||||||
|
$fileIdent = request()->module() . request()->controller() . request()->method();
|
||||||
|
}
|
||||||
|
$config = Register::get('Config')->get('view');
|
||||||
|
$filename = $config['cacheDir'] . $fileIdent;
|
||||||
|
$cache = Register::get('FileCache');
|
||||||
|
if ($cache->check($filename, $config['cacheTime'])) {
|
||||||
|
echo Response::instance()->dispatch(file_get_contents($filename));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function after($data)
|
||||||
|
{
|
||||||
|
// TODO: Implement after() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
父级模板
|
||||||
|
|
||||||
|
BODY
|
||||||
|
49999985000001
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,11 +1,14 @@
|
||||||
<?php /* topnuomi */ (!defined('APP_PATH')) && exit(0); ?><!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Title</title>
|
<title>Title</title>
|
||||||
<script src="/resource/jquery.min.js"></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Hello</h1> <?php $i = 0; foreach ($lists as $value): $i++; echo $value; endforeach; ?>
|
父级模板
|
||||||
|
|
||||||
|
BODY
|
||||||
|
<?php echo $num; ?>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -1,13 +0,0 @@
|
||||||
<?php /* topnuomi */ (!defined('APP_PATH')) && exit(0); ?><!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport"
|
|
||||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
||||||
<title>Document</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Loading…
Reference in New Issue