模板变量

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 使用自定义变量,避免覆盖内置变量。

最近更新:
Contributors: 邹景立, Anyon