Files

147 lines
6.1 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// +----------------------------------------------------------------------
// | YwxApp [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: ywxapp<admin@ywxapp.cn>
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace ywxapp\controller;
use ywxapp\library\SkinVariables;
use ywxapp\model\MemberUser;
/**
* 会员中心控制器基类(MemberBase)
*
* 同时服务于两类场景:
* 1) 会员中心本体(app/member 应用):view_path = app/member/view/layout = common/layout
* 2) 插件用户中心(addon/<插件>/controller/member/):view_path = addon/<插件>/view/member/layout = member/layout
*
* 鉴权:容器 auth 在 AppService 中默认已绑定 \ywxapp\library\Auth(会员鉴权),
* 故会员登录态由 BaseController::verifyAuth 自动校验(设置 $noNeedLogin 可放行)。
*
* 用法:
* // 会员中心本体控制器
* namespace app\member\controller;
* use ywxapp\controller\MemberBase;
* class Index extends MemberBase { ... }
*
* // 插件用户中心控制器
* namespace addon\blog\controller\member;
* use ywxapp\controller\MemberBase;
* class Index extends MemberBase { ... }
*/
class MemberBase extends BaseController
{
/**
* 视图类实例
* @var \think\View
*/
protected $view;
/**
* 控制器初始化
*/
public function _initialize()
{
MemberUser::ensureSchema(); // 用户中心核心表自愈(缺表/缺列兜底)
$this->view = $this->app->view;
$appName = $this->app->http->getName();
// 全局 layout 模式:会员中心本体套 view/layout,插件用户中心套各自的 view/member/layout。
// 不需要套 layout 的页面(如会员中心 iframe 主框架页)可在控制器内调用 $this->view->layout(false) 关闭。
$layout = 'common/layout';
if ($appName === 'member') {
// 会员中心本体:视图根目录为 app/member/view/layout 为 view/layout.html
$viewPath = $this->app->getAppPath() . 'view' . DIRECTORY_SEPARATOR;
} else {
// 插件用户中心:视图根目录为 addon/<插件>/view/member/
$addon = $this->currentAddon();
$viewPath = $addon
? root_path() . 'addon' . DIRECTORY_SEPARATOR . $addon . DIRECTORY_SEPARATOR
. 'view' . DIRECTORY_SEPARATOR . 'member' . DIRECTORY_SEPARATOR
: $this->app->getAppPath() . 'view' . DIRECTORY_SEPARATOR . 'member' . DIRECTORY_SEPARATOR;
// 插件内使用插件自己的 view/member/layout.htmlview_path 已含 member/
$layout = 'common/layout';
}
$this->view->config([
'view_suffix' => 'html',
'view_path' => $viewPath,
'layout_on' => true,
'layout_name' => $layout,
]);
// 登录与权限校验:统一走 Base 的 verifyAuth + $noNeedLogin 机制
// (未登录且非免登录 action 时整页 302 跳登录页,AJAX 返回 401,与后台一致)。
// 注意:verifyAuth 内部会 tokenParse() 还原登录态,无需在中间件重复处理。
$this->auth->verifyAuth($this->noNeedLogin, $this->noNeedVerify);
if ($this->auth && $this->auth->isLogin) {
$this->view->assign('member', $this->auth->info);
}
$siteConf = \ywxapp\model\Configure::cache(true)->column('value', 'name');
$this->view->assign('siteConf', $siteConf);
$links = \ywxapp\model\Links::cache(true)->where('status', 1)->order('sort desc')->select();
$this->view->assign('links', $links);
// 注入站点信息(route_base / site.module / site.controller 等),供前端 route.js 使用
$this->assignSite();
$this->initialize();
}
/**
* 子类初始化钩子
*/
protected function initialize() {}
/**
* 获取当前登录会员信息(未登录直接报错)
* @return \ywxapp\model\Member
*/
protected function user()
{
if ($this->auth && $this->auth->isLogin) {
return $this->auth->info;
}
$this->result->error('请先登录会员中心');
}
/**
* 当前插件名(addon\<name>\...
* 由 appPathaddon/<插件>/)剥 rootPath 取首段,无需正则。
*/
protected function currentAddon(): string
{
$rel = trim(substr($this->app->getAppPath(), strlen($this->app->getRootPath())), DIRECTORY_SEPARATOR);
$seg = explode(DIRECTORY_SEPARATOR, $rel);
return $seg[0] === 'addon' && isset($seg[1]) ? $seg[1] : '';
}
/**
* 渲染模板:优先使用已激活模板的覆盖页(Discuz 式局部覆盖),未命中回退插件默认视图。
*/
protected function fetch($template = '', $vars = [], $replace = [], $config = [])
{
$addon = $this->currentAddon();
$restore = null;
if ($addon && $overlay = \ywxapp\library\SkinOverlay::resolve($addon, 'member')) {
// 把视图根目录切到「插件视图 + 皮肤覆盖」合并层,使 extend 的 layout 也走皮肤
$restore = \think\facade\View::getConfig('view_path');
\think\facade\View::config(['view_path' => $overlay]);
}
$result = \think\facade\View::fetch($template, $vars, $replace, $config);
if ($restore !== null) {
\think\facade\View::config(['view_path' => $restore]);
}
// 注入皮肤变量 CSS(Discuz 式配色层,无需改 HTML
$style = SkinVariables::styleTag($addon, 'member');
if ($style !== '' && ($pos = stripos($result, '</head>')) !== false) {
$result = substr($result, 0, $pos) . $style . "\n" . substr($result, $pos);
} elseif ($style !== '') {
$result = $style . $result;
}
return $result;
}
}