<?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. [Offer收割]编程练习赛32

    气泡图 两两判断关系,dfs. #include<stdio.h> #include<string.h> #include<stdlib.h> #include&l ...

  2. Android 关于Toolbar和FragmentActivity的问题

    今天在工作中遇到用Fragment搭Tab框架时,FragmentActivity无法使用Toolbar的问题.查了许多资料,其实AppComponent继承自FragmentActivity,所以A ...

  3. 六星经典CSAPP笔记系列 - 作者:西代零零发

    六星经典CSAPP笔记(1)计算机系统巡游 六星经典CSAPP笔记(2)信息的操作和表示 六星经典CSAPP-笔记(3)程序的机器级表示

  4. (转)Bootstrap 之 Metronic 模板的学习之路 - (6)自定义和扩展

    https://segmentfault.com/a/1190000006815041 前面我们将 Metronic 的结构和源码大致浏览了一遍,Metronic 整个文件包有三百多兆,在实际项目中, ...

  5. MySQL_pymysql模块

    安装:pip install pymysql 基本操作 import pymysql conn=pymysql.connect(host=',database='lary',charset='utf8 ...

  6. day05_20190127_python之路——常用模块

    什么是模块? 常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀.模块的本质:就是封装了很多很多函数.功能的一个文件 但其实import加载的模块分为四 ...

  7. Steamroller FreeCodeCamp

    function steamroller(arr) { // I'm a steamroller, baby var resultArr = []; for(var i = 0; i < arr ...

  8. windows 端口号占用和解决方法

    https://blog.csdn.net/qq_39657909/article/details/80378983

  9. linux内核内存分配(一、基本概念)

    内存分配是Linux比较复杂也是比较重要的部分,这个和ssd驱动很类似:物理地址和虚拟地址的映射关系.下面总结下最近看到的有关内存分配的内容和自己的理解: 1.一致内存访问和非一致内存访问 上图来自& ...

  10. Linux中的gpio口使用方法

    Linux中的IO使用方法 应该是新版本内核才有的方法.请参考:./Documentation/gpio.txt文件 提供的API:驱动需要包含 #include <linux/gpio.h&g ...