You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
yanzong/app/common/library/collector/provider/driver/Alibaba.php

245 lines
8.1 KiB

11 months ago
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\common\library\collector\provider\driver;
use app\common\enum\goods\SpecType as GoodsSpecTypeEnum;
use app\common\library\helper;
use app\common\library\collector\provider\Driver;
use cores\exception\BaseException;
/**
* 阿里巴巴商品采集驱动
* Class Alibaba
* @package app\common\library\collector\provider\driver
*/
class Alibaba extends Driver
{
// API地址
const API_URL = 'https://api09.99api.com/alibaba/detail';
/**
* 获取商品详情
* @param string $itemId
* @return array
* @throws BaseException
*/
public function detail(string $itemId): array
{
$result = $this->curlGet(self::API_URL, $itemId);
return $this->formatGoods($result['data']);
}
/**
* 格式化商品数据
* @param array $original
* @return array
*/
private function formatGoods(array $original): array
{
$data = [];
// 商品规格
$data['spec_type'] = !empty($original['skuMap']) ? GoodsSpecTypeEnum::MULTI : GoodsSpecTypeEnum::SINGLE;
$data['goods_name'] = $original['title'];
$data['goodsImages'] = $this->goodsImages($original['images']);
$data['content'] = $this->goodsContent($original['descImgs']);
$price = \current($original['showPriceRanges'])['price'] ?? '0.00';
// 整理多规格数据
if ($data['spec_type'] === GoodsSpecTypeEnum::MULTI) {
$specList = $this->createSpecList($original['skuProps']);
$data['specData']['specList'] = $specList;
$data['specData']['skuList'] = $this->createSkuList($original['skuMap'], $specList, $price, $original['skuProps']);
} elseif ($data['spec_type'] === GoodsSpecTypeEnum::SINGLE) {
$data['goods_price'] = $price;
$data['line_price'] = '0.00';
$data['stock_num'] = 100; // 库存数量 (单规格商品没有库存数量 默认100)
$data['goods_weight'] = 1; // 重量默认1kg
}
return $data;
}
/**
* 创建标准的商品SKU数据
* @param array $originalSkuList 商品SKU列表
* @param array $specList 商品规格
* @param string $defaultPrice 默认价格
* @param array $skuProps 规格信息 (用于获取缩略图)
* @return array
*/
private function createSkuList(array $originalSkuList, array $specList, string $defaultPrice, array $skuProps): array
{
// 根据规格数据生成完整的SKU数据 (因为originalSkuList会有不存在的sku)
$cartesian = $this->cartesian($specList);
// 整理商品SKU列表
$skuList = [];
foreach ($cartesian as $spec) {
// 设置skuKeys数据
$skuKeys = [];
foreach ($spec as $specValue) {
$skuKeys[] = [
'groupKey' => $specValue['groupKey'],
'valueKey' => $specValue['key']
];
}
// 查找已存在的SKU
$originalSku = $this->findOriginalSku($originalSkuList, $spec);
// 整理SKU数据
$skuList[] = [
'image_id' => 0,
'goods_price' => $originalSku['price'] ?? $defaultPrice,
'line_price' => '0.00',
'stock_num' => $originalSku ? $originalSku['canBookCount'] : 0, // 库存数量
'goods_weight' => 1, // 重量默认1kg
'goods_sku_no' => $originalSku ? $originalSku['skuId'] : '',
'skuKeys' => $skuKeys,
'imageUrl' => $this->findClothesColor($skuProps, $spec),
];
}
return $skuList;
}
/**
* 查找SKU封面图
* @param array $skuProps 规格信息
* @param array $spec
* @return string
*/
private function findClothesColor(array $skuProps, array $spec): string
{
foreach ($spec as $skuValue) {
if ($skuValue['groupKey'] != 0) {
continue;
}
foreach ($skuProps as $prop) {
foreach ($prop['value'] as $value) {
if ($skuValue['spec_value'] === $value['name'] && !empty($value['imageUrl'])) {
return $this->imageUrl($value['imageUrl'], '_800x800.jpg');
}
}
}
}
return '';
}
/**
* 查找已存在的SKU
* @param array $originalSkuList
* @param array $spec
* @return false|mixed
*/
private function findOriginalSku(array $originalSkuList, array $spec)
{
foreach ($originalSkuList as $key => $item) {
$skuKey = implode('&gt;', helper::getArrayColumn($spec, 'spec_value'));
if ($skuKey === $key) {
return $item;
}
}
return false;
}
/**
* 生成完整的SKU列表(笛卡尔积运算)
* @param array $specList
* @param array $tmp
* @param array $nArr
* @return int
*/
private function cartesian(array $specList, array $tmp = [], array $nArr = [])
{
foreach (array_shift($specList)['valueList'] as $v) {
$tmp[] = $v;
if ($specList) {
$nArr = $this->cartesian($specList, $tmp, $nArr);
} else {
$nArr[] = $tmp;
}
array_pop($tmp);
}
return $nArr;
}
/**
* 创建标准的商品规格数据(树状)
* @param array $skuProps 规格信息
* @return array
*/
private function createSpecList(array $skuProps): array
{
$specList = [];
foreach ($skuProps as $prop) {
$groupKey = \count($specList);
$valueList = [];
foreach ($prop['value'] as $value) {
$valueList[] = [
'key' => \count($valueList),
'groupKey' => $groupKey,
'spec_value' => $value['name'],
];
}
$specList[] = [
'key' => $groupKey,
'spec_name' => $prop['prop'],
'valueList' => $valueList,
];
}
return $specList;
}
/**
* 格式化商品主图
* @param array $images
* @return array
*/
private function goodsImages(array $images): array
{
return array_map(function (string $imageUrl) {
return $this->imageUrl($imageUrl, '_800x800.jpg');
}, \array_slice($images, 0, 10));
}
/**
* 格式化图片url
* @param string $url 图片url
* @param string $suffix 后缀 (目的是格式化图片尺寸和压缩文件体积)
* @return string
*/
private function imageUrl(string $url, string $suffix = ''): string
{
if (empty($url)) {
return '';
}
// 补全url协议
if (\substr($url, 0, 2) === '//') {
return "https:{$url}{$suffix}";
}
if (\substr($url, 0, 4) != 'http') {
return "https://{$url}{$suffix}";
}
// http替换为https
return str_replace('http://', 'https://', $url) . $suffix;
}
/**
* 格式化商品详情
* @param array $descImgs
* @return string
*/
private function goodsContent(array $descImgs): string
{
$content = '';
foreach ($descImgs as $img) {
$content .= "<p><img src=\"{$img}\"/></p>";
}
return $content;
}
}