<?php
/**
* Redis + 单例型购物车
* param $basket 存储商品信息
* param $ins 存储实例化对象
*/
namespace lib; use redis\Redis;
class Cart{
private $expire = 43200; //redis购物车商品缓存过期时间
private $redis = Null;
private $redis_ext = ''; //redis缓存键名拼接字符串
private $cachekey = Null;
private $basket = []; //私有空数组用于存放商品信息 /**
* 购物车初始化,传入用户id
*/
public function init($user_id){
$this->redis = Redis::ins(); //调用redis缓存类(连接redis)
$this->redis_ext = '.'.config('system')['project_name_zn']; //redis缓存键名拼接项目中文名称字符串
$this->cachekey = "user.cart.{$user_id}".$this->redis_ext; //redis缓存键名拼接用户ID与项目中文名称字符串为对象用户购物车缓存键名
$this->basket = json_decode($this->redis->get($this->cachekey),true); //获取对象用户的redis购物车商品缓存信息并解码为PHP数组
} //添加商品 $id 商品ID $attr_id 商品对应属性ID $goodsName 商品名称 $number 加入数量 $price 商品对应属性单价
public function addbasket( $id, $attr_id, $goodsName, $attr_name, $number, $price , $freight ){
//判断对象商品是否已经存在redis购物车商品缓存内
if( $this->isExist($id,$attr_id) ){
//存在时增加该对象商品数量
return $this->add($id, $attr_id ,$number);
} //对象商品不在redis购物车商品缓存内时
$tmp = [];
$tmp['goods_id'] = intval($id); //对象商品ID
$tmp['attr_id'] = intval($attr_id); //对象商品对应属性ID
$tmp['goods_name'] = $goodsName; //对象商品名称
$tmp['attr_name'] = $attr_name; //对象商品名称
$tmp['goods_number'] = intval($number); //对象商品数量,新增的商品默认加入数量为1
$tmp['price'] = intval($price); //对象商品对应属性单价
$tmp['freight'] = intval($freight); //对象商品运费
$tmp['subtotal'] = $tmp['goods_number'] * $price; //对象商品总价 $this->basket[] = $tmp; //新的商品信息存入redis购物车商品缓存信息解码的PHP数组内,每件属性商品信息对应一个索引键值 //重新将新的购物车商品信息数组编码为json字符串存入对象用户redis购物车商品缓存内
$this->redis->setex($this->cachekey,$this->expire,json_encode($this->basket)); return 1;
} //判断商品是否已经存在
// $id 商品ID
// $attr_id 商品属性ID
public function isExist($id,$attr_id){
$isExist = false;
//当对象用户redis购物车商品缓存不为空时
if( !empty($this->basket) ){
foreach ($this->basket as $key=>$val){
if( $val['goods_id'] == $id && $attr_id == $val['attr_id'] ){
$isExist = true;
break;
}
}
}
return $isExist;
} //获取所有商品信息
public function getAll(){
return $this->basket;
} //获取部分商品信息
public function getPartGoods($ids)
{
$goods = [];
foreach ($ids as $v) {
foreach ($this->basket as $k => $val) {
if ($val['goods_id'] == $v['goods_id'] && $val['attr_id'] == $v['attr_id']) {
$goods[] = $val;
}
}
}
return $goods;
} //获取部分商品总数
public function getPartGoodsNum($ids)
{
$number = '';
foreach ($ids as $v) {
foreach ($this->basket as $k => $val) {
if ($val['goods_id'] == $v['goods_id'] && $val['attr_id'] == $v['attr_id']) {
$number += $val['goods_number'];
}
}
}
return $number;
} /*添加商品
* @param $id商品id
* @param $number 添加的数量 默认为1
* @param $type 1为在原有商品数上添加 总商品数= 当前数 + 历史数,2为总商品数 默认为 1
*/
public function add($id, $attr_id ,$number){
$goods_number = 0; //加入不成功时默认返回添加数量为0
//商品ID不为空并且商品在redis购物车商品缓存内
if( !empty($id) && $this->isExist($id ,$attr_id) ){
$cache_detail = $this->basket; //获取用户购物车所有商品信息
foreach ($cache_detail as $key=>$val){
if( $val['goods_id'] == $id && $val['attr_id'] == $attr_id){
$val['goods_number'] = $val['goods_number']+$number; //购物车存在该商品时增加该商品数量
$val['subtotal'] = $val['goods_number']*$val['price']; //购物车存在该商品时重新计算该件商品总价
$this->basket[$key] = $val; //购物车存在该商品时重新将新的商品信息放入该商品的redis缓存信息内($key即为该商品的redis缓存键值)
$this->redis->setex($this->cachekey,$this->expire,json_encode($this->basket)); //购物车存在该商品时更新该商品的redis缓存信息
$goods_number = $val['goods_number']; //商品加入成功将商品数量赋值变量返回
break;
}
}
}
return $goods_number; //返回商品数量
} //减一商品
public function reduce($id, $attr_id ,$number){
$goods_number = 0;
if(!empty($id) && $this->isExist($id ,$attr_id )){
$cache_detail = $this->basket;
foreach ($cache_detail as $key=>$val){
if( $val['goods_id'] == $id && $val['attr_id'] == $attr_id ){
$val['goods_number'] = $val['goods_number']-$number;
$goods_number = $val['goods_number'];
//若为0则删除
if( $val['goods_number'] <= 0 ){
$this->dele($id ,$attr_id);
$this->redis->setex($this->cachekey,$this->expire,json_encode($this->basket));
$goods_number = 0;
break;
}
$val['subtotal'] = $val['goods_number']*$val['price'];
$this->basket[$key] = $val;
$this->redis->setex($this->cachekey,$this->expire,json_encode($this->basket));
break;
}
}
}
return $goods_number;
} //删除商品
public function dele($ids){
if(is_array($ids)){
foreach ($ids as $v){
foreach ($this->basket as $k=>$val) {
if( $val['goods_id'] == $v['goods_id'] && $val['attr_id'] == $v['attr_id'] ){
array_splice($this->basket,$k,1);
}
}
}
}else{
foreach ($this->basket as $k=>$val) {
if( $val['goods_id'] == $ids){
//unset(self::$basket[$k]);
array_splice($this->basket,$k,1);
}
}
}
$this->redis->setex($this->cachekey,$this->expire,json_encode($this->basket));
return true;
} //清空购物车
public function emptyCart(){
return $this->redis->del($this->cachekey);
} //部分商品总价(包含商品运费) $type不为0时商品总价与商品总运费作为关联数组返回
public function getTotalPrices($ids,$type=0)
{
$totalPrice = 0;
$goods_freight = [];
$freight = 0;
foreach ($ids as $v) {
foreach ($this->basket as $k => $val) {
if ($val['goods_id'] == $v['goods_id'] && $val['attr_id'] == $v['attr_id']) {
$totalPrice += $val['subtotal'];
$goods_freight[$v['goods_id']] = $val['freight']; //获取不同商品的运费
}
}
} //相同商品不同属性只收取一次运费
foreach ( $goods_freight as $value ){
$freight += $value;
}
if ($type == 0){
return $totalPrice+$freight; //总价=商品总价+商品总运费
}else{
return ['total_price'=>$totalPrice,'freight'=>$freight]; //商品总价与商品总运费
}
} //编辑某商品数量
public function edit($id, $attr_id, $number)
{
if (!empty($id) && $this->isExist($id, $attr_id) && $number > 0) {
$cache_detail = $this->basket;
foreach ($cache_detail as $key => $val) {
if ($val['goods_id'] == $id && $val['attr_id'] == $attr_id) {
$val['goods_number'] = intval($number);
$val['subtotal'] = $val['goods_number'] * $val['price'];
$this->basket[$key] = $val;
return $this->redis->setex($this->cachekey, $this->expire, json_encode($this->basket));
}
}
}
} }

