多店铺电商平台商品图片批量上传实现方案咨询
多店铺电商中台:商品图片批量同步至分类绑定店铺的实现方案
一、获取分类绑定的店铺列表
首先确保模型关联配置正确:
- 在
Category模型中定义与店铺的多对多关联:
public function shops() { return $this->belongsToMany(Shop::class, 'category_shop', 'category_id', 'shop_id'); }
- 创建商品时,通过关联的分类获取绑定店铺:
// 从请求中拿到分类ID,查询对应分类及绑定店铺 $category = Category::find($request->category_id); // 提取店铺的FTP配置信息(需在店铺表中提前配置ftp_host、ftp_username等字段) $shops = $category->shops()->select('id', 'ftp_host', 'ftp_username', 'ftp_password', 'ftp_image_path')->get();
二、改造上传逻辑,实现多店铺批量FTP上传
基于你现有的本地上传代码,重构为支持多目标FTP上传的版本:
1. 新增动态构建FTP磁盘的方法
替换原单一本地磁盘方法,新增适配不同店铺FTP配置的动态构建方法:
/** * 动态生成FTP存储磁盘实例 * @param array $ftpConfig 店铺FTP配置 * @return \Illuminate\Filesystem\FilesystemAdapter */ private function buildFtpDisk(array $ftpConfig) { return Storage::build([ 'driver' => 'ftp', 'host' => $ftpConfig['ftp_host'], 'username' => $ftpConfig['ftp_username'], 'password' => $ftpConfig['ftp_password'], 'root' => $ftpConfig['ftp_image_path'], // 对应店铺的images目录绝对路径 'passive' => true, // 多数服务器需开启被动模式 'ssl' => false, // 根据店铺服务器配置调整 'timeout' => 30, ]); }
2. 重构批量上传方法
整合原有上传逻辑,实现同时上传至本地和所有绑定店铺:
/** * 批量上传商品图片至分类绑定的所有店铺 * @param Request $request * @param int $product_id * @param int $category_id * @return array 各店铺上传结果 */ private function batchUploadProductImage(Request $request, $product_id, $category_id) { $image = $request->file('image'); $name = pathinfo($image->getClientOriginalName(), PATHINFO_FILENAME); $extension = $image->getClientOriginalExtension(); $imageContent = file_get_contents($image); // 中台本地存储路径(可选:保留本地备份) $localPath = config('ecommerce.product_upload_dir').'/'.Str::slug($product_id, '-'); $localImagePath = $localPath.'/'.$name.'.'.$extension; // 获取分类绑定的店铺列表 $category = Category::find($category_id); $shops = $category->shops()->select('id', 'ftp_host', 'ftp_username', 'ftp_password', 'ftp_image_path', 'domain')->get(); $uploadResults = []; // 先处理本地存储(复用原有逻辑) if (!$this->_imageExistOnStorage($localImagePath)) { $this->ecommercePublicDisk()->put($localImagePath, $imageContent); } else { $this->_renameMainProductImageOnStorage($request, $product_id); $localImagePath = $this->_uploadProductImage($request, $product_id, true); } // 循环上传至每个店铺的FTP服务器 foreach ($shops as $shop) { try { $ftpDisk = $this->buildFtpDisk($shop->toArray()); // 店铺端的图片存储路径(可根据需求调整结构) $shopImagePath = Str::slug($product_id, '-').'/'.$name.'.'.$extension; // 检查店铺端是否存在同名图片,存在则重命名 if ($ftpDisk->exists($shopImagePath)) { $newName = $name.'_'.time().'.'.$extension; $shopImagePath = Str::slug($product_id, '-').'/'.$newName; } $ftpDisk->put($shopImagePath, $imageContent); $uploadResults[$shop->id] = [ 'shop_domain' => $shop->domain, 'upload_path' => $ftpDisk->path($shopImagePath), 'status' => 'success' ]; } catch (\Exception $e) { $uploadResults[$shop->id] = [ 'shop_domain' => $shop->domain, 'error' => $e->getMessage(), 'status' => 'failed' ]; // 记录上传失败日志,便于后续排查或重试 \Log::error("图片上传至店铺{$shop->id}失败:".$e->getMessage()); } } return $uploadResults; }
3. 保留原本地磁盘方法(用于本地备份)
public function ecommercePublicDisk() { return Storage::build([ 'driver' => 'local', 'root' => public_path('/') ]); }
三、关键优化点
- FTP配置管理:在店铺表中新增FTP相关字段,允许中台后台为每个店铺单独配置FTP信息。
- 异步上传:若店铺数量较多,建议将上传逻辑放入Laravel队列异步处理,避免阻塞接口响应。
- 重试机制:针对FTP上传失败的情况,增加重试逻辑(如队列重试3次),保证最终上传成功率。
- 文件名唯一:复用你现有重命名逻辑,或通过追加时间戳/随机串,避免不同商品图片重名覆盖。
内容的提问来源于stack exchange,提问作者Ivan
相关产品推荐
相关产品推荐

