Files

381 lines
9.9 KiB
PHP

<?php
namespace app\common\service\app\physical;
use app\admin\model\app\physical\Goods;
use app\admin\model\app\physical\Category;
use think\Db;
/**
* 商品服务类
*/
class GoodsService
{
protected $query = null;
protected $order = [];
protected $md5s = [];
protected $format = null;
public function __construct(\Closure $format = null, \think\db\Query $query = null)
{
$this->query = $query ?: new Goods();
$this->format = $format;
}
/**
* with 关联
*
* @param mixed $with
* @return self
*/
public function with($with)
{
$this->query->with($with);
return $this;
}
/**
* 查询上架的商品,包含隐藏商品
*
* @return self
*/
public function show()
{
$this->md5s[] = 'show';
$this->query = $this->query->whereIn('status', [1]);
return $this;
}
/**
* 查询上架的商品,不包含隐藏商品
*
* @return self
*/
public function up()
{
$this->md5s[] = 'up';
$this->query = $this->query->where('status', 1);
return $this;
}
/**
* 查询库存大于0的商品
*
* @return self
*/
public function inStock()
{
$this->md5s[] = 'inStock';
$this->query = $this->query->where('stock', '>', 0);
return $this;
}
/**
* 搜索商品
*
* @param string $keyword
* @return self
*/
public function search($keyword)
{
$keyword = is_string($keyword) ? $keyword : json_encode($keyword);
$this->md5s[] = 'search:' . $keyword;
$this->query = $this->query->where('name', 'like', '%' . $keyword . '%');
return $this;
}
/**
* 根据 ids 获取商品
*
* @param string|array $ids ids 数组或者 , 隔开的字符串
* @return self
*/
public function whereIds($ids = '')
{
$ids = array_map('intval', is_array($ids) ? $ids : explode(',', $ids));
$this->md5s[] = 'ids:' . implode(',', $ids);
if (!empty($ids)) {
$this->query = $this->query->orderRaw('field(id, ' . implode(',', $ids) . ')');
$this->query = $this->query->whereIn('id', $ids);
}
return $this;
}
/**
* 根据商品分类获取商品
*
* @param integer $category_id
* @param boolean $is_category_deep 是否深度搜索子分类
* @return self
*/
public function category($category_id, $is_category_deep = true)
{
$category_id = intval($category_id);
$this->md5s[] = 'category_id:' . $category_id;
$category_ids = [];
if (isset($category_id) && $category_id != 0) {
if ($is_category_deep) {
// 查询分类所有子分类,包括自己
$category_ids = $this->getChildIds($category_id);
} else {
$category_ids = [$category_id];
}
}
$this->query->where(function ($query) use ($category_ids) {
// 所有子分类使用 find_in_set or 匹配
foreach ($category_ids as $key => $category_id) {
$query->whereOrRaw("find_in_set($category_id, category_id)");
}
});
return $this;
}
/**
* 获取分类及其所有子分类ID
*
* @param int $categoryId
* @return array
*/
protected function getChildIds($categoryId)
{
$categoryIds = [$categoryId];
$this->getChildCategoryIds($categoryId, $categoryIds);
return $categoryIds;
}
/**
* 递归获取子分类ID
*
* @param int $parentId
* @param array $categoryIds
*/
protected function getChildCategoryIds($parentId, &$categoryIds)
{
$children = Category::where('parent_id', $parentId)
->where('status', 1)
->where('uniacid', UNIACID)
->column('id');
foreach ($children as $childId) {
$categoryIds[] = $childId;
$this->getChildCategoryIds($childId, $categoryIds);
}
}
/**
* 排序,方法参数同 thinkphp order 方法
*
* @param string $sort
* @param string $order
* @return self
*/
public function order($sort = 'weigh', $order = 'desc')
{
$sort = $sort == 'price' ? Db::raw('convert(`price`, DECIMAL(10, 2)) ' . $order) : $sort;
$this->query->order($sort, $order);
return $this;
}
/**
* 获取商品列表
*
* @param bool $is_cache 是否缓存
* @return array|\think\model\Collection
*/
public function select($is_cache = false)
{
$this->md5s[] = 'select';
// 默认排序
$this->order();
$goods = $this->query->select();
// 格式化数据
foreach ($goods as $key => $gd) {
$gd = $this->defaultFormat($gd);
if ($this->format instanceof \Closure) {
$gd = ($this->format)($gd, $this);
}
$goods[$key] = $gd;
}
return $goods;
}
/**
* 获取商品列表(分页)
*
* @param bool $is_cache 是否缓存
* @return \think\Paginator
*/
public function paginate($is_cache = false)
{
$this->md5s[] = 'paginate';
// 默认排序
$this->order();
$goods = $this->query->paginate(request()->param('list_rows', 10));
// 格式化数据
$goods->each(function ($god) {
$god = $this->defaultFormat($god);
if ($this->format instanceof \Closure) {
($this->format)($god, $this);
}
});
return $goods;
}
/**
* 获取单个商品
*
* @param bool $is_cache
* @return Goods
*/
public function find($is_cache = false)
{
$this->md5s[] = 'find';
$goods = $this->query->find();
if ($goods && $this->format instanceof \Closure) {
// 格式化数据
$goods = $this->defaultFormat($goods);
($this->format)($goods, $this);
}
return $goods;
}
/**
* 获取单个商品,找不到抛出异常
*
* @param bool $is_cache
* @return Goods
*/
public function findOrFail($is_cache = false)
{
$this->md5s[] = 'find';
$goods = $this->query->find();
if (!$goods) {
throw new \Exception('商品不存在');
}
if ($this->format instanceof \Closure) {
// 格式化数据
$goods = $this->defaultFormat($goods);
($this->format)($goods, $this);
}
return $goods;
}
/**
* 默认格式化数据
*
* @param array|object $goods
* @return array
*/
public function defaultFormat($goods)
{
// 获取配置
$physicalConfig = \app\common\model\app\Config::getConfig('physical');
$showSales = $physicalConfig['show_sales'] ?? 1;
// 处理图片
if (isset($goods['carousel']) && is_string($goods['carousel'])) {
$goods['carousel'] = json_decode($goods['carousel'], true) ?: [];
}
// 处理分类ID
if (isset($goods['category_id']) && is_string($goods['category_id'])) {
$goods['category_id'] = array_map('intval', explode(',', $goods['category_id']));
}
// 处理参数
if (isset($goods['params']) && is_string($goods['params'])) {
$goods['params'] = json_decode($goods['params'], true) ?: [];
}
// 根据配置决定是否显示销量
if ($showSales != 1) {
unset($goods['total_sales']);
}
// 获取最低价格、库存和销量
if (isset($goods['id'])) {
$goodsId = $goods['id'];
// 优先使用商品表中的 price 字段
if (isset($goods['price']) && $goods['price'] > 0) {
$goods['price'] = floatval($goods['price']);
} else {
// 如果商品表中没有价格,则从 SKU 价格表中计算
$skuPrices = \app\admin\model\app\physical\SkuPrice::where('goods_id', $goodsId)
->where('uniacid', UNIACID)
->where('status', 1)
->select();
if ($skuPrices) {
if (is_array($skuPrices)) {
$skuPricesArray = $skuPrices;
} else {
$skuPricesArray = $skuPrices->toArray();
}
$goods['price'] = min(array_column($skuPricesArray, 'price'));
} else {
$goods['price'] = 0;
}
}
// 计算库存和销量
$skuPrices = \app\admin\model\app\physical\SkuPrice::where('goods_id', $goodsId)
->where('uniacid', UNIACID)
->where('status', 1)
->select();
if ($skuPrices) {
if (is_array($skuPrices)) {
$skuPricesArray = $skuPrices;
} else {
$skuPricesArray = $skuPrices->toArray();
}
$goods['stock'] = array_sum(array_column($skuPricesArray, 'stock'));
// 根据配置决定是否显示销量
if ($showSales != 1) {
unset($goods['sales']);
}
} else {
$goods['stock'] = 0;
$goods['sales'] = 0;
}
}
return $goods;
}
/**
* 默认调用 query 中的方法,比如 withTrashed()
*
* @param string $funcname
* @param array $arguments
* @return self
*/
public function __call($funcname, $arguments)
{
$this->query->{$funcname}(...$arguments);
return $this;
}
}