ThinkPHP5+Redis单例型购物车的更多相关文章

  1. Redis 单例、主从模式、sentinel 以及集群的配置方式及优缺点对比(转)

    摘要: redis作为一种NoSql数据库,其提供了一种高效的缓存方案,本文则主要对其单例,主从模式,sentinel以及集群的配置方式进行说明,对比其优缺点,阐述redis作为一种缓存框架的高可用性 ...

  2. Redis单例、主从模式、sentinel以及集群的配置方式及优缺点对比

    https://my.oschina.net/zhangxufeng/blog/905611

  3. php单例型(singleton pattern)

    搞定,吃饭 <?php /* The purpose of singleton pattern is to restrict instantiation of class to a single ...

  4. spring bean单例注入与用单例模式通过class.getinstance()区别?

    1.action的某个方法中,用以下代码获得redis单例实例 RedisDelegate redisDelegate = RedisDelegate.getInstance(); redisDele ...

  5. 初探Java设计模式1:创建型模式(工厂,单例等)

    Java 设计模式 一直想写一篇介绍设计模式的文章,让读者可以很快看完,而且一看就懂,看懂就会用,同时不会将各个模式搞混.自认为本文还是写得不错的,花了不少心思来写这文章和做图,力求让读者真的能看着简 ...

  6. Spring + Jedis集成Redis(单例redis数据库)

    这几天没事,就把之前学习的redis代码整理一遍,废话不多说,上步骤. 1.pom.xml引入资源: <dependency> <groupId>org.springframe ...

  7. 002-创建型-03-单例模式(Singleton)【7种】、spring单例及原理

    一.概述 保证一个类仅有一个实例,并提供一个全局访问点 私有构造器.线程安全.延迟加载.序列化和反序列化安全.反射攻击 1.1.适用场景 1.在多个线程之间,比如servlet环境,共享同一个资源或者 ...

  8. ios oc 和 swfit 用dispatch_once 创建单例

    网上已经有方法了,我这里就是抄了下,原文链接 http://bj007.blog.51cto.com/1701577/649413 http://blog.csdn.net/u010124617/ar ...

  9. php 设计模式 - 单例

    概述: 作为对象的创建模式,单例确保某一个内在系统中只存在一个实例,它不可以创建副本. 克隆函数(__clone )以及构造函数(__construct )必须声明为私用, 防止外部程序 创建一个新类 ...

随机推荐

  1. 修复wordpress插件编辑器漏洞

    具体方法,将下面的代码添加到您的配置文件 wp-config.php中: define( 'DISALLOW_FILE_EDIT', true ); 以此关闭插件编辑器功能,一切就这么简单,漏洞也就不 ...

  2. 整理Py小demo

    from email.mime.text import MIMEText # 第一个参数就是邮件正文,第二个参数是MIME的subtype, # 传入'plain'表示纯文本,最终的MIME就是'te ...

  3. 移植开源QT软件-SameGame

    前言: QML是一种描述性的脚本语言,文件格式以.qml结尾.语法格式非常像CSS(参考后文具体例子),但又支持javascript形式的编程控制.我个人认为它结合了QtDesigner UI和QtS ...

  4. 图像压缩Vs.压缩感知

    压缩感知科普文两则: 原文链接:http://www.cvchina.info/2010/06/08/compressed-sensing-2/ 这几天由于happyharry的辛勤劳动,大伙纷纷表示 ...

  5. 编写可维护的javascript阅读笔记

    格式 变量 变量命名, 采取小驼峰大小写 变量使用名词, 函数前缀为动词 局部变量应统一定义在函数的最上面, 而不是散落在函数的任意角落. 赋初始值的定义在未赋初始值的变量的上面. 我个人建议不使用单 ...

  6. ReactiveX Operators

    This documentation groups information about the various operators and examples of their usage into t ...

  7. Spring依赖注入:@Autowired,@Resource和@Inject区别与实现原理

    一.spring依赖注入使用方式 @Autowired是spring框架提供的实现依赖注入的注解,主要支持在set方法,field,构造函数中完成bean注入,注入方式为通过类型查找bean,即byT ...

  8. POI操作Excel的三种Workbook的发展和区别

    POI的一些使用方法: 创建流程:(上级为下级的载体) 1.创建Workbook(工作薄): 2.创建Sheet(表单,可以创建多个): 3.创建Row(行): 4.创建Cell(单元格) 接下来分别 ...

  9. 路飞学城Python-Day53

    01-jquery的介绍 JS在做项目或者是实现功能的时候,用JS去操作DOM元素非常复杂,代码量大,重复性代码也多 多个元素使用for循环遍历也是非常麻烦的,对于JS使用来说加大了难度 jQuery ...

  10. BZOJ 3878 [AHOI&JSOI2014]奇怪的计算器 (线段树)

    题面:BZOJ传送门 洛谷传送门 线段树好题 题目保证$a$一定是正整数,容易发现计算结果是单调的 我们把询问离线,并按照从小到大排序 某次操作可能导致某些位置达到边界$L/R$ 根据单调性的结论 这 ...