Files
hyperf_service/app/Cache/Redis/Api/GoodCache.php
2025-04-18 09:29:27 +08:00

418 lines
10 KiB
PHP

<?php
namespace App\Cache\Redis\Api;
use App\Cache\Redis\RedisCache;
use App\Constants\Common\GoodCode;
use App\Extend\DateUtil;
use App\Model\AdminUser;
use App\Model\Purchase;
use App\Model\Sku;
use App\Model\Spu;
use App\Service\ServiceTrait\Common\OssTrait;
use Hyperf\Di\Annotation\Inject;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class GoodCache
{
use OssTrait;
/**
* @var RedisCache $redis
*/
#[Inject]
protected RedisCache $redis;
/**
* @var Spu $spuModel
*/
#[Inject]
protected Spu $spuModel;
/**
* @var Sku $skuModel
*/
#[Inject]
protected Sku $skuModel;
/**
* @var Purchase
*/
#[Inject]
protected Purchase $purchaseModel;
/**
* @var int $cycleId
*/
public int $cycleId;
/**
* @var AdminUser
*/
#[Inject]
protected AdminUser $adminUserModel;
/**
* @var int $kitchenId
*/
public int $kitchenId;
/**
* @var string
*/
protected string $optionalKey;
/**
* @var string
*/
protected string $mealKey;
/**
* @var string
*/
protected string $purchaseKey;
/**
* @var array $stockArr
*/
private array $stockArr = [];
/**
* @var int
*/
private int $expireTime;
/**
* @return void
*/
public function __construct()
{
$this->expireTime = DateUtil::DAY;
}
/**
* @param int $id
* @return bool|float|int|\Redis
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function getStock(int $id): float|bool|int|\Redis
{
$stockKey = ApiRedisKey::goodStockKey($this->cycleId,$this->kitchenId);
return $this->redis->zScore($stockKey, $id) ?? 0;
}
/**
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function initGoodCacheByCycleId(): void
{
$this->mealKey = ApiRedisKey::mealGoodListKey($this->cycleId,$this->kitchenId);
$this->optionalKey = ApiRedisKey::optionalGoodListKey($this->cycleId,$this->kitchenId);
if ($this->checkMealGoodCache() && $this->checkOptionalGoodCache()) return;
$this->setOptionalGoodCache();
$this->setMealGoodCache();
if (!empty($this->stockArr)) {
$stockKey = ApiRedisKey::goodStockKey($this->cycleId,$this->kitchenId);
foreach ($this->stockArr as $one) {
$this->redis->zAdd($stockKey,$one['stock'],$one['id']);
}
$this->redis->expire($stockKey,$this->expireTime);
}
}
/**
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function initPurchaseCacheByCycleId(): void
{
$this->purchaseKey = ApiRedisKey::purchaseGoodListKey($this->cycleId,$this->kitchenId);
if ($this->checkPurchaseGoodCache()) return;
$this->setPurchaseGoodCache();
}
/**
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function setMealGoodCache(): void
{
$list = $this->spuModel->getListByCycleIdAndType($this->cycleId, $this->kitchenId,GoodCode::SPU_TYPE_MEAL);
if (empty($list)) return;
$list = $list->toArray();
$this->buildData($list);
$this->redis->set($this->mealKey, json_encode($list));
$this->redis->expire($this->mealKey,$this->expireTime);
}
/**
* @param $list
* @return mixed
*/
private function buildData(&$list): mixed
{
$spuIds = array_column($list, 'id');
$skuList = $this->skuModel->getListBySpuIds($spuIds);
if ($skuList->isEmpty()) return $list;
$skuList = $skuList->toArray();
$imageIdArr = array_column($skuList,'image_ids');
$imageList = $this->getOssObjects($imageIdArr);
$chefIds = array_column($skuList,'chef_id');
$chefList = $this->adminUserModel->getDataByIds($chefIds);
$skuListArr = [];
$imageArr = [];
$stockArr = [];
$price = [];
foreach ($skuList as $sku) {
if (empty($skuListArr[$sku['spu_id']])) {
$skuListArr[$sku['spu_id']] = [];
}
$sku['url'] = $imageList[$sku['image_ids']]['url'] ?? '';
$sku['chef_name'] = $chefList[$sku['chef_id']]['chinese_name'] ?? '';
$skuListArr[$sku['spu_id']][] = $sku;
$price[$sku['spu_id']][] = $sku['price'];
$imageArr[$sku['spu_id']] = array_merge($imageArr[$sku['spu_id']] ?? [],[$sku['url']]);
$stockArr[] = [
'id' => $sku['id'],
'stock' => $sku['surplus_stock']
];
}
if (!empty($stockArr)) {
$this->stockArr = array_merge($this->stockArr,$stockArr);
}
foreach ($list as &$item) {
$item['sku_list'] = $skuListArr[$item['id']] ?? [];
$item['image_list'] = $imageArr[$item['id']] ?? [];
$item['price'] = !empty($price[$item['id']]) ? (min($price[$item['id']]) ?? 0) : 0;
}
return $list;
}
/**
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function setPurchaseGoodCache(): void
{
$list = $this->purchaseModel->getListByCycleIdAndKitchenId($this->cycleId, $this->kitchenId);
if ($list->isEmpty()) return;
$list = $list->toArray();
$imageIds = array_column($list,'image_id');
$imageList = $this->getOssObjects($imageIds);
foreach ($list as &$item) {
$item['url'] = $imageList[$item['image_id']]['url'] ?? '';
}
$this->redis->set($this->purchaseKey, json_encode($list));
$this->redis->expire($this->purchaseKey,$this->expireTime);
}
/**
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function setOptionalGoodCache(): void
{
$list = $this->spuModel->getListByCycleIdAndType($this->cycleId, $this->kitchenId,GoodCode::SPU_TYPE_OPTIONAL);
if (empty($list)) return;
$list = $list->toArray();
$this->buildData($list);
$this->redis->set($this->optionalKey, json_encode($list));
$this->redis->expire($this->optionalKey,$this->expireTime);
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function checkMealGoodCache(): bool
{
if ($this->redis->exists($this->mealKey)) return true;
$this->redis->delete($this->mealKey);
return false;
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function checkPurchaseGoodCache(): bool
{
if ($this->redis->exists($this->purchaseKey)) return true;
$this->redis->delete($this->purchaseKey);
return false;
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function checkOptionalGoodCache(): bool
{
if ($this->redis->exists($this->optionalKey)) return true;
$this->redis->delete($this->optionalKey);
return false;
}
/**
* @return array|mixed
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function getOptionalGoodList(): mixed
{
$this->initGoodCacheByCycleId();
$data = $this->redis->get($this->optionalKey);
if (empty($data)) return [];
$data = json_decode($data,true);
$this->buildStockData($data);
return $data;
}
/**
* @return mixed
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function getPurchaseGoodList(): mixed
{
$this->initPurchaseCacheByCycleId();
$data = $this->redis->get($this->purchaseKey);
if (empty($data)) return [];
$data = json_decode($data,true);
return $data;
}
/**
* @param $data
* @return mixed
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function buildStockData(&$data): mixed
{
foreach ($data as &$spu) {
foreach ($spu['sku_list'] as &$sku) {
$sku['stock'] = $this->getStock($sku['id']);
}
}
return $data;
}
/**
* @return array|mixed
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function getMealGoodList(): mixed
{
$this->initGoodCacheByCycleId();
$data = $this->redis->get($this->mealKey);
if (empty($data)) return [];
$data = json_decode($data,true);
$this->buildStockData($data);
return $data;
}
/**
* @param int $kitchenId
* @param int $cycleId
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function delCache(int $kitchenId,int $cycleId): void
{
$keyArr = [
ApiRedisKey::mealGoodListKey($cycleId,$kitchenId),
ApiRedisKey::optionalGoodListKey($cycleId,$kitchenId),
ApiRedisKey::goodStockKey($cycleId,$kitchenId)
];
$script = <<<LUA
local corpseCount = 0
for _, key in ipairs(KEYS) do
corpseCount = corpseCount + redis.call('DEL', key)
end
return corpseCount
LUA;
$this->redis->eval($script, $keyArr,count($keyArr));
}
/**
* @param int $kitchenId
* @param int $cycleId
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function delPurchaseCache(int $kitchenId,int $cycleId): void
{
$key = ApiRedisKey::purchaseGoodListKey($cycleId,$kitchenId);
$this->redis->delete($key);
}
}