559 行
22 KiB
PHP
559 行
22 KiB
PHP
<?php
|
||
|
||
namespace app\common\library;
|
||
|
||
use think\Db;
|
||
|
||
/**
|
||
* 订单多维抽佣规则匹配与订单级快照核算服务
|
||
*
|
||
* 核心原则:
|
||
* 1. 按订单维度灵活匹配:支持按【订单模式(一口价/报价/自主定价/区间) + 发单客群(个人/商家) + 服务类目 + 加急属性 + 订单金额阶梯】匹配 fa_commission_rule,支持按比例(%)、按单固定额(¥)、混合计佣及单笔保底/封顶。
|
||
* 2. 创单完整快照隔离:订单创建时同时写入 fa_order.commission_rate 与 fa_order.commission_snapshot(JSON 快照,报价单同步固化创单时刻的金额阶梯候选快照 candidate_tiers)。
|
||
* 3. 历史订单零干扰:选报价定档、施工增项结算、核销分账全部 100% 读取订单自身锁定的快照计算,后续后台增删改任何抽佣规则绝不影响历史已创订单。
|
||
*/
|
||
class CommissionService
|
||
{
|
||
const DEFAULT_RATE = 10.00;
|
||
|
||
/** @var array|null 请求内启用规则静态缓存 */
|
||
protected static $activeRulesCache = null;
|
||
|
||
/**
|
||
* 清空请求内规则缓存
|
||
*/
|
||
public static function clearCache(): void
|
||
{
|
||
self::$activeRulesCache = null;
|
||
}
|
||
|
||
/**
|
||
* 规范化百分比数值至 [0.00, 100.00]
|
||
*
|
||
* @param mixed $rate
|
||
* @return float
|
||
*/
|
||
public static function normalizeRate($rate): float
|
||
{
|
||
$val = round((float)$rate, 2);
|
||
if ($val < 0.00) {
|
||
return 0.00;
|
||
}
|
||
if ($val > 100.00) {
|
||
return 100.00;
|
||
}
|
||
return $val;
|
||
}
|
||
|
||
/**
|
||
* 强校验百分比输入(0 ~ 100)
|
||
*
|
||
* @param mixed $raw
|
||
* @return float
|
||
* @throws \InvalidArgumentException
|
||
*/
|
||
public static function validateRateInput($raw): float
|
||
{
|
||
$str = trim((string)$raw);
|
||
if ($str === '' || !is_numeric($str)) {
|
||
throw new \InvalidArgumentException('请填写有效的抽佣比例数字(0 ~ 100)');
|
||
}
|
||
$val = (float)$str;
|
||
if ($val < 0 || $val > 100) {
|
||
throw new \InvalidArgumentException('抽佣比例必须在 0% ~ 100% 之间');
|
||
}
|
||
return round($val, 2);
|
||
}
|
||
|
||
/**
|
||
* 读取全局默认兜底抽佣比例(%)
|
||
*/
|
||
public static function getGlobalRate(): float
|
||
{
|
||
$defaults = FinanceConfigService::getCommissionDefaults();
|
||
return self::normalizeRate($defaults['commission_rate'] ?? self::DEFAULT_RATE);
|
||
}
|
||
|
||
/**
|
||
* 计算单条规则的条件精确度得分(相同权重 weigh 时,条件越具体越优先命中)
|
||
*/
|
||
protected static function calcSpecificity(array $rule): int
|
||
{
|
||
$score = 0;
|
||
if ((int)($rule['cat_id'] ?? 0) > 0) {
|
||
$score += 16;
|
||
}
|
||
if (($rule['customer_type'] ?? 'all') !== 'all') {
|
||
$score += 8;
|
||
}
|
||
if (($rule['order_mode'] ?? 'all') !== 'all') {
|
||
$score += 4;
|
||
}
|
||
if (($rule['urgent_mode'] ?? 'all') !== 'all') {
|
||
$score += 2;
|
||
}
|
||
if ((float)($rule['min_amount'] ?? 0) > 0 || (float)($rule['max_amount'] ?? 0) > 0) {
|
||
$score += 1;
|
||
}
|
||
return $score;
|
||
}
|
||
|
||
/**
|
||
* 获取当前全部启用中的订单抽佣规则(按 weigh DESC -> 精确度 DESC -> id DESC 排序)
|
||
*/
|
||
public static function getActiveRules(bool $forceRefresh = false): array
|
||
{
|
||
if (self::$activeRulesCache === null || $forceRefresh) {
|
||
$rows = [];
|
||
try {
|
||
$rows = Db::name('commission_rule')
|
||
->where('status', 'normal')
|
||
->order('weigh desc, id desc')
|
||
->select();
|
||
if (!is_array($rows)) {
|
||
$rows = [];
|
||
}
|
||
} catch (\Throwable $e) {
|
||
$rows = [];
|
||
}
|
||
|
||
foreach ($rows as &$r) {
|
||
$r['id'] = (int)$r['id'];
|
||
$r['cat_id'] = (int)($r['cat_id'] ?? 0);
|
||
$r['weigh'] = (int)($r['weigh'] ?? 0);
|
||
$r['min_amount'] = round(max(0.00, (float)($r['min_amount'] ?? 0)), 2);
|
||
$r['max_amount'] = round(max(0.00, (float)($r['max_amount'] ?? 0)), 2);
|
||
$r['commission_rate'] = self::normalizeRate($r['commission_rate'] ?? 0);
|
||
$r['fixed_fee'] = round(max(0.00, (float)($r['fixed_fee'] ?? 0)), 2);
|
||
$r['min_commission'] = round(max(0.00, (float)($r['min_commission'] ?? 0)), 2);
|
||
$r['max_commission'] = round(max(0.00, (float)($r['max_commission'] ?? 0)), 2);
|
||
$r['_specificity'] = self::calcSpecificity($r);
|
||
}
|
||
unset($r);
|
||
|
||
usort($rows, function (array $a, array $b) {
|
||
if ($a['weigh'] !== $b['weigh']) {
|
||
return $b['weigh'] <=> $a['weigh'];
|
||
}
|
||
if ($a['_specificity'] !== $b['_specificity']) {
|
||
return $b['_specificity'] <=> $a['_specificity'];
|
||
}
|
||
return $b['id'] <=> $a['id'];
|
||
});
|
||
|
||
self::$activeRulesCache = $rows;
|
||
}
|
||
return self::$activeRulesCache;
|
||
}
|
||
|
||
/**
|
||
* 判断订单静态维度(不含金额区间)是否匹配规则
|
||
*/
|
||
protected static function matchStaticDimensions(array $rule, string $priceType, string $customerType, int $catId, int $urgent): bool
|
||
{
|
||
$rMode = (string)($rule['order_mode'] ?? 'all');
|
||
if ($rMode !== 'all' && $rMode !== $priceType) {
|
||
return false;
|
||
}
|
||
|
||
$rCust = (string)($rule['customer_type'] ?? 'all');
|
||
if ($rCust !== 'all' && $rCust !== $customerType) {
|
||
return false;
|
||
}
|
||
|
||
$rCat = (int)($rule['cat_id'] ?? 0);
|
||
if ($rCat > 0 && $rCat !== $catId) {
|
||
return false;
|
||
}
|
||
|
||
$rUrgent = (string)($rule['urgent_mode'] ?? 'all');
|
||
if ($rUrgent === 'urgent' && $urgent !== 1) {
|
||
return false;
|
||
}
|
||
if ($rUrgent === 'normal' && $urgent !== 0) {
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 判断订单金额是否命中规则的金额区间
|
||
*/
|
||
protected static function matchAmountRange(array $rule, float $amount): bool
|
||
{
|
||
$minAmt = (float)($rule['min_amount'] ?? 0);
|
||
$maxAmt = (float)($rule['max_amount'] ?? 0);
|
||
$amt = round(max(0.00, $amount), 2);
|
||
|
||
if ($amt < $minAmt) {
|
||
return false;
|
||
}
|
||
if ($maxAmt > 0 && $amt > $maxAmt) {
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 提取规则核心计佣描述结构(用于写入订单快照)
|
||
*/
|
||
protected static function extractRuleItem(array $rule): array
|
||
{
|
||
$calcMode = in_array($rule['calc_mode'] ?? 'percent', ['percent', 'fixed', 'mixed'], true)
|
||
? $rule['calc_mode']
|
||
: 'percent';
|
||
|
||
return [
|
||
'rule_id' => (int)($rule['id'] ?? 0),
|
||
'rule_name' => (string)($rule['name'] ?? '全局默认抽佣规则'),
|
||
'min_amount' => round((float)($rule['min_amount'] ?? 0), 2),
|
||
'max_amount' => round((float)($rule['max_amount'] ?? 0), 2),
|
||
'calc_mode' => $calcMode,
|
||
'commission_rate' => self::normalizeRate($rule['commission_rate'] ?? 0),
|
||
'fixed_fee' => round(max(0.00, (float)($rule['fixed_fee'] ?? 0)), 2),
|
||
'min_commission' => round(max(0.00, (float)($rule['min_commission'] ?? 0)), 2),
|
||
'max_commission' => round(max(0.00, (float)($rule['max_commission'] ?? 0)), 2),
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 创单阶段:根据订单多维上下文匹配生效抽佣规则并生成完整快照
|
||
*
|
||
* @param array $ctx ['price_type' => string, 'customer_type' => 'personal'|'merchant', 'cat_id' => int, 'urgent' => int, 'order_amount' => float]
|
||
* @param array|null $rules 可选预加载规则列表(批量导单防重复查库)
|
||
* @param array|null $defaults 可选预加载默认兜底配置
|
||
* @return array ['commission_rate' => float, 'commission_snapshot' => string(JSON), 'rule_name' => string]
|
||
*/
|
||
public static function matchOrderSnapshot(array $ctx, ?array $rules = null, ?array $defaults = null): array
|
||
{
|
||
$rules = $rules !== null ? $rules : self::getActiveRules();
|
||
$defaults = $defaults !== null ? $defaults : FinanceConfigService::getCommissionDefaults();
|
||
|
||
$priceType = trim((string)($ctx['price_type'] ?? 'fixed')) ?: 'fixed';
|
||
$customerType = in_array($ctx['customer_type'] ?? 'personal', ['personal', 'merchant'], true)
|
||
? $ctx['customer_type']
|
||
: 'personal';
|
||
$catId = max(0, (int)($ctx['cat_id'] ?? 0));
|
||
$urgent = (int)($ctx['urgent'] ?? 0) === 1 ? 1 : 0;
|
||
$orderAmount = round(max(0.00, (float)($ctx['order_amount'] ?? 0)), 2);
|
||
|
||
$fallbackItem = [
|
||
'rule_id' => 0,
|
||
'rule_name' => '全局默认兜底规则',
|
||
'min_amount' => 0.00,
|
||
'max_amount' => 0.00,
|
||
'calc_mode' => $defaults['calc_mode'],
|
||
'commission_rate' => self::normalizeRate($defaults['commission_rate']),
|
||
'fixed_fee' => round((float)$defaults['fixed_fee'], 2),
|
||
'min_commission' => round((float)$defaults['min_commission'], 2),
|
||
'max_commission' => round((float)$defaults['max_commission'], 2),
|
||
];
|
||
|
||
$staticMatched = [];
|
||
$matchedItem = null;
|
||
|
||
foreach ($rules as $rule) {
|
||
if (!self::matchStaticDimensions($rule, $priceType, $customerType, $catId, $urgent)) {
|
||
continue;
|
||
}
|
||
$item = self::extractRuleItem($rule);
|
||
$staticMatched[] = $item;
|
||
if ($matchedItem === null && self::matchAmountRange($rule, $orderAmount)) {
|
||
$matchedItem = $item;
|
||
}
|
||
}
|
||
|
||
// 若报价单创单金额为 0,且存在起始金额 > 0 的报价阶梯但暂无 0 元阶梯,优先取第一条无金额限制规则,否则暂挂兜底并保留全部阶梯候选
|
||
if ($matchedItem === null) {
|
||
$matchedItem = $fallbackItem;
|
||
}
|
||
|
||
$snapshot = [
|
||
'version' => 1,
|
||
'snapshot_time' => time(),
|
||
'context' => [
|
||
'price_type' => $priceType,
|
||
'customer_type' => $customerType,
|
||
'cat_id' => $catId,
|
||
'urgent' => $urgent,
|
||
'init_amount' => $orderAmount,
|
||
],
|
||
'include_diff_in_commission' => (int)$defaults['include_diff_in_commission'] === 1 ? 1 : 0,
|
||
'active_rule' => $matchedItem,
|
||
'fallback_rule' => $fallbackItem,
|
||
];
|
||
|
||
// 报价单创单时金额通常为 0,固化创单时刻符合静态条件的全部金额阶梯,供后续选定报价时在快照内部闭环定档
|
||
if ($priceType === 'quote' && !empty($staticMatched)) {
|
||
$snapshot['candidate_tiers'] = $staticMatched;
|
||
}
|
||
|
||
$effectiveRate = self::calcDisplayRateForAmount($orderAmount, $matchedItem);
|
||
|
||
return [
|
||
'commission_rate' => $effectiveRate,
|
||
'commission_snapshot' => json_encode($snapshot, JSON_UNESCAPED_UNICODE),
|
||
'rule_name' => $matchedItem['rule_name'],
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 报价单选定师傅报价并确认金额时:仅在订单自身的创单快照 candidate_tiers 内部重新定档(严禁读取后台新规则)
|
||
*
|
||
* @param float $finalAmount 选定报价后的订单金额
|
||
* @param mixed $existingSnapshotJson 订单表已有的 commission_snapshot
|
||
* @param mixed $existingRate 订单表已有的 commission_rate
|
||
* @return array ['commission_rate' => float, 'commission_snapshot' => string|null]
|
||
*/
|
||
public static function refreshQuoteOrderSnapshotOnAmountConfirmed(float $finalAmount, $existingSnapshotJson, $existingRate): array
|
||
{
|
||
$fallbackRate = ($existingRate !== null && trim((string)$existingRate) !== '' && is_numeric($existingRate))
|
||
? self::normalizeRate($existingRate)
|
||
: self::DEFAULT_RATE;
|
||
|
||
if (!is_string($existingSnapshotJson) || trim($existingSnapshotJson) === '') {
|
||
return [
|
||
'commission_rate' => $fallbackRate,
|
||
'commission_snapshot' => null,
|
||
];
|
||
}
|
||
|
||
$snap = json_decode($existingSnapshotJson, true);
|
||
if (!is_array($snap)) {
|
||
return [
|
||
'commission_rate' => $fallbackRate,
|
||
'commission_snapshot' => $existingSnapshotJson,
|
||
];
|
||
}
|
||
|
||
$chosen = null;
|
||
if (!empty($snap['candidate_tiers']) && is_array($snap['candidate_tiers'])) {
|
||
foreach ($snap['candidate_tiers'] as $tier) {
|
||
if (is_array($tier) && self::matchAmountRange($tier, $finalAmount)) {
|
||
$chosen = $tier;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ($chosen === null) {
|
||
if (!empty($snap['fallback_rule']) && is_array($snap['fallback_rule'])) {
|
||
$chosen = $snap['fallback_rule'];
|
||
} elseif (!empty($snap['active_rule']) && is_array($snap['active_rule'])) {
|
||
$chosen = $snap['active_rule'];
|
||
}
|
||
}
|
||
|
||
if (is_array($chosen)) {
|
||
$snap['active_rule'] = $chosen;
|
||
$snap['confirmed_quote_amount'] = round(max(0.00, $finalAmount), 2);
|
||
$snap['confirmed_time'] = time();
|
||
$newRate = self::calcDisplayRateForAmount($finalAmount, $chosen);
|
||
return [
|
||
'commission_rate' => $newRate,
|
||
'commission_snapshot' => json_encode($snap, JSON_UNESCAPED_UNICODE),
|
||
];
|
||
}
|
||
|
||
return [
|
||
'commission_rate' => $fallbackRate,
|
||
'commission_snapshot' => $existingSnapshotJson,
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 计算给定金额与规则项下的展示/快照百分比
|
||
*/
|
||
protected static function calcDisplayRateForAmount(float $amount, array $ruleItem): float
|
||
{
|
||
$mode = $ruleItem['calc_mode'] ?? 'percent';
|
||
$rate = self::normalizeRate($ruleItem['commission_rate'] ?? 0);
|
||
if ($mode === 'percent' && (float)($ruleItem['min_commission'] ?? 0) <= 0 && (float)($ruleItem['max_commission'] ?? 0) <= 0) {
|
||
return $rate;
|
||
}
|
||
if ($amount <= 0) {
|
||
return $rate;
|
||
}
|
||
$res = self::computeCommissionByRuleItem($amount, $amount, $ruleItem);
|
||
return $res['commission_rate'];
|
||
}
|
||
|
||
/**
|
||
* 核心纯函数:按规则项核算抽佣与实结金额
|
||
*
|
||
* @param float $totalPayAmount 订单总实付金额(主单实付/应付总额,师傅结算总额上限)
|
||
* @param float $calcBaseAmount 参与抽佣计算的基数金额(若增项免抽佣则已剔除增项差价)
|
||
* @param array $ruleItem 规则快照结构
|
||
* @return array
|
||
*/
|
||
protected static function computeCommissionByRuleItem(float $totalPayAmount, float $calcBaseAmount, array $ruleItem): array
|
||
{
|
||
$total = max(0.00, round($totalPayAmount, 2));
|
||
$base = max(0.00, min($total, round($calcBaseAmount, 2)));
|
||
$mode = in_array($ruleItem['calc_mode'] ?? 'percent', ['percent', 'fixed', 'mixed'], true)
|
||
? $ruleItem['calc_mode']
|
||
: 'percent';
|
||
$rate = self::normalizeRate($ruleItem['commission_rate'] ?? 0);
|
||
$fixed = round(max(0.00, (float)($ruleItem['fixed_fee'] ?? 0)), 2);
|
||
$minC = round(max(0.00, (float)($ruleItem['min_commission'] ?? 0)), 2);
|
||
$maxC = round(max(0.00, (float)($ruleItem['max_commission'] ?? 0)), 2);
|
||
|
||
if ($total <= 0 || $base <= 0) {
|
||
return [
|
||
'commission_rate' => $mode === 'percent' ? $rate : 0.00,
|
||
'commission' => 0.00,
|
||
'settle_amount' => $total,
|
||
'calc_mode' => $mode,
|
||
'rule_name' => (string)($ruleItem['rule_name'] ?? '历史比例快照'),
|
||
'calc_base_amount' => $base,
|
||
];
|
||
}
|
||
|
||
if ($mode === 'fixed') {
|
||
$rawComm = $fixed;
|
||
} elseif ($mode === 'mixed') {
|
||
$rawComm = round($base * $rate / 100 + $fixed, 2);
|
||
} else {
|
||
$rawComm = round($base * $rate / 100, 2);
|
||
}
|
||
|
||
$comm = $rawComm;
|
||
if ($minC > 0 && $comm < $minC) {
|
||
$comm = $minC;
|
||
}
|
||
if ($maxC > 0 && $comm > $maxC) {
|
||
$comm = $maxC;
|
||
}
|
||
// 抽佣额绝不可超过计佣基数或总实付额
|
||
$comm = round(min($base, max(0.00, $comm)), 2);
|
||
$settle = round(max(0.00, $total - $comm), 2);
|
||
|
||
// 若为纯比例且未触发保底/封顶与增项剔除,保留原配置比例;否则折算实际综合抽佣率供结算单归档对账
|
||
if ($mode === 'percent' && $comm === $rawComm && abs($total - $base) < 0.001) {
|
||
$effectiveRate = $rate;
|
||
} else {
|
||
$effectiveRate = $total > 0 ? self::normalizeRate(round($comm / $total * 100, 2)) : $rate;
|
||
}
|
||
|
||
return [
|
||
'commission_rate' => $effectiveRate,
|
||
'commission' => $comm,
|
||
'settle_amount' => $settle,
|
||
'calc_mode' => $mode,
|
||
'rule_name' => (string)($ruleItem['rule_name'] ?? '历史比例快照'),
|
||
'calc_base_amount' => $base,
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 基于完整订单行记录(fa_order)锁定的快照计算平台抽佣与师傅实结金额
|
||
*
|
||
* @param array $order fa_order 行数据(含 pay_amount/total_amount, diff_amount, diff_status, commission_rate, commission_snapshot)
|
||
* @param float|null $overrideAmount 可选指定结算总金额(如订单大厅预估展示时传入基准价)
|
||
* @return array ['commission_rate' => float, 'commission' => float, 'settle_amount' => float, 'calc_mode' => string, 'rule_name' => string, 'calc_base_amount' => float]
|
||
*/
|
||
public static function calcByOrder(array $order, ?float $overrideAmount = null): array
|
||
{
|
||
if ($overrideAmount !== null) {
|
||
$totalAmount = max(0.00, round($overrideAmount, 2));
|
||
} else {
|
||
$payAmt = (float)($order['pay_amount'] ?? 0);
|
||
$totAmt = (float)($order['total_amount'] ?? 0);
|
||
$totalAmount = max(0.00, round($payAmt > 0 ? $payAmt : $totAmt, 2));
|
||
}
|
||
|
||
$snapshotRate = $order['commission_rate'] ?? null;
|
||
$snapshotJson = $order['commission_snapshot'] ?? null;
|
||
|
||
if (is_string($snapshotJson) && trim($snapshotJson) !== '') {
|
||
$snap = json_decode($snapshotJson, true);
|
||
if (is_array($snap) && !empty($snap['active_rule']) && is_array($snap['active_rule'])) {
|
||
$calcBase = $totalAmount;
|
||
$includeDiff = isset($snap['include_diff_in_commission']) ? (int)$snap['include_diff_in_commission'] : 1;
|
||
if ($overrideAmount === null && $includeDiff === 0 && (int)($order['diff_status'] ?? 0) === 2) {
|
||
$diffAmt = round(max(0.00, (float)($order['diff_amount'] ?? 0)), 2);
|
||
if ($diffAmt > 0 && $calcBase >= $diffAmt) {
|
||
$calcBase = round($calcBase - $diffAmt, 2);
|
||
}
|
||
}
|
||
return self::computeCommissionByRuleItem($totalAmount, $calcBase, $snap['active_rule']);
|
||
}
|
||
}
|
||
|
||
return self::calcByOrderSnapshot($totalAmount, $snapshotRate);
|
||
}
|
||
|
||
/**
|
||
* 兼容历史仅含 commission_rate 字段或传入快照 JSON 的核算调用
|
||
*
|
||
* @param float $orderAmount 订单实付结算基数
|
||
* @param mixed $snapshotRate fa_order.commission_rate 快照值
|
||
* @param string|null $snapshotJson 可选 fa_order.commission_snapshot JSON
|
||
* @return array ['commission_rate' => float, 'commission' => float, 'settle_amount' => float, 'calc_mode' => string, 'rule_name' => string, 'calc_base_amount' => float]
|
||
*/
|
||
public static function calcByOrderSnapshot(float $orderAmount, $snapshotRate, ?string $snapshotJson = null): array
|
||
{
|
||
if ($snapshotJson !== null && trim($snapshotJson) !== '') {
|
||
return self::calcByOrder([
|
||
'pay_amount' => $orderAmount,
|
||
'total_amount' => $orderAmount,
|
||
'commission_rate' => $snapshotRate,
|
||
'commission_snapshot' => $snapshotJson,
|
||
]);
|
||
}
|
||
|
||
$rate = ($snapshotRate !== null && trim((string)$snapshotRate) !== '' && is_numeric($snapshotRate))
|
||
? self::normalizeRate($snapshotRate)
|
||
: self::DEFAULT_RATE;
|
||
|
||
return self::computeCommissionByRuleItem($orderAmount, $orderAmount, [
|
||
'rule_name' => '比例快照(' . number_format($rate, 2, '.', '') . '%)',
|
||
'calc_mode' => 'percent',
|
||
'commission_rate' => $rate,
|
||
'fixed_fee' => 0.00,
|
||
'min_commission' => 0.00,
|
||
'max_commission' => 0.00,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 将 fa_config 同步至 application/extra/site.php,并保留文件中非数据库托管的扩展密钥
|
||
*
|
||
* @param string $removedKey 刚被删除的配置键名
|
||
* @return void
|
||
*/
|
||
public static function syncSiteConfigFile(string $removedKey = ''): void
|
||
{
|
||
$siteFile = CONF_PATH . 'extra' . DS . 'site.php';
|
||
$existing = [];
|
||
if (is_file($siteFile)) {
|
||
$loaded = include $siteFile;
|
||
if (is_array($loaded)) {
|
||
$existing = $loaded;
|
||
}
|
||
}
|
||
if ($removedKey !== '' && array_key_exists($removedKey, $existing)) {
|
||
unset($existing[$removedKey]);
|
||
}
|
||
|
||
$dbConfig = [];
|
||
$rows = Db::name('config')->select();
|
||
foreach ($rows as $value) {
|
||
$val = $value['value'];
|
||
if (in_array($value['type'], ['selects', 'checkbox', 'images', 'files'], true)) {
|
||
$val = $val === '' ? [] : explode(',', (string)$val);
|
||
} elseif ($value['type'] === 'array') {
|
||
$val = (array)json_decode((string)$val, true);
|
||
}
|
||
$dbConfig[$value['name']] = $val;
|
||
}
|
||
|
||
$merged = array_merge($existing, $dbConfig);
|
||
file_put_contents(
|
||
$siteFile,
|
||
'<?php' . "\n\nreturn " . var_export($merged, true) . ";\n"
|
||
);
|
||
}
|
||
}
|