first commit

This commit is contained in:
编码猿
2024-09-27 01:32:49 +08:00
commit 28ebe05a64
7399 changed files with 1174529 additions and 0 deletions

View File

@@ -0,0 +1,649 @@
<?php
namespace app\common\tools;
use app\ydyd_service\model\UserCartModel;
use think\Db;
use think\facade\Cache;
class UserCart
{
// 个人购物车标记前缀
protected $cartName = 'USER_CART_DATA_INFO_';
// 商品数据
protected $goods = [];
// 当前用户
protected $user_id = 0;
//初始化缓存数据
public function __construct($user_id = null)
{
$init_flag = false;
$this->user_id = session('user_id')?session('user_id'):$user_id;
if($user_id){
$this->cartName .= 'API_';
}
$this->cartName .= $this->user_id;
//Cache::rm($this->cartName);
//完善 缓存不存在且表中无记录Cache::get()默认值
$default_result = ['goods_list'=>['gba'=>[],'gbaa'=>[]],'total_num'=>0,'total_price'=>0];
$default_data = Cache::get($this->cartName,$default_result)['goods_list']??[];//缓存数据索引goods_list;
if (!$default_data){//缓存不存在,从数据库表读取并设置缓存
$_where = [];
$_where[] = ['user_id',"=",$this->user_id];
$_where[] = ['type',"=",''];//type为空自营否则如 hy华源(目前统一标记为extend),此处未处理扩展商品
//购物车数据--user_cart表 price_type字段由自定义模型获取器由0/1修改为gba、gbaa
$cart_data = UserCartModel::field('id,price_type,price_id,batch_id,goods_number as num, unit_price as price')->where($_where)->select()->toArray();
if ($cart_data){
$init_flag = true;
foreach ($cart_data as $item){
$this->initCartData($item, true);//添加到购物车数据缓存
}
$this->store();
}
}
//缓存存在,更新缓存(有效期?)
if (!$init_flag){//init_flag=false: 1.缓存存在(缓存信息来源于数据库)2.缓存不存在 且 user_cart表无记录
//$this->setGoods($default_data);//缓存数据存在时,$this->goods = 缓存数据?;缓存不存在,赋值为空数组
$this->reCreateCartCache(true);//暂时冗余执行重建缓存后期添加user_cart操作日志作为判断标准判定是否重建
}
}
/**
* cart缓存数据初始化分离不再公用add方法
*
* */
public function initCartData($data,$init_flag=false){
if (is_array($data)&&!empty($data)&&$init_flag){
//初始化缓存信息
$to_cache = [];
$to_cache['id']=$data['id'];
$to_cache['batch_id'] = $data['batch_id'];
$to_cache['num'] = $data['num'];
$to_cache['price'] = $data['price'];
$to_cache['price_id'] = $data['price_id'];
$to_cache['price_type'] = $data['price_type'];
$to_cache['total'] = $data['price']*$data['num'];
//price_id严格存储gba.id或gbaa.id
//$arr_price_type = [0=>'gba',1=>'gbaa'];
//$data['price_type']已由修改器修改为对应gba/gbaa
$this->goods[$data['price_type']][$data['price_id']] = $to_cache;//price_idgba_id充当sku_id作用user_cart不存在同一用户两条相同price_id的记录
}
}
/**
* 数据库记录变更(删除、更新、新增……)之后更新缓存
* */
public function reCreateCartCache($recreate=false){
if ($recreate){
$this->goods = ['gba'=>[],'gbaa'=>[]];
$recreate_where = [];
$recreate_where[] = ['user_id',"=",$this->user_id];
$recreate_where[] = ['type',"=",''];//type为空自营否则如 hy华源(目前统一标记为extend),此处未处理扩展商品
$cart_data = UserCartModel::field('id,price_type,price_id,batch_id,goods_number as num, unit_price as price')->where($recreate_where)->select()->toArray();
if ($cart_data){
foreach ($cart_data as $item){
$this->initCartData($item, true);//添加到购物车数据缓存
}
$this->store();
}
}
}
/**
* gbaa/gba价格变化
* */
public function updatePriceChange(){
$_where = [];
$_where[] = ['user_id','=',$this->user_id];
$old_data = Db::name('user_cart')->where($_where);
$gbaa_id = $old_data->where('price_type','=',1)->column('price_id');
$uc_gbaa_price = $old_data->where('price_type','=',1)->column('unit_price','price_id');
$gba_id = $old_data->where('price_type','=',0)->column('price_id');
$uc_gba_price = $old_data->where('price_type','=',0)->column('unit_price','price_id');
$price_gbaa_now = Db::name('goods_batch_area_agent_relation')->where('id','in',$gbaa_id)->column('agent_price','id');
$price_gba_now = Db::name('goods_batch_area_relation')->where('id','in',$gba_id)->column('price','id');
/**
* 注意column返回数据结构 price_id=>unit_price
* */
if (is_array($uc_gba_price)&&$uc_gba_price){
foreach ($uc_gba_price as $pid=>$unit_price){
$old_data = Db::name('user_cart')->where($_where);
if (isset($price_gba_now[$pid]) && ($price_gba_now[$pid]!=$unit_price)){
$old_data->where('price_type','=',0)->where('price_id','=',$pid)->update(['unit_price'=>$price_gba_now[$pid],'update_time'=>date('Y-m-d H:i:s')]);
}
}
}
//重置query对象
$old_data = Db::name('user_cart')->where($_where);
if (is_array($uc_gbaa_price)&&$uc_gbaa_price){
foreach ($uc_gbaa_price as $pid=>$unit_price){
$old_data = Db::name('user_cart')->where($_where);
if (isset($price_gbaa_now[$pid]) && ($price_gbaa_now[$pid]!=$unit_price)){
$old_data->where('price_type','=',1)->where('price_id','=',$pid)->update(['unit_price'=>$price_gbaa_now[$pid],'update_time'=>date('Y-m-d H:i:s')]);
}
}
}
//单价处理完成之后修改购物车数据
$this->reCreateCartCache(true);
return true;
}
/**
* 保存到缓存
*
* 缓存数据结构
* $cart =
* [
* 'goods_list'=>[
* //问题存在 price_id gba.id = gbaa.id
* 'price_id'=>['id'=>$id,'batch_id'=>$batch_id,'goods_num'=>$num,'price'=>$price,'price_type'=>$price_type,'total'=>$price*$num],//新增user_cart id
* 'price_id'=>['id'=>$id,'batch_id'=>$batch_id,'goods_num'=>$num,'price'=>$price,'price_type'=>$price_type,'total'=>$price*$num],
* ],
* 'total_num' =>$num,//batch_id数量相同batch_id合并处理
* 'total_price'=>$total_price,//总金额
* ]
* 修改如下
* $cart =
* [
* 'goods_list'=>[
*
* 'gba'=>[ 'price_id'=>['id'=>$id,'batch_id'=>$batch_id,'goods_num'=>$num,'price'=>$price,'price_type'=>$price_type,'total'=>$price*$num],]//新增user_cart id
* 'gbaa'=>['price_id'=>['id'=>$id,'batch_id'=>$batch_id,'goods_num'=>$num,'price'=>$price,'price_type'=>$price_type,'total'=>$price*$num],],
* ],
* 'price_id'=>['gba'=>[],'gbaa'=>[]]
* 'total_num' =>$num,//batch_id数量相同batch_id合并处理
* 'total_price'=>$total_price,//总金额
* ]
*
* 重点 $goods 赋值逻辑!
*/
private function store()
{
$cart = [
'goods_list' => $this->goods,
'total_num' => $this->getTotalNums(),
'total_price' => $this->getTotalPrice(),
'price_id' => $this->getPriceId(),
];
Cache::set($this->cartName,$cart,config('SYSTEM_CONSTANT')['USER_INFO_CACHE_TIME']);
}
/**
* 统计购物车中数据条数
*/
public function getTotalNums()
{
$rows = 0;
//空数组 不会进入循环体内执行$num++
if (isset($this->goods['gba'])&&$this->goods['gba']){
foreach ($this->goods['gba'] as $v) {
//$rows += $v['num'];
$rows ++;
}
}
if (isset($this->goods['gbaa'])&& $this->goods['gbaa']){
foreach ($this->goods['gbaa'] as $v) {
//$rows += $v['num'];
$rows ++;
}
}
return $rows;
}
/**
* 获得商品汇总价格
*/
public function getTotalPrice()
{
$total = 0;
if (isset($this->goods['gba'])&&$this->goods['gba']){
foreach ($this->goods['gba'] as $v) {
$total += $v['price'] * $v['num'];
}
}
if (isset($this->goods['gbaa'])&&$this->goods['gbaa']){
foreach ($this->goods['gbaa'] as $v) {
$total += $v['price'] * $v['num'];
}
}
return $total;
}
/**
* 价格id
* */
public function getPriceId(){
$price_id = ['gba'=>[],'gbaa'=>[]];
if (isset($this->goods['gba'])&&$this->goods['gba']){
$price_id['gba'] = array_keys($this->goods['gba']);
}
if (isset($this->goods['gbaa'])&&$this->goods['gbaa']){
$price_id['gbaa'] = array_keys($this->goods['gbaa']);
}
return $price_id;
}
public function getGoods()
{
return $this->goods;
}
public function setGoods($goods)
{
$this->goods = $goods;
$this->store();
}
/**
* 用户添加购物车
* 更新缓存数据+数据库记录
* 商品检测状态、库存、批次状态、gba_id/gbaa_id
* */
public function addProduct($data){
if (is_array($data)&&!empty($data)){//其他校验service接口已处理
$where = [];
$where[] = ['batch_id','=',$data['batch_id']];
$where[] = ['price_id','=',$data['price_id']];
$where[] = ['user_id','=',$this->user_id];
$where[] = ['price_type','=',$data['price_type']];
$gba_or_gbaa = ($data['price_type']==1)? 'gbaa':'gba';
$has = UserCartModel::where($where)->find();
if (!$has){
//数据库不存在记录
$add_data = [];
$add_data['batch_id'] = $data['batch_id'];
$add_data['goods_number'] = $data['goods_number'];
$add_data['unit_price'] = $data['price'];
$add_data['price_type'] = $data['price_type'];
$add_data['price_id'] = $data['price_id'];
$add_data['user_id'] = $this->user_id;
$add_data['create_time'] = date('Y-m-d H:i:s',time());//只接赋值time()的情况下UserCartModel自行添加修改器定义
$add_data['update_time'] = date('Y-m-d H:i:s',time());
if (isset($data['type'])){
$add_data['type'] = $data['type'];
}
if (isset($data['extend_data'])){
$add_data['extend_data'] = $data['extend_data'];
}
$id = UserCartModel::create($add_data)->getAttr('id');//写入并获取id
//price_id 索引的情况下该price_id为gba_id存在多条记录同price_id的可能性(一个平台价对应多个同一地区的多个代理价格)
if ($id){
//更新缓存信息
$to_cache = [];
$to_cache['id']=$id;
$to_cache['batch_id'] = $add_data['batch_id'];
$to_cache['num'] = $add_data['goods_number'];
$to_cache['price'] = $add_data['unit_price'];
$to_cache['price_id'] = $add_data['price_id'];
//$this->goods[$id] = $to_cache;
$this->goods[$gba_or_gbaa][$add_data['price_id']]= $to_cache;//改为price_id索引
//unset($to_cache);
$this->store();
}
}else{
//数据库存在记录
$add_data = [];
$add_data['batch_id'] = $data['batch_id'];
$add_data['goods_number'] = $data['goods_number']+$has->goods_number;
$add_data['unit_price'] = $data['price'];
$add_data['price_type'] = $data['price_type'];
$add_data['price_id'] = $data['price_id'];
$add_data['user_id'] = $this->user_id;
$add_data['update_time'] = date('Y-m-d H:i:s',time());
$id = $has->id;
UserCartModel::where('id','=',$id)->update($add_data);
//更新缓存信息
$to_cache = [];
$to_cache['id']=$id;
$to_cache['batch_id'] = $add_data['batch_id'];
$to_cache['num'] = $data['goods_number']+$has->goods_number;
$to_cache['price'] = $add_data['unit_price'];
$to_cache['price_id'] = $add_data['price_id'];
//$this->goods[$id] = $to_cache;
$this->goods[$gba_or_gbaa][$add_data['price_id']]= $to_cache;//改为price_id索引
//unset($to_cache);
$this->store();
}
}
}
/**
* 数据来源:
* 1.初始化--user_cart表数据写入
* 2.客户端请求--添加购物车操作
*
* 购物车信息更新:
* 客户端发起请求(新增、删除、修改)
* 商品状态变化--1.数据获取是相对实时的(缓存有效期内视为暂无变化)---无需处理2.缓存期间已变化,下单时验证
*
* 缓存操作:
* 1.数据库读取写入缓存
* 2.客户端请求操作
*
* @todo 现有业务逻辑待厘清
* 添加购物车 同时更新model
* @access public
* @param array $data
* $data为数组包含以下几个值
* $Data= [
* "id"=>1, //批次ID
* "num"=>2, //商品数量
* "options"=>array() //其他参数,如价格、颜色可以是数组或字符串|可以不添加
* ]
*
* @throws \Exception
* @return void
*/
public function add($data,$init_flag = false)
{
//增加num类型校验
//add price_type、price_id 暂不验证 添加购物车请求调用本方法?
if ( !is_array($data) || !isset($data['id']) || !(isset($data['num'])&&is_numeric($data['num'])) || !isset($data['price']) || ($data['price'] <0)) {
throw new \Exception('购物车ADD方法参数设置错误');//抛出异常keys捕获异常--异常处理
}
//$sid = md5($data['id']);
$sid = $data['id'];//batch_id
$id = $data['ucid'];
$_where = [];
$_where[] = ['user_id',"=",$this->user_id];
$_where[] = ["batch_id","=",$sid];
//生成唯一ID用于处理相同商品有不同属性时
if (isset($this->goods[$sid])) {//缓存已存在(默认数据库表存在记录)
$_where[] = ['id','=',$data['ucid']];//batch_id+user_id存在条件不足增加user_cart表id确保唯一注意同步客户端请求参数添加
//如果数量为0删除商品--客户端删除操作init_flag=false
if ($data['num'] == 0) {
unset($this->goods[$sid]);//先删除缓存数据后删除user_cart表
if (!$init_flag){
//user_id+batch_id校验足矣暂时默认不存在同一batch_id的多条记录
UserCartModel::where($_where)->delete();//模型delete模型对象or数据表软删除
}
} else {//不为0 增加
//已经存在相同商品时增加商品数量
$this->goods[$sid]['num'] = $this->goods[$sid]['num'] + $data['num'];
$this->goods[$sid]['total'] = $this->goods[$sid]['num'] * $this->goods[$sid]['price'];//两次添加,销售价格不一样未处理
if (!$init_flag){//客户端请求处理
if ($this->goods[$sid]['num'] > 0){
$update_data['goods_number'] = $this->goods[$sid]['num'];
$update_data['unit_price'] = $this->goods[$sid]['price'];//价格变动?默认修改为最新单价
UserCartModel::where($_where)->update($update_data);
}else{
UserCartModel::where($_where)->delete();
}
}
}
} else {//不存在 写入goods和user_cart表
if ($data['num'] > 0) {
/*$this->goods[$sid] = $data;//batch_id索引对应商品数据
$this->goods[$sid]['total'] = $data['num'] * $data['price'];//金额*/
//设置goods数据改为id索引
$this->goods[$id] = $data;//batch_id索引对应商品数据
$this->goods[$id]['total'] = $data['num'] * $data['price'];//金额*/
if (!$init_flag) {//待确定? 暂时理解为添加购物车请求调用此处add方法写入数据库
$add_data = [];
$price_id = 0;
$price_type = 0;//默认为平台价格
if (isset($data['gba_id'])&&is_numeric($data['gba_id'])){
$price_id = $data['gba_id'];
$price_type = 0;
}
if (isset($data['gbaa_id'])&& is_numeric($data['gbaa_id'])){
$price_id = $data['gbaa_id'];
$price_type = 1;
}
$add_data['price_id'] = $price_id;
$add_data['price_type'] = $price_type;
$add_data['user_id'] = $this->user_id;
$add_data['batch_id'] = $sid;
$add_data['unit_price'] = $data['price'];
$add_data['goods_number'] = $data['num'];
UserCartModel::create($add_data);
}
}
}
//每add一条数据即缓存一次,确保缓存为最新状态
return $this->store();
}
/**
*
* 客户端请求处理待完善
* 更新购物车数量(update+delete操作)
* 适用场景:
* 1.删除购物车数据传值goods_number=0
* 2.更新shopping_cart表中价格和数量信息
*
* @param $data
* $data=[
* "sid"=>'', //商品的唯一SID
* "num"=>2, //商品数量
* ]
* @return bool
* @throws \Exception
*/
public function update($data,$flag=true)
{
if (!isset($data['id']) || !isset($data['batch_id']) || !isset($data['num'])) {
throw new \Exception('购物车update方法参数错误缺少ucid或batch_id或num值');
}
$_where = [];
$_where[] = ['user_id',"=",$this->user_id];
$_where[] = ["batch_id","=",$data['batch_id']];
$_where[] = ['id','=',$data['id']];
$price_type_array = [0=>'gba',1=>'gbaa'];
$price_type = $price_type_array[$data['price_type']];
$_where[] = ['price_type','=',$price_type];
if (isset($this->goods[$data['price_type']]['price_id'])) {
if ($data['num'] == 0) {
unset($this->goods[$data['id']]);
UserCartModel::where($_where)->delete();
} else {
if ($flag){
$this->goods[$data['price_type']]['price_id']['num'] += $data['num'];
}else{//flag处理意外原因造成的价格不匹配此时数量无需累加
$this->goods[$data['price_type']]['price_id']['num'] = $data['num'];
}
if (isset($data['price']) && is_numeric($data['price']) && ($data['price'] > 0)){
$this->goods[$data['price_type']]['price_id']['price'] = $data['price'];
}
$this->goods[$data['price_type']]['price_id']['total'] = sprintf('%.2f',$this->goods[$data['price_type']]['price_id']['num'] * $this->goods[$data['price_type']]['price_id']['price']);
$update_data['goods_number'] = $this->goods[$data['price_type']]['price_id']['num'];
$update_data['unit_price'] = $this->goods[$data['price_type']]['price_id']['price'];
$this->store();
UserCartModel::where($_where)->update($update_data);
$this->reCreateCartCache(true);
}
$this->store();
}
}
//更新--对应ShopCartService中putInCart方法中价格不匹配更新操作
public function updatePrice($data,$flag=true)
{
if (!isset($data['id']) || !isset($data['price_id']) || !isset($data['batch_id']) || !isset($data['num'])) {
throw new \Exception('购物车update方法参数错误缺少ucid或sid或num值');
}
$_where[] = ['user_id',"=",$this->user_id];
$_where[] = ["batch_id","=",$data['batch_id']];
$_where[] = ['id','=',$data['id']];
$_where[] = ['price_id','=',$data['price_id']];
if (isset($this->goods[$data['price_id']])) {
if ($data['num'] == 0) {
unset($this->goods[$data['price_id']]);
UserCartModel::where($_where)->delete();
} else {
if ($flag){
$this->goods[$data['price_id']]['num'] += $data['num'];
}else{//flag处理意外原因造成的价格不匹配此时数量无需累加
$this->goods[$data['price_id']]['num'] = $data['num'];
}
if (isset($data['price']) && is_numeric($data['price']) && $data['price'] > 0){
$this->goods[$data['price_id']]['price'] = $data['price'];
}
$this->goods[$data['price_id']]['total'] = $this->goods[$data['price_id']]['num'] * $this->goods[$data['price_id']]['price'];
$update_data['goods_number'] = $this->goods[$data['price_id']]['num'];
$update_data['unit_price'] = $this->goods[$data['price_id']]['price'];
UserCartModel::where($_where)->update($update_data);
$this->reCreateCartCache(true);
}
$this->store();
}
}
/**
* 获得购物车中的所有数据(缓存中取出,初始状态为空)
* @return mixed
*/
public function getAllData()
{
$this->store();//缓存数据,冗余更新缓存有效期?
return Cache::get($this->cartName);//cartName格式前缀+user_id缓存值(session)
}
public function getGoodsList(){
$data = $this->getAllData()['goods_list'];
$res = [];
if (isset($data['gba'])&&$data['gba']){
foreach ($data['gba'] as $pid=>$item){
$res[] = $item;
}
}
if (isset($data['gbaa'])&&$data['gbaa']){
foreach ($data['gbaa'] as $pid=>$item){
$res[] = $item;
}
}
return $res;
}
/**
* 获取购物车内所有商品的price_id(gba.id or gbaa.id)
* @return array
*/
public function getAllPriceId()
{
$id_arr = [];
if (isset($this->goods['gba'])&&$this->goods['gba']){
foreach ($this->goods['gba'] as $k => $item) {
$id_arr[] = $item['price_id'];
}
}
if (isset($this->goods['gbaa'])&&$this->goods['gbaa']){
foreach ($this->goods['gbaa'] as $k => $item) {
$id_arr[] = $item['price_id'];
}
}
return $id_arr;
}
/**
* 获取购物车内所有商品的ID信息(batch_id)
* @return array
*/
public function getAllId()
{
$id_arr = [];
foreach ($this->goods as $k => $item) {
$id_arr[] = $item['id'];
}
return $id_arr;
}
/**
* 获取购物车内所有商品的ID信息(user_cart.id)
* 【自营商品】
* @return array
*/
public function getAllUcId()
{
$id_arr = [];
if (isset($this->goods['gba'])&&$this->goods['gba']){
foreach ($this->goods['gba'] as $k => $item) {
$id_arr[] = $item['id'];
}
}
if (isset($this->goods['gbaa'])&&$this->goods['gbaa']){
foreach ($this->goods['gbaa'] as $k => $item) {
$id_arr[] = $item['id'];
}
}
return $id_arr;
}
/**
* 删除购物车,同步删除数据库表记录
* @param $sid 商品SID编号
* user_cart表id
* @return bool
* @throws \Exception
*/
public function del($sid)
{
if (isset($this->goods[$sid])) {
unset($this->goods[$sid]);
$_where[] = ['user_id',"=",$this->user_id];
$_where[] = ["price_id","=",$sid];
UserCartModel::where($_where)->delete();//没有更新缓存
$this->store();
return true;
}
return false;
}
/**
* 删除所有商品
* @return bool
* @throws \Exception
*/
public function flush()
{
UserCartModel::where("user_id",$this->user_id)->delete();
//['goods_list'=>['gba'=>[],'gbaa'=>[]],'total_num'=>0,'total_price'=>0]
$this->setGoods(['gba'=>[],'gbaa'=>[]]);
$this->store();
return true;
}
}