凌晨两点的报错——自定义模型建好了,前台却死活不显示
老张盯着屏幕,烟灰缸里堆满了烟头,他刚用帝国CMS后台的“模型管理”创建了一个“产品档案”自定义模型,字段加了十几个,数据也录入了,但前台栏目页就是空白,他检查了栏目绑定、模板选择,都没问题。
帝国CMS二次开发实录,从数据表引擎转换到模板调用的血泪排坑指南
“这是典型的‘模型创建后未执行数据表引擎转换’。”我敲了敲键盘,打开数据库管理工具,“你看,phome_enewsproduct 这个新表虽然建了,但它的存储引擎是 MyISAM,而帝国CMS核心内容表 phome_ecms_news 是 InnoDB,前台查询时,模型表没有与主表做JOIN的索引,或者表引擎导致事务不一致,就会静默失败。”
排障步骤:
- 确认模型表是否存在字段缺失:执行
DESCRIBE phome_enewsproduct;对比默认模型表结构。 - 手动转换引擎:
ALTER TABLE phome_enewsproduct ENGINE=InnoDB; ALTER TABLE phome_enewsproduct_data ENGINE=InnoDB; -- 如果存在副表
- 检查模型关联字段:帝国CMS的模型表必须有
id(等于主表id)和classid(栏目id),如果漏了,需要补上:ALTER TABLE phome_enewsproduct ADD COLUMN id int(11) NOT NULL DEFAULT '0'; ALTER TABLE phome_enewsproduct ADD COLUMN classid int(11) NOT NULL DEFAULT '0';
老张一拍大腿:“原来我建模型时选了‘继承主表’,结果它没自动建副表,我手动加字段时把 id 写成了 pid!”
灵动标签SQL调用——列表页想调出副表字段
小李的需求:在列表模板中,要显示“产品价格”和“库存”,这两个字段存放在自定义模型的副表 phome_enewsproduct_data 中,而列表页默认只能调用主表字段。
“用灵动标签[e:loop]直接写SQL连接。”我在编辑器里输入:
[e:loop={ "SELECT main.*, data.* FROM phome_ecms_news main
LEFT JOIN phome_enewsproduct_data data ON main.id = data.id
WHERE main.classid = 1 AND main.checked = 1
ORDER BY main.newstime DESC LIMIT 10", 10, 24, 0}]
<li>
<a href="<?=$bqsr['titleurl']?>"><?=$bqr['title']?></a>
<span>价格:<?=$bqr['price']?>元 | 库存:<?=$bqr['stock']?>件</span>
</li>
[/e:loop]
关键点:
main.*是主表字段,data.*是自定义模型副表字段。- 必须用
LEFT JOIN保持主表记录完整。 $bqr是SQL查询结果集,$bqsr是系统生成参数(如titleurl)。
“如果你只想要某一条的详细数据,在内容页模板里直接调副表字段,用这个代码:”
<?php
$data_r = $empire->fetch1("SELECT * FROM phome_enewsproduct_data WHERE id='$navinfor[id]'");
echo "价格:".$data_r['price'];
?>
模板变量调用——明明写在标签里却不解析
王姐是模板设计师,她把灵动标签里的 <?=$bqr['title']?> 写成了 <%=bqr.title%>,结果页面直接输出了源代码。
“帝国CMS的模板解析不同于别的CMS,它是在PHP中嵌套HTML,变量必须是 <?=...?> 形式,不能用 号。”我给她看了一个典型的列表模板完整写法:
<ul>
[e:loop={ "SELECT id, title, titlepic, newstime FROM phome_ecms_news WHERE classid=5 ORDER BY id DESC LIMIT 5", 5, 24, 0}]
<li>
<img src="<?=$bqr['titlepic']?>" alt="">
<a href="<?=$bqsr['titleurl']?>"><?=$bqr['title']?></a>
<span><?=date('Y-m-d', $bqr['newstime'])?></span>
</li>
[/e:loop]
</ul>
万能标签([ecms])与智能标签([e:loop])的区别:
- 智能标签:适合常规列表、分页,内部自动处理分页参数和链接,但你无法随心所欲写复杂SQL。
- 万能标签:适合需要多表查询、条件筛选、自定义排序的场景,它不直接支持分页,需要配合JS或PHP手写分页逻辑。
例如万能标签调用同一模型下的随机产品:
[ecms]{
"sql":"SELECT * FROM phome_ecms_news WHERE classid=3 ORDER BY RAND() LIMIT 3",
"cache":0,
"return":true
}[/ecms]
全站搜索配置——为什么搜不到自定义字段内容
小赵在后台启用了全站搜索,但搜“耐磨”这个词,明明产品描述里有,却返回空,他查了 phome_ecms_search 表,发现索引只更新了标题。
解决:
- 后台>数据更新>更新搜索索引,但必须勾选“自定义字段索引”。
- 如果还是不行,手动执行SQL更新搜索表:
-- 清空旧索引
DELETE FROM phome_ecms_search;
-- 重新生成索引,product_desc”是自定义字段名
INSERT INTO phome_ecms_search (searchid, id, classid, title, infotags, smalltext, addtime)
SELECT CONCAT('p', id) as searchid, id, classid, title, infotags, CONCAT(title, ' ', product_desc) as smalltext, newstime
FROM phome_ecms_news;
注意:全站搜索的 smalltext 字段会被分词,所以要把自定义字段拼进去,搜索页面调用的变量是 $r[title] 和 $r[smalltext]。
附表字段调用技巧——内容页如何高效读副表 页模板中,为了显示“项目地址”字段(存在副表),他写了个循环:
<?php
$db->query("SELECT * FROM phome_enewsproduct_data WHERE id='$navinfor[id]'");
$row = $db->fetch_array();
?>
“这样每次页面刷新都会多一次SQL查询,如果模型有10个副表字段,建议用 $navinfor 预加载。”我告诉他帝国CMS的 [!--字段名--] 可以直接输出主表和副表字段,前提是在后台“系统设置-数据表”中,把副表字段绑定到主模型。
如果必须手动查询,最好用全局缓存:
<?php
// 判断是否已缓存
if(!defined('PRODUCT_DATA_'.$navinfor[id])){
$data_row = $empire->fetch1("SELECT * FROM phome_enewsproduct_data WHERE id='$navinfor[id]'");
define('PRODUCT_DATA_'.$navinfor[id], 1);
$GLOBALS['product_data_cache'] = $data_row;
}
$data_r = $GLOBALS['product_data_cache'];
echo "地址:".$data_r['address'];
?>
凌晨四点,老张的网站终于恢复了。
他把所有列表页的SQL都改成了 LEFT JOIN 形式,并给副表字段加了索引:
ALTER TABLE phome_enewsproduct_data ADD INDEX idx_product_id (id);
帝国CMS性能瓶颈往往不在PHP层,而在数据表引擎和SQL写法,如果表引擎不统一,事务处理会出现幻读;如果不加索引,联合查询会直接把数据库拖垮。一切优化从引擎转换开始,一切BUG先从查询日志排查。



发表评论