\App\Services\AdminConfigService

系统配置取值服务

职责:提供配置的读取、批量保存、分组查询。取值优先级:DB value > definition.default_value。 tabs 多卡片:分组内 type=tabs 定义的值 = tab 列表 JSON([{key,name}]), 同组 is_tabs=1 的定义按 tab_key 各存一条值,站点配置页按 tab 切换编辑。 按 group 缓存,修改后自动清除对应缓存。定义维护(CRUD)在 MaintainConfigService。

┌────────────────── 分区导航(按此顺序阅读)──────────────────┐ 分区 1 · 读取 get / getTab / groupTabs / group / all / siteInfo 分区 2 · 批量保存 save 分区 3 · 极简单写 set / setTab 分区 4 · 内部辅助 encryptSensitive / decryptSensitive / maskSensitive / multiselectOptions findDefinition / resolveValue / castValue / typedValue validate / decodeTabs / cleanupOrphanTabs └────────────────────────────────────────────────────────────┘

Summary

Methods
Properties
Constants
get()
getTab()
groupTabs()
group()
all()
siteInfo()
save()
set()
setTab()
No public properties found
SENSITIVE_KEYS
MASKED
ENCRYPT_PREFIX
No protected methods found
No protected properties found
N/A
encryptSensitive()
decryptSensitive()
maskSensitive()
multiselectOptions()
dictOptions()
findDefinition()
resolveValue()
castValue()
typedValue()
validate()
decodeTabs()
cleanupOrphanTabs()
No private properties found
N/A

Constants

SENSITIVE_KEYS

SENSITIVE_KEYS = ['mail.smtp_password', 'template.render_key', 'sms.access_secret', 'sms.access_key']

敏感配置键:管理面回显脱敏(******),保存提交占位值/空串 = 保持原值; 内部消费仍走 get()/getTab() 取原始值(如 MailService 读 SMTP 密码不受影响)。 落库应用层加密(enc: 前缀),迁移命令 config:encrypt-sensitive 与此清单同源。 新增敏感项在此追加。

MASKED

MASKED = '******'

敏感值展示掩码

ENCRYPT_PREFIX

ENCRYPT_PREFIX = 'enc:'

落库加密前缀(敏感值应用层加密;enc: 标记密文,与历史明文/空值区分)

Methods

get()

get(string  $key, mixed  $default = null) : mixed

获取单个配置值(带缓存;tabs 定义请用 getTab,此处只读全局值 tab_key='')。 返回类型按定义 type 转换(number→int/float、boolean→bool、其余→string), 与 set() 写入类型一致——读写同型。

Parameters

string $key
mixed $default

Returns

mixed —

getTab()

getTab(string  $key, string  $tabKey, mixed  $default = null) : mixed

获取指定 tab 的配置值(is_tabs=1 定义专用;非 tabs 定义/空 tabKey 返回 default)。 按定义 key 缓存整个 tab 映射 {tabKey: value}(MailService 多通道高频读)。

Parameters

string $key
string $tabKey
mixed $default

Returns

mixed —

groupTabs()

groupTabs(string  $groupCode) : array

分组内 tab 列表(type=tabs 定义的值,JSON [{key,name}]);无 tabs 定义返回 []。

Parameters

string $groupCode

Returns

array —

group()

group(string  $groupCode) : array

获取指定分组的所有配置(站点配置页数据源)。

含分组级 tabs 元数据:is_tabs(分组是否启用 tab 切换)/ tab_list_key(tabs 定义键)/ tabs([{key,name}]);items 不含 tabs 定义本身——is_tabs=1 项带 values(tabKey=>value), 其余项带 value(全局值,tab_key='')。

Parameters

string $groupCode

Returns

array —

all()

all() : array

获取所有分组及其配置。

Returns

array —

siteInfo()

siteInfo() : array<string,string>

站点公开信息聚合(公开接口 /api/site 数据源,数据驱动化)。

返回全部 is_public=1 启用定义的 key→value(值优先,回落 default_value)——跨分组聚合: SITE 分组站点信息 + 登录页三开关(SECURITY 分组)等显式公开的定义。 「加定义 + 勾公开 = 前端自动多字段」,零代码零发布;默认 0 = 公开接口不暴露(安全默认)。 依赖 definition/value 表事件自动失效——站点配置页保存、站点维护页改定义(含 is_public)后立即重建, 24h TTL 仅兜底。公开接口无认证可无限调用,命中即返回,不打库。

Returns

array

save()

save(array  $data) : void

批量保存配置值。

