You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Resource API按关联模型分组结果的实现方案

解决方案:将Barcode按关联Product分组返回

当然可以实现这个分组需求!下面给你两种实用的方案,都是基于Laravel的特性来实现的,你可以根据自己的项目情况选择:

方案一:控制器内直接用集合处理(快速实现)

这种方法适合快速调整输出格式,不需要额外创建资源文件:

// 控制器代码调整
$outlet = Outlet::where('slug', $slug)->with(['barcodes.product', 'damages', 'images'])->firstOrFail();

// 把barcodes按关联的product.id分组
$groupedBarcodes = $outlet->barcodes->groupBy('product.id');

// 构建目标格式的products数组
$formattedProducts = $groupedBarcodes->map(function ($barcodesGroup) {
    // 取分组内第一个barcode关联的Product作为基础数据
    $product = $barcodesGroup->first()->product;
    // 给Product添加barcodes字段,同时去掉barcode里的product关联避免冗余
    $product->barcodes = $barcodesGroup->map(function ($barcode) {
        return $barcode->makeHidden(['product']);
    });
    return $product;
});

// 替换outlet原有的products属性
$outlet->products = $formattedProducts;

// 返回响应
return response()->json([
    'data' => $outlet,
    'message' => 'Outlet retrieved successfully.'
]);

代码说明:

  • 用groupBy('product.id')把属于同一个Product的Barcode聚到一起
  • 遍历每个分组,基于分组内的Product模型构建新的对象,并注入对应的Barcodes集合
  • 用makeHidden隐藏Barcode里的product关联,避免返回重复的Product数据

方案二:使用Laravel API Resource(优雅且易维护)

如果你的API需要长期维护或者有多个类似的格式化需求,推荐用Laravel的API Resource来实现,这也是Laravel官方推荐的API输出格式化方式:

步骤1:创建BarcodeResource

// app/Http/Resources/BarcodeResource.php
namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class BarcodeResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'sku' => $this->sku,
            'serial_number' => $this->serial_number,
            'price' => $this->price,
            'discount' => $this->discount,
        ];
    }
}

步骤2:创建ProductResource

// app/Http/Resources/ProductResource.php
namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class ProductResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'slug' => $this->slug,
            'stock' => $this->stock,
            'cover' => $this->cover,
            'description' => $this->description,
            'sku' => $this->sku,
            'price' => $this->price,
            'discount' => $this->discount,
            'barcodes' => BarcodeResource::collection($this->whenLoaded('barcodes')),
        ];
    }
}

步骤3:创建OutletResource

// app/Http/Resources/OutletResource.php
namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class OutletResource extends JsonResource
{
    public function toArray($request)
    {
        // 按product.id分组barcodes
        $groupedBarcodes = $this->barcodes->groupBy('product.id');
        
        // 构建带barcodes的Product集合
        $formattedProducts = $groupedBarcodes->map(function ($barcodesGroup) {
            $product = $barcodesGroup->first()->product;
            // 手动给Product设置barcodes关联,避免重复查询数据库
            $product->setRelation('barcodes', $barcodesGroup);
            return new ProductResource($product);
        });

        return [
            'id' => $this->id,
            'name' => $this->name,
            'slug' => $this->slug,
            'address' => $this->address,
            'cover' => $this->cover,
            'phone' => $this->phone,
            'products' => $formattedProducts,
            'damages' => $this->damages, // 若需要格式化可创建对应Resource
            'images' => $this->images,   // 同理
        ];
    }
}

步骤4:控制器返回Resource

// 控制器代码
$outlet = Outlet::where('slug', $slug)->with(['barcodes.product', 'damages', 'images'])->firstOrFail();

return response()->json([
    'data' => new OutletResource($outlet),
    'message' => 'Outlet retrieved successfully.'
]);

方案优势:

  • 格式集中管理,后续修改输出字段只需要修改对应的Resource文件
  • 遵循Laravel API开发最佳实践,代码更整洁易维护
  • 支持条件加载(whenLoaded),避免不必要的数据输出

内容的提问来源于stack exchange,提问作者mafortis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 12:07:48