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

Laravel Accessor设置问题:JSON字段运费乘除100不生效

问题原因及解决方案

你的代码不生效核心有两个问题:

1. 错误直接从$attributes获取子键

$attributes数组存储的是数据库列的原始值,键是数据库列名(此处为shippingcosts),而非JSON列内部的Small/Large子键。你直接调用$attributes['Small']会返回null,导致访问器逻辑完全失效。

2. 类型转换与自定义访问器的冲突

你同时设置了shippingcosts => 'collection'的类型转换和自定义Attribute访问器,Laravel会优先将JSON列转为Collection实例,再传入访问器的get方法,但你的代码没有正确处理这个转换后的值,反而错误地去$attributes中查找不存在的子键。


修正后的代码方案

方案一:移除类型转换,让访问器全权处理

删除模型中$casts里的shippingcosts配置,修改访问器如下:

protected function shippingcosts(): Attribute
{
    return Attribute::make(
        get: fn ($value) => [
            'Small' => isset($value['Small']) && is_numeric($value['Small']) ? ($value['Small'] / 100) : 0,
            'Large' => isset($value['Large']) && is_numeric($value['Large']) ? ($value['Large'] / 100) : 0,
            'BulkSizeForLarge' => $value['BulkSizeForLarge'] ?? null,
        ],
        set: fn ($value) => [
            // 用round避免浮点数精度问题,再转为整数
            'Small' => isset($value['Small']) && is_numeric($value['Small']) ? (int)round($value['Small'] * 100) : 0,
            'Large' => isset($value['Large']) && is_numeric($value['Large']) ? (int)round($value['Large'] * 100) : 0,
            'BulkSizeForLarge' => $value['BulkSizeForLarge'] ?? null,
        ],
    );
}

方案二:保留类型转换,适配转换后的值

如果需要保留collection类型转换,访问器需先将Collection实例转为数组再处理:

protected function shippingcosts(): Attribute
{
    return Attribute::make(
        get: function ($value) {
            $data = $value->toArray();
            return [
                'Small' => isset($data['Small']) && is_numeric($data['Small']) ? ($data['Small'] / 100) : 0,
                'Large' => isset($data['Large']) && is_numeric($data['Large']) ? ($data['Large'] / 100) : 0,
                'BulkSizeForLarge' => $data['BulkSizeForLarge'] ?? null,
            ];
        },
        set: function ($value) {
            // 兼容传入的数组或Collection实例
            $inputData = is_object($value) ? $value->toArray() : $value;
            return [
                'Small' => isset($inputData['Small']) && is_numeric($inputData['Small']) ? (int)round($inputData['Small'] * 100) : 0,
                'Large' => isset($inputData['Large']) && is_numeric($inputData['Large']) ? (int)round($inputData['Large'] * 100) : 0,
                'BulkSizeForLarge' => $inputData['BulkSizeForLarge'] ?? null,
            ];
        },
    );
}

额外注意事项

  • 存入时用round处理后再转int,避免浮点数运算精度问题(比如2.99 * 100可能得到298.99999999999994,直接转int会丢失精度)。
  • 访问器返回的数组,Laravel会自动序列化为JSON存入数据库(因列类型为JSON),无需手动调用json_encode。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 22:48:53