Files
CompanyProject/金壶/ydyd_service/application/common/tools/UserCart.php
2024-09-27 01:32:49 +08:00

649 lines
25 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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;
}
}