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

Laravel:将含子对象数组的JSON解析为带OrderItem实例的Order模型

问题描述

我在Laravel应用中收到以下格式的JSON数据:

{
  "name": "order 1",
  "customer": "cus123",
  "orderItems": [
    {
      "amount": 1,
      "name": "cola",
      "price": "2.10"
    },
    {
      "amount": 3,
      "name": "fanta",
      "price": "2.00"
    }
  ]
}

我已经创建了Order和OrderItem两个模型,希望将该JSON解析为Order实例$order。目前在OrderController中通过以下代码实现基础解析:

class OrderController extends Controller
{
  public function store(Request $request) {
    $order = new Order();
    $order->forceFill($request->toArray());
  }
}

现在可以访问$order->name、$order->customer等属性,但$order->orderItems返回的是普通数组而非OrderItem实例数组。尝试在Order模型中配置$casts未成功,请问如何实现$order->orderItems返回OrderItem实例数组?

解决方案

方法一:利用Eloquent关联关系+批量创建

这是Laravel中处理关联模型的标准方式,适合需要将数据持久化到数据库的场景:

1. 配置模型关联

在Order模型中定义一对多关联:

class Order extends Model
{
    // 其他模型代码...

    public function orderItems()
    {
        return $this->hasMany(OrderItem::class);
    }
}

在OrderItem模型中定义反向关联(可选,但推荐):

class OrderItem extends Model
{
    // 其他模型代码...

    public function order()
    {
        return $this->belongsTo(Order::class);
    }
}

2. 修改控制器逻辑

先保存主订单,再批量创建关联的OrderItem实例:

class OrderController extends Controller
{
    public function store(Request $request) {
        // 创建并保存主订单,排除orderItems字段
        $order = Order::create($request->except('orderItems'));

        // 将请求中的orderItems数组转换为OrderItem实例集合
        $orderItems = collect($request->input('orderItems'))->map(function ($item) {
            // 转换price为数值类型(适配数据库decimal字段)
            $item['price'] = (float)$item['price'];
            return new OrderItem($item);
        });

        // 批量保存关联的订单商品
        $order->orderItems()->saveMany($orderItems);

        // 加载关联后,$order->orderItems即为OrderItem实例数组
        return $order->load('orderItems');
    }
}

方法二:自定义模型转换(Cast)

如果不需要立即持久化数据,只是想将数组转为OrderItem实例数组,可以自定义Cast类:

1. 创建自定义Cast类

在app/Casts目录下创建OrderItemsCast.php(目录不存在则手动创建):

namespace App\Casts;

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use App\Models\OrderItem;

class OrderItemsCast implements CastsAttributes
{
    public function get($model, $key, $value, $attributes)
    {
        if (is_null($value)) {
            return [];
        }

        // 将JSON字符串或数组转换为OrderItem实例数组
        $items = is_string($value) ? json_decode($value, true) : $value;

        return collect($items)->map(function ($item) {
            if (isset($item['price'])) {
                $item['price'] = (float)$item['price'];
            }
            return new OrderItem($item);
        })->all();
    }

    public function set($model, $key, $value, $attributes)
    {
        // 保存时将OrderItem实例数组转为JSON字符串
        if (is_array($value) && !empty($value) && $value[0] instanceof OrderItem) {
            $value = collect($value)->map(fn($item) => $item->toArray())->all();
        }

        return json_encode($value);
    }
}

2. 在Order模型中配置Cast

class Order extends Model
{
    protected $casts = [
        'orderItems' => \App\Casts\OrderItemsCast::class,
    ];

    // 其他模型代码...
}

3. 控制器中直接使用

此时forceFill后$order->orderItems就是OrderItem实例数组:

class OrderController extends Controller
{
    public function store(Request $request) {
        $order = new Order();
        $order->forceFill($request->toArray());

        // 此时$order->orderItems为OrderItem实例数组
        dd($order->orderItems);
    }
}

注意:使用自定义Cast时,若要保存orderItems到数据库,需确保orders表中有order_items字段(类型为JSON或JSONB)。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 13:46:04