模板变量
ThinkAdmin 在多应用调度成功后,会把 SystemService::uris() 生成的路径写入 ThinkPHP 视图配置 tpl_replace_string。后台模板中常见的 __ROOT__、__APP__、__PLUG__、__FULL__ 都来自这里。
相关实现:
think\admin\service\SystemService::uri()think\admin\service\SystemService::uris()think\admin\support\middleware\MultAccess::setMultiApp()
实现规则
SystemService::uri() 当前实现如下:
public static function uri(string $path = '', ?string $type = '__ROOT__', $default = '')
{
$plugin = Library::$sapp->http->getName();
if (strlen($path)) {
$path = '/' . ltrim($path, '/');
}
$prefix = rtrim(dirname(Library::$sapp->request->basefile()), '\/');
$data = [
'__APP__' => rtrim(url('@')->build(), '\/') . $path,
'__ROOT__' => $prefix . $path,
'__PLUG__' => "{$prefix}/static/extra/{$plugin}{$path}",
'__FULL__' => Library::$sapp->request->domain() . $prefix . $path,
];
return is_null($type) ? $data : ($data[$type] ?? $default);
}MultAccess 解析当前应用后会合并路径变量:
$uris = array_merge($this->app->config->get('view.tpl_replace_string', []), SystemService::uris());
$this->app->config->set([
'view_path' => $this->appPath . 'view' . DIRECTORY_SEPARATOR,
'tpl_replace_string' => $uris,
], 'view');注意:后面的 SystemService::uris() 会覆盖同名变量。如果项目也配置了 __ROOT__ 等同名键,以当前实现为准。
变量说明
| 变量 | 来源 | 用途 |
|---|---|---|
__APP__ | url('@')->build() | 当前入口路由根地址,适合动态请求 |
__ROOT__ | dirname(request()->baseFile()) | 当前入口文件所在目录,适合公共静态资源 |
__PLUG__ | __ROOT__/static/extra/{当前应用} | 当前应用或插件的专属静态资源 |
__FULL__ | request()->domain() + __ROOT__ | 带协议和域名的当前站点根地址 |
这些值会受入口文件、URL 重写、子目录部署、域名和当前应用影响,不应把它们固定理解为 /index.php 或 /。
常用写法
公共静态资源
公共资源优先使用 __ROOT__:
<link rel="stylesheet" href="__ROOT__/static/plugs/layui/css/layui.css">
<script src="__ROOT__/static/admin.js"></script>
<img src="__ROOT__/static/theme/img/headimg.png" alt="">动态请求
需要走路由、中间件或权限校验的请求使用 __APP__:
<script src="__APP__/admin/api.plugs/script"></script>
<script>
$.get('__APP__/admin/api.system/config', function (ret) {
console.log(ret);
});
</script>__APP__ 的真实输出由 url('@') 决定。开启 URL 重写时可能接近站点根路径;未开启时可能包含入口文件。
应用专属资源
当前应用或插件独有的资源可以放在:
public/static/extra/{应用名}/模板中使用:
<link rel="stylesheet" href="__PLUG__/css/custom.css">
<script src="__PLUG__/js/page.js"></script>在 admin 应用中,__PLUG__/js/page.js 会指向 static/extra/admin/js/page.js;在插件应用中会使用当前插件编码。
完整 URL
外部回调、分享链接、邮件图片等需要完整地址时使用 __FULL__:
<input type="hidden" name="notify_url" value="__FULL__/plugin-payment/api.notify/wechat">
<img src="__FULL__/static/theme/img/headimg.png" alt="">__FULL__ 使用当前请求域名,不会自动读取 base.site_host 或 CDN 配置。
PHP 中读取
在 PHP 代码中读取同一组路径,使用 SystemService::uri():
use think\admin\service\SystemService;
$root = SystemService::uri('', '__ROOT__');
$app = SystemService::uri('', '__APP__');
$plug = SystemService::uri('', '__PLUG__');
$full = SystemService::uri('', '__FULL__');
$image = SystemService::uri('/static/theme/img/headimg.png', '__FULL__');读取全部变量:
$uris = SystemService::uris();
// [
// '__APP__' => '...',
// '__ROOT__' => '...',
// '__PLUG__' => '...',
// '__FULL__' => '...',
// ]sysuri() 和 admuri() 是路由 URL 生成函数,不是模板变量读取函数。
路径示例
以下示例只说明相对关系,真实输出以当前请求为准。
普通根目录部署:
__ROOT__ =>
__APP__ => 当前入口路由根地址
__PLUG__ => /static/extra/admin
__FULL__ => https://example.com部署在子目录 /project:
__ROOT__ => /project
__PLUG__ => /project/static/extra/admin
__FULL__ => https://example.com/project当前应用为 plugin-wemall:
__PLUG__ => /static/extra/plugin-wemall常见误区
把 __APP__ 当成固定 /index.php
不要在文档或业务中假设 __APP__ 一定输出 /index.php。它来自 ThinkPHP 的 url('@'),会受入口文件和 URL 重写影响。
在静态资源中使用 __APP__
静态 CSS、JS、图片通常不需要经过 PHP:
<!-- 不推荐 -->
<script src="__APP__/static/js/app.js"></script>
<!-- 推荐 -->
<script src="__ROOT__/static/js/app.js"></script>跨应用误用 __PLUG__
__PLUG__ 总是当前应用或插件的专属目录。跨应用共享资源应放到公共静态目录,并用 __ROOT__ 引用。
<!-- 当前是 admin 应用时,会指向 static/extra/admin/js/index.js -->
<script src="__PLUG__/js/index.js"></script>期望自动使用 CDN
当前四个内置变量不会读取 CDN 配置。如需 CDN 地址,可以扩展 view.tpl_replace_string 使用自定义变量,避免覆盖内置变量。
