| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- <?php
- namespace bizHd\homePageConfig\classes;
- use bizHd\base\classes\BaseClass;
- use Yii;
- /**
- * 门店首页模块配置的 MySQL 落库层
- * 表 xhHomePageModuleConfig 以 shopId+moduleKey 唯一标识一条配置,是首页配置的唯一权威数据源,
- * Redis 仅作为兼容镜像:读取以本类为准,不存在时才回退旧 Redis key 并自愈迁移。
- */
- class HomePageModuleConfigClass extends BaseClass
- {
- public static $baseFile = '\bizHd\homePageConfig\models\HomePageModuleConfig';
- /**
- * 读取某模块配置,不存在返回 null(区别于「已保存的空数组/空对象」)
- *
- * @param int $shopId
- * @param string $moduleKey
- * @return array|null
- */
- public static function getConfigValue($shopId, $moduleKey)
- {
- $row = self::getByCondition(['shopId' => intval($shopId), 'moduleKey' => strval($moduleKey)]);
- if (empty($row) || !isset($row['configValue'])) {
- return null;
- }
- $decoded = json_decode($row['configValue'], true);
- return is_array($decoded) ? $decoded : null;
- }
- /**
- * 保存某模块配置:存在则更新,不存在则新建;并发写入命中唯一索引冲突时兜底改为更新
- *
- * @param int $mainId 仅作参考字段落库,不参与查重
- * @param int $shopId
- * @param string $moduleKey
- * @param array $payload
- * @return bool
- */
- public static function saveConfigValue($mainId, $shopId, $moduleKey, $payload)
- {
- $mainId = intval($mainId);
- $shopId = intval($shopId);
- $moduleKey = strval($moduleKey);
- $json = json_encode($payload, JSON_UNESCAPED_UNICODE);
- $exist = self::getByCondition(['shopId' => $shopId, 'moduleKey' => $moduleKey], true);
- if (!empty($exist)) {
- self::updateById($exist->id, ['mainId' => $mainId, 'configValue' => $json]);
- return true;
- }
- try {
- self::add(['mainId' => $mainId, 'shopId' => $shopId, 'moduleKey' => $moduleKey, 'configValue' => $json]);
- } catch (\Exception $e) {
- // 并发写入命中唯一索引冲突时兜底改为更新
- $exist = self::getByCondition(['shopId' => $shopId, 'moduleKey' => $moduleKey], true);
- if (!empty($exist)) {
- self::updateById($exist->id, ['mainId' => $mainId, 'configValue' => $json]);
- return true;
- }
- throw $e;
- }
- return true;
- }
- /**
- * 存量数据自愈迁移:MySQL 无记录时,回退读取旧 Redis key(历史按 mainId 存,新 key 按 shopId 存),
- * 命中后立即落库 MySQL 并镜像写入新 Redis key,保证后续请求都能直接从 MySQL 命中
- *
- * @param int $mainId
- * @param int $shopId
- * @param string $moduleKey
- * @param string $newRedisKey 按 shopId 生成的新 key
- * @param string $legacyRedisKey 按 mainId 生成的历史 key
- * @return array|null
- */
- public static function migrateFromRedis($mainId, $shopId, $moduleKey, $newRedisKey, $legacyRedisKey)
- {
- $raw = Yii::$app->redis->executeCommand('GET', [$newRedisKey]);
- if (empty($raw) && $legacyRedisKey !== $newRedisKey) {
- $raw = Yii::$app->redis->executeCommand('GET', [$legacyRedisKey]);
- }
- if (empty($raw)) {
- return null;
- }
- $decoded = json_decode($raw, true);
- if (!is_array($decoded)) {
- return null;
- }
- self::saveConfigValue($mainId, $shopId, $moduleKey, $decoded);
- try {
- Yii::$app->redis->executeCommand('SET', [$newRedisKey, json_encode($decoded, JSON_UNESCAPED_UNICODE)]);
- } catch (\Exception $e) {
- Yii::error('首页配置迁移写入新Redis key失败: ' . $e->getMessage());
- }
- return $decoded;
- }
- }
|