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_id(gba_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; } }