模板文件位置为:\vendor\topthink\think-template\src\Template.php。
由于模板继承(extend)只能解析一次block正好今天遇到这个问题就顺手研究了一下,修复后可使用如下代码
{extend name="base/frame" /}
{block name="head"}
{block name="base_css"}{/block}
{block name="css"}{/block}
{block name="base_js"}{/block}
{block name="js"}{/block}
{/block}
{block name="body"}
{block name="base_main"}
{include file="base/page-head" /}
{block name="main"}{/block}
{include file="base/footer" /}
{/block}
{block name="base_bottom"}{/block}
{block name="bottom"}{/block}
{:hook('bottom')}
{/block}修改代码如下:新增2个方法,改进模板的parseExtend方法 /**
* 修复parent值被替换
* @param $blocks
* @param $_blocks
* @return array
*/
private function mergeBlock(&$blocks, $_blocks)
{
if (is_array($blocks)) {
foreach ($_blocks as $_block => $_values) {
if (array_key_exists($_block, $blocks)) {
$blocks[$_block]['content'] = $_values['content'];
} else {
$blocks[$_block] = $_values;
}
}
} else {
$blocks = [];
}
return $blocks;
}
/**
* 替换嵌套的block
* @param $blocks
* @param string $pKey
* @param string $key
* @return mixed
*/
private function updateBlocks(&$blocks, $pKey = '', $key = '')
{
$begin = $this->config['tpl_begin'];
$end = $this->config['tpl_end'];
if (empty($pKey) && empty($key)) {
foreach ($blocks as $k => $v) {
if (!empty($blocks[$k]['parent'])) {
$this->updateBlocks($blocks, $blocks[$k]['parent'], $k);
}
}
} else {
if (isset($blocks[$pKey]) && isset($blocks[$key])) {
$pBlock = &$blocks[$pKey];
$block = &$blocks[$key];
$search = "/{$begin}block name=\"{$key}\"{$end}[\s\S]*?{$begin}\/block{$end}/";
$replace = $block['content'];
$pBlock['content'] = preg_replace($search, $replace, $pBlock['content']);
if (!empty($pBlock['parent'])) {
$this->updateBlocks($blocks, $pBlock['parent'], $key);
}
}
}
return $blocks;
}
/**
* 解析模板中的extend标签
* @access private
* @param string $content 要解析的模板内容
* @return void
*/
private function parseExtend(string &$content): void
{
$regex = $this->getRegex('extend');
$array = $blocks = $baseBlocks = [];
$extend = '';
$func = function ($template) use (&$func, &$regex, &$array, &$extend, &$blocks, &$baseBlocks) {
if (preg_match($regex, $template, $matches)) {
if (!isset($array[$matches['name']])) {
$array[$matches['name']] = 1;
// 读取继承模板
$extend = $this->parseTemplateName($matches['name']);
// 递归检查继承
$func($extend);
// 取得block标签内容
$blocks = $this->mergeBlock($blocks, $this->parseBlock($template));//修复点1
return;
}
} else {
// 取得顶层模板block标签内容
$baseBlocks = $this->parseBlock($template, true);
if (empty($extend)) {
// 无extend标签但有block标签的情况
$extend = $template;
}
}
};
$func($content);
$blocks = $this->updateBlocks($blocks);//修复点2
if (!empty($extend)) {
if ($baseBlocks) {
$children = [];
foreach ($baseBlocks as $name => $val) {
$replace = $val['content'];
if (isset($children[$name]) && is_array($children[$name])) {
// 如果包含有子block标签
foreach ($children[$name] as $key) {
$replace = str_replace($baseBlocks[$key]['begin'] . $baseBlocks[$key]['content'] . $baseBlocks[$key]['end'], $blocks[$key]['content'], $replace);
}
}
if (isset($blocks[$name])) {
// 带有{__block__}表示与所继承模板的相应标签合并,而不是覆盖
$replace = str_replace(['{__BLOCK__}', '{__block__}'], $replace, $blocks[$name]['content']);
if (!empty($val['parent'])) {
// 如果不是最顶层的block标签
$parent = $val['parent'];
if (isset($blocks[$parent])) {
$blocks[$parent]['content'] = str_replace($blocks[$name]['begin'] . $blocks[$name]['content'] . $blocks[$name]['end'], $replace, $blocks[$parent]['content']);
}
$blocks[$name]['content'] = $replace;
$children[$parent][] = $name;
continue;
}
} elseif (!empty($val['parent'])) {
// 如果子标签没有被继承则用原值
$children[$val['parent']][] = $name;
$blocks[$name] = $val;
}
if (!$val['parent']) {
// 替换模板中的顶级block标签
$extend = str_replace($val['begin'] . $val['content'] . $val['end'], $replace, $extend);
}
}
}
$content = $extend;
unset($blocks, $baseBlocks);
}
}上传不了附件,可以自行按照代码修改测试。 最佳答案