From 4dc26f5dab90b93a96fddfec5bdfdd448cabed4f Mon Sep 17 00:00:00 2001 From: oldrind <1401019000@qq.com> Date: Thu, 18 Feb 2016 21:23:55 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E8=BF=9B=E6=A8=A1=E6=9D=BF=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E6=A3=80=E6=B5=8B=E6=96=B9=E5=BC=8F=EF=BC=9B=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=85=A8=E5=B1=80=E5=B8=83=E5=B1=80=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=BC=80=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- library/think/Template.php | 81 +++++++++--- library/think/template/driver/File.php | 52 ++++++-- library/think/template/driver/Sae.php | 44 +++++-- tests/thinkphp/library/think/extend2.html | 2 +- tests/thinkphp/library/think/include2.html | 2 +- tests/thinkphp/library/think/layout.html | 4 +- tests/thinkphp/library/think/layout2.html | 2 + tests/thinkphp/library/think/templateTest.php | 123 ++++++++---------- 8 files changed, 199 insertions(+), 111 deletions(-) create mode 100644 tests/thinkphp/library/think/layout2.html diff --git a/library/think/Template.php b/library/think/Template.php index 17b8ee9c..26d8c039 100644 --- a/library/think/Template.php +++ b/library/think/Template.php @@ -34,6 +34,9 @@ class Template 'compile_type' => 'file', // 模板编译类型 'cache_prefix' => '', // 模板缓存前缀标识,可以动态改变 'cache_time' => 0, // 模板缓存有效期 0 为永久,(以数字为值,单位:秒) + 'cache_record_file' => 'cache_record_file', // 记录模板更新时间的文件 + 'layout_on' => false, // 布局模板开关 + 'layout_name' => 'layout', // 布局模板入口文件 'layout_item' => '{__CONTENT__}', // 布局模板的内容替换标识 'taglib_begin' => '{', // 标签库标签开始标记 'taglib_end' => '}', // 标签库标签结束标记 @@ -47,8 +50,10 @@ class Template 'namespace' => '\\think\\template\\driver\\', ]; - private $literal = []; - protected $storage = null; + private $literal = []; + private $includeFile = []; // 记录所有模板包含的文件路径及更新时间 + private $md5Key = ''; // 保存当前模板的md5码 + protected $storage = null; /** * 架构函数 @@ -153,7 +158,7 @@ class Template * 渲染模板文件 * @access public * @param string $template 模板文件 - * @param array $vars 模板变量 + * @param array $vars 模板变量 * @param array $config 模板参数 * @return void */ @@ -190,7 +195,7 @@ class Template * 渲染模板内容 * @access public * @param string $content 模板内容 - * @param array $vars 模板变量 + * @param array $vars 模板变量 * @return void */ public function fetch($content, $vars = []) @@ -211,7 +216,7 @@ class Template * 检查编译缓存是否有效 * 如果无效则需要重新编译 * @access private - * @param string $template 模板文件名 + * @param string $template 模板文件名 * @param string $cacheFile 缓存文件名 * @return boolean */ @@ -221,8 +226,20 @@ class Template // 优先对配置设定检测 return false; } - // 检查编译存储是否有效 - return $this->storage->check($template, $cacheFile, $this->config['cache_time']); + $this->md5Key = md5($template); + $recordFile = $this->config['cache_path'] . md5($this->config['cache_record_file']) . $this->config['cache_suffix']; + if (!is_file($recordFile)) { + return false; + } else { + $this->includeFile = $this->storage->read($recordFile, [], true); + if (!isset($this->includeFile[$this->md5Key])) { + // 缓存记录中无此模板 + return false; + } else { + // 检查编译存储是否有效 + return $this->storage->check($this->includeFile[$this->md5Key], $cacheFile, $this->config['cache_time']); + } + } } /** @@ -249,6 +266,26 @@ class Template */ private function compiler(&$content, $cacheFile) { + // 判断是否启用布局 + if ($this->config['layout_on']) { + if (false !== strpos($content, '{__NOLAYOUT__}')) { + // 可以单独定义不使用布局 + $content = str_replace('{__NOLAYOUT__}', '', $content); + } else { + // 读取布局模板 + $layoutFile = $this->parseTemplateFile($this->config['layout_name']); + // 检查布局文件 + if (is_file($layoutFile)) { + // 替换布局的主体内容 + $content = str_replace($this->config['layout_item'], $content, file_get_contents($layoutFile)); + // 记录布局文件的更新时间 + $this->includeFile[$this->md5Key][filemtime($layoutFile)] = $layoutFile; + } else { + throw new Exception('template not exist:' . $layoutFile, 10700); + } + } + } + // 模板解析 $this->parse($content); // 添加安全代码 @@ -266,6 +303,10 @@ class Template $content = str_replace(array_keys($replace), array_values($replace), $content); // 编译存储 $this->storage->write($cacheFile, $content); + // 保存模板更新记录 + $string = "includeFile, true) . ';'; + $this->storage->write($this->config['cache_path'] . md5($this->config['cache_record_file']) . $this->config['cache_suffix'], $string); + $this->includeFile = []; return; } @@ -361,15 +402,17 @@ class Template $content = str_replace($matches[0], '', $content); // 解析Layout标签 $array = $this->parseAttr($matches[0]); - //if (!C('LAYOUT_ON') || C('LAYOUT_NAME') != $array['name']) { - // 读取布局模板 - $layoutFile = (defined('THEME_PATH') && substr_count($array['name'], '/') < 2 ? THEME_PATH : $this->config['view_path']) . $array['name'] . $this->config['view_suffix']; - if (is_file($layoutFile)) { - $replace = isset($array['replace']) ? $array['replace'] : $this->config['layout_item']; - // 替换布局的主体内容 - $content = str_replace($replace, $content, file_get_contents($layoutFile)); + if (!$this->config['layout_on'] || $this->config['layout_name'] != $array['name']) { + // 读取布局模板 + $layoutFile = $this->parseTemplateFile($array['name']); + if (is_file($layoutFile)) { + $replace = isset($array['replace']) ? $array['replace'] : $this->config['layout_item']; + // 替换布局的主体内容 + $content = str_replace($replace, $content, file_get_contents($layoutFile)); + // 记录布局文件的更新时间 + $this->includeFile[$this->md5Key][filemtime($layoutFile)] = $layoutFile; + } } - //} } else { $content = str_replace('{__NOLAYOUT__}', '', $content); } @@ -397,7 +440,7 @@ class Template foreach ($array as $k => $v) { // 以$开头字符串转换成模板变量 if (0 === strpos($v, '$')) { - $v = ltrim($this->config['tpl_begin'], '\\') . $v . ltrim($this->config['tpl_end'], '\\'); + $v = $this->get(substr($v, 1)); } $parseStr = str_replace('[' . $k . ']', $v, $parseStr); } @@ -422,7 +465,7 @@ class Template private function parseExtend(&$content) { $regex = $this->getRegex('extend'); - $array = $blocks = $extBlocks = []; + $array = $blocks = $extBlocks = []; $extend = ''; $fun = function ($template) use (&$fun, &$regex, &$array, &$extend, &$blocks, &$extBlocks) { if (preg_match($regex, $template, $matches)) { @@ -515,7 +558,7 @@ class Template 'content' => substr($content, $start, $len), 'end' => $end, ]; - $keys[] = $begin['offset']; + $keys[] = $begin['offset']; } else { continue; } @@ -920,6 +963,8 @@ class Template if (is_file($template)) { // 获取模板文件内容 $parseStr .= file_get_contents($template); + // 记录模板文件的更新时间 + $this->includeFile[$this->md5Key][filemtime($template)] = $template; } } return $parseStr; diff --git a/library/think/template/driver/File.php b/library/think/template/driver/File.php index 2fb143a8..35f7c802 100644 --- a/library/think/template/driver/File.php +++ b/library/think/template/driver/File.php @@ -15,7 +15,12 @@ use think\Exception; class File { - // 写入编译缓存 + /** + * 写入编译缓存 + * @string $cacheFile 缓存的文件名 + * @string $content 缓存的内容 + * @return void|array + */ public function write($cacheFile, $content) { // 检测模板目录 @@ -29,22 +34,43 @@ class File } } - // 读取编译编译 - public function read($cacheFile, $vars) + /** + * 读取编译编译 + * @string $cacheFile 缓存的文件名 + * @array $vars 变量数组 + * @boolean $isReturn 是否返回内容 + * @return void|array + */ + public function read($cacheFile, $vars = [], $isReturn = false) { - // 模板阵列变量分解成为独立变量 - extract($vars, EXTR_OVERWRITE); - //载入模版缓存文件 - include $cacheFile; + if (!empty($vars) && is_array($vars)) { + // 模板阵列变量分解成为独立变量 + extract($vars, EXTR_OVERWRITE); + } + if ($isReturn) { + //载入模版缓存文件 + include $cacheFile; + } else { + return include $cacheFile; + } } - // 检查编译缓存是否有效 - public function check($template, $cacheFile, $cacheTime) + /** + * 检查编译缓存是否有效 + * @array $template 用到的模板更新时间列表 + * @string $cacheFile 缓存的文件名 + * @int $cacheTime 缓存时间 + * @return boolean + */ + public function check($files, $cacheFile, $cacheTime) { - if (!is_file($cacheFile) || (is_file($template) && filemtime($template) > filemtime($cacheFile))) { - // 模板文件如果有更新则缓存需要更新 - return false; - } elseif (0 != $cacheTime && time() > filemtime($cacheFile) + $cacheTime) { + foreach($files as $time => $path) { + if (is_file($path) && filemtime($path) > $time) { + // 模板文件如果有更新则缓存需要更新 + return false; + } + } + if (0 != $cacheTime && time() > filemtime($cacheFile) + $cacheTime) { // 缓存是否在有效期 return false; } diff --git a/library/think/template/driver/Sae.php b/library/think/template/driver/Sae.php index 8e1c9300..610569a9 100644 --- a/library/think/template/driver/Sae.php +++ b/library/think/template/driver/Sae.php @@ -35,7 +35,12 @@ class Sae } } - // 写入编译缓存 + /** + * 写入编译缓存 + * @string $cacheFile 缓存的文件名 + * @string $content 缓存的内容 + * @return void|array + */ public function write($cacheFile, $content) { // 添加写入时间 @@ -48,23 +53,42 @@ class Sae } } - // 读取编译编译 - public function read($cacheFile, $vars) + /** + * 读取编译编译 + * @string $cacheFile 缓存的文件名 + * @array $vars 变量数组 + * @boolean $isReturn 是否返回内容 + * @return void|array + */ + public function read($cacheFile, $vars = [], $isReturn = false) { - if (!is_null($vars)) { + if (!empty($vars) && is_array($vars)) { extract($vars, EXTR_OVERWRITE); } - eval('?>' . $this->get($cacheFile, 'content')); + if ($isReturn) { + return $this->get($cacheFile, 'content'); + } else { + eval('?>' . $this->get($cacheFile, 'content')); + } } - // 检查编译缓存是否有效 + /** + * 检查编译缓存是否有效 + * @array $template 用到的模板更新时间列表 + * @string $cacheFile 缓存的文件名 + * @int $cacheTime 缓存时间 + * @return boolean + */ public function check($template, $cacheFile, $cacheTime) { + foreach($template as $time => $path) { + if (is_file($path) && filemtime($path) > $time) { + // 模板文件如果有更新则缓存需要更新 + return false; + } + } $mtime = $this->get($cacheFile, 'mtime'); - if (!$this->get($cacheFile, 'content') || (is_file($template) && filemtime($template) > $mtime)) { - // 模板文件如果有更新则缓存需要更新 - return false; - }if (0 != $cacheTime && time() > $mtime + $cacheTime) { + if (0 != $cacheTime && time() > $mtime + $cacheTime) { // 缓存是否在有效期 return false; } else { diff --git a/tests/thinkphp/library/think/extend2.html b/tests/thinkphp/library/think/extend2.html index b40e9c7a..ab08b984 100644 --- a/tests/thinkphp/library/think/extend2.html +++ b/tests/thinkphp/library/think/extend2.html @@ -1,4 +1,4 @@ -{layout name="layout" replace="[__REPLACE__]" /} +{layout name="layout2" replace="[__REPLACE__]" /}
{include file="include" name="info" value="$info.value" /} {block name="main"} diff --git a/tests/thinkphp/library/think/include2.html b/tests/thinkphp/library/think/include2.html index 6d4dd4be..24bdacb3 100644 --- a/tests/thinkphp/library/think/include2.html +++ b/tests/thinkphp/library/think/include2.html @@ -1 +1 @@ -include2 \ No newline at end of file +{$info.value}: \ No newline at end of file diff --git a/tests/thinkphp/library/think/layout.html b/tests/thinkphp/library/think/layout.html index a5b75729..be8d4a07 100644 --- a/tests/thinkphp/library/think/layout.html +++ b/tests/thinkphp/library/think/layout.html @@ -1,2 +1,2 @@ - \ No newline at end of file +
{__CONTENT__} +
\ No newline at end of file diff --git a/tests/thinkphp/library/think/layout2.html b/tests/thinkphp/library/think/layout2.html new file mode 100644 index 00000000..a5b75729 --- /dev/null +++ b/tests/thinkphp/library/think/layout2.html @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/tests/thinkphp/library/think/templateTest.php b/tests/thinkphp/library/think/templateTest.php index aa14b94f..b044a5b6 100644 --- a/tests/thinkphp/library/think/templateTest.php +++ b/tests/thinkphp/library/think/templateTest.php @@ -27,7 +27,7 @@ class templateTest extends \PHPUnit_Framework_TestCase $content = << EOF; @@ -37,7 +37,7 @@ EOF; $content = << EOF; @@ -47,7 +47,7 @@ EOF; $content = << EOF; @@ -57,7 +57,7 @@ EOF; $content = << EOF; @@ -67,7 +67,7 @@ EOF; $content = << EOF; @@ -77,7 +77,7 @@ EOF; $content = << EOF; @@ -87,7 +87,7 @@ EOF; $content = << EOF; @@ -97,7 +97,7 @@ EOF; $content = << EOF; @@ -107,7 +107,7 @@ EOF; $content = << EOF; @@ -117,7 +117,7 @@ EOF; $content = << EOF; @@ -127,7 +127,7 @@ EOF; $content = << EOF; @@ -137,7 +137,7 @@ EOF; $content = << EOF; @@ -147,7 +147,7 @@ EOF; $content = <<parse($content); $this->assertEquals($data, $content); @@ -155,7 +155,7 @@ EOF; $content = <<parse($content); $this->assertEquals($data, $content); @@ -240,54 +240,13 @@ EOF; $content = <<b)?'yes':'no'; ?> EOF; $template2->parse($content); $this->assertEquals($data, $content); } - public function testTag() - { - $config['view_path'] = dirname(__FILE__) . '/'; - $config['view_suffix'] = '.html'; - $template = new Template($config); - $files = ['extend' => 'extend', 'include' => 'include']; - $template->assign('files', $files); - - $content = << -
- -include2 - - - -include2 - {\$message} - - - mainbody - - - - {\$name} - - -
- -EOF; - $template->parse($content); - $this->assertEquals($data, $content); - } - public function testThinkVar() { $config['tpl_begin'] = '{'; @@ -321,7 +280,7 @@ EOF; {\$Think.SITE_NAME}
{\$Think.SITE.URL} EOF; - $data = <<


@@ -353,22 +312,54 @@ EOF; 'strip_space' => true, 'view_path' => dirname(__FILE__) . '/', ]; - $data = ['name' => 'value']; + $data = ['name' => 'value']; $template->display('display', $data, $config); $this->expectOutputString('value'); } public function testFetch() { - $template = new Template(); - $template->view_path = dirname(__FILE__) . '/'; - $data = ['name' => 'value']; - $content = << 'extend', 'include' => 'include']; + $template->assign('files', $files); + $template->assign('user', ['name' => 'name', 'account' => 100]); + $template->assign('message', 'message'); + $template->assign('info', ['value' => 'value']); - $template->fetch($content, $data); - $this->expectOutputString('value'); + $content = << +
+ +value: + + + +value: + message{\$message} + + + mainbody + + + + {\$name} + + php code
+ +EOF; + $template->fetch($content); + $this->expectOutputString($content2); } public function testVarAssign()