// +---------------------------------------------------------------------- namespace ywxapp\library; /** * 模板(皮肤)覆盖解析器 —— Discuz 式局部覆盖核心。 * * 解析顺序(优先级高 → 低): * 1. templates/<激活模板>/view/<插件>/<区域>/<页面>.html ← 用户购买的自定义皮肤 * 2. addon/<插件>/view/<区域>/<页面>.html ← 插件默认视图(回退) * * 激活映射见 config/template.php 的 active_map: * ['blog' => 'myblog', '*' => 'default'];值 'default'/空 = 用插件自带视图。 * * 决策(2026-07-28):整站皮肤 + 局部覆盖 + 每插件独立选。 */ class TemplateResolver { /** * 解析模板覆盖页的绝对路径;未命中返回 null(交由默认视图回退)。 * * @param string $addon 插件名,如 blog * @param string $area 区域:frontend / backend / member * @param string $template 模板名,如 article/detail (与控制器 fetch 入参一致) * @return string|null */ public static function resolve(string $addon, string $area, string $template): ?string { // 空模板或跨应用语法(含 @)不处理,直接回退 if ($template === '' || strpos($template, '@') !== false) { return null; } $map = config('template.active_map', []); if (!is_array($map)) { return null; } $tpl = $map[$addon] ?? ($map['*'] ?? 'default'); if (empty($tpl) || $tpl === 'default') { return null; } $rel = 'templates' . DIRECTORY_SEPARATOR . $tpl . DIRECTORY_SEPARATOR . 'view' . DIRECTORY_SEPARATOR . $addon . DIRECTORY_SEPARATOR . $area . DIRECTORY_SEPARATOR . $template . '.html'; $file = root_path() . $rel; return is_file($file) ? $file : null; } }