载荷契约(显式 full-replace 语义):

  • flat [key => value]:普通定义 + type=tabs 定义的「通道列表 JSON」本身 (tabs 定义以 tab_key='' 行存储,如 mail.tabs = [{"key":"c1","name":"..."}]);
  • tabs [tabKey => [key => value]]:仅 is_tabs=1 定义接受 per-tab 值;
  • 清理语义:只要出现 tabs 载荷,即以本次提交的 tabKey 集合为准, 删除该组未提交 tab 的全部 per-tab 值(前端恒全量提交 tabs 草稿, 删通道即删其全部值;API 调用方必须同样遵守全量提交,禁止部分提交)。

Parameters

array $data

set()

set(string  $key, mixed  $value) : void

按 key 设置单个配置值(极简写入口,业务代码一行调用)。

app(ConfigService::class)->set('auth.register_enabled', true); app(ConfigService::class)->set('captcha.ttl', 300);

自动完成:定义校验(类型/选项白名单/validation)、按定义 type 转换落库、 分组缓存失效(list/info:key/def/tab 全清)。类型一致:get() 读回同型值。 敏感项(mail.smtp_password):传入 ****** 或空串保持原值。

Parameters

string $key
mixed $value

Throws

\InvalidArgumentException

定义不存在 / 校验失败 / 敏感项占位

setTab()

setTab(string  $key, string  $tabKey, mixed  $value) : void

按 key + tabKey 设置 tabs 定义的单个通道值。

app(ConfigService::class)->setTab('mail.smtp_host', 'c1', 'smtp.example.com');

Parameters

string $key
string $tabKey
mixed $value

encryptSensitive()

encryptSensitive(string  $key, mixed  $value) : mixed

敏感值写侧加密:仅敏感键调用;空串不加密(空值语义=未配置,占位保持路径已在前置拦截)。 缓存层存密文——Redis 泄密面同步收敛。

Parameters

string $key
mixed $value

Returns

mixed —

decryptSensitive()

decryptSensitive(string  $key, mixed  $value) : mixed

敏感值读侧解密:非敏感键/非密文原样返回(兼容存量明文与占位); 解密失败(典型为 APP_KEY 轮换未重加密)回落原值并告警,不阻断读取——密文作为 错误凭据使用时下游认证自然失败,与「配置错误」语义一致。

Parameters

string $key
mixed $value

Returns

mixed —

maskSensitive()

maskSensitive(?string  $value) : ?string

敏感值脱敏:有值 → ******(占位,保存时保持原值);空/无值 → 原样。

Parameters

?string $value

Returns

?string —

multiselectOptions()

multiselectOptions(string  $key) : ?array

multiselect 配置项动态选项注册表(强边界): 选项由系统注册表产出(非自由文本),group() 下发与 validate() 白名单同源。 新增多选项在此登记(key => [{value,label}]);未登记项回落定义 options 静态值。

Parameters

string $key

Returns

?array —

dictOptions()

dictOptions(string  $dictType) : ?array

source=dict 配置项选项:由字典类型(dict_type)供给启用项([{value,label}], 与 multiselect 同形态);字典数据页直接维护,配置界面自动跟随。

Parameters

string $dictType

Returns

?array —

findDefinition()

findDefinition(string  $key) : ?\App\Models\SysConfigDefinition

按 key 取启用配置定义(缓存;setRawAttributes 绕过 fillable,避免 new Model 丢 id)

Parameters

string $key

Returns

?\App\Models\SysConfigDefinition —

resolveValue()

resolveValue(\App\Models\SysConfigDefinition  $def) : mixed

取定义的全局值(tab_key=''):值记录优先,回落定义 default_value

Parameters

\App\Models\SysConfigDefinition $def

Returns

mixed —

castValue()

castValue(string  $type, mixed  $value) : mixed

写侧类型转换:number→int/float、boolean→'1'/'0'、multiselect→去重逗号串、其余→string

Parameters

string $type
mixed $value

Returns

mixed —

typedValue()

typedValue(string  $type, mixed  $value) : mixed

读取侧类型转换:与 castValue(写侧)对称,保证读写类型一致。 number→int/float、boolean→bool、其余→string。

Parameters

string $type
mixed $value

Returns

mixed —

validate()

validate(\App\Models\SysConfigDefinition  $def, mixed  $value) : void

保存侧校验:boolean 归一、tabs JSON、template 白名单、multiselect 白名单、select options、validation 规则

Parameters

\App\Models\SysConfigDefinition $def
mixed $value

decodeTabs()

decodeTabs(string  $raw) : array

解析 tab 列表 JSON(过滤非法项,key 兜底为 name)。

Parameters

string $raw

Returns

array —

cleanupOrphanTabs()

cleanupOrphanTabs(string  $groupCode, array  $keepTabKeys) : void

删除分组内 is_tabs=1 定义中不属于 keepTabKeys 的 per-tab 值。

Parameters

string $groupCode
array $keepTabKeys