Laravel中怎么处理Json数据_Laravel 模型字段Json转换【技巧】

2次阅读

laravel 的 json 类型字段通过 $casts 自动序列化/反序列化,需确保数据库使用 utf8mb4;迁移用 $table->json(),查询嵌套值推荐 wherejsoncontains();自定义访问器/修改器可增强控制但会覆盖 cast;务必验证前端 json 输入并确认生产环境数据库 json 支持级别。

Laravel中怎么处理Json数据_Laravel 模型字段Json转换【技巧】

模型字段声明为 json 类型后,laravel 自动处理序列化和反序列化

只要在模型的 $casts 数组里把字段设为 'meta' => 'json',Laravel 就会在写入数据库前自动 json_encode(),读取时自动 json_decode() 成 PHP 数组或对象。不用手动调用 json_encode() 或检查 is_String()

常见错误现象:SQLSTATE[HY000]: General Error: 1366 Incorrect string value —— 这通常是因为数据库字段没设成 utf8mb4,导致 emoji 或某些 Unicode 字符存不进去。

  • 确保 mysql 表字符集是 utf8mb4,排序规则是 utf8mb4_unicode_ci
  • 迁移中用 $table->json('meta')(Laravel 5.2+),它会自动建 JSON 类型字段(MySQL 5.7+)或 TEXT(低版本)
  • 如果用的是旧版 MySQL,json cast 仍可用,但底层是 TEXT,Laravel 会自行处理编解码

json 字段查询时不能直接用 where() 查嵌套值

比如 User::where('meta->theme', 'dark') 看起来能用,但实际只在 MySQL 5.7+ 的原生 JSON 字段上生效;sqlite 和旧版 MySQL 会报错或返回空。更稳妥的方式是先取出数据再 PHP 层过滤,或者用 whereJsonContains() / whereJsonDoesntContain()

使用场景:查某个 JSON 字段是否包含特定键值对,比如用户设置里启用了通知:'notifications' => ['email' => true, 'sms' => false]

  • whereJsonContains('meta', ['notifications->email' => true]) —— 注意键路径写法,Laravel 会转成 MySQL 的 JSON_CONTAINS
  • 嵌套太深(如 meta->settings->privacy->public)时,部分驱动不支持,建议拆到独立字段或改用 Eloquent 访问器
  • 想查 JSON 数组长度?whereRaw('JSON_LENGTH(meta->"$.roles") > 0') 可行,但失去可移植性

用访问器(Accessor)和修改器(Mutator)控制 JSON 字段的读写逻辑

当默认的 json cast 不够用——比如要保证某个键始终存在、或对值做格式标准化(如强制转小写、补默认结构)——就得上访问器和修改器。

性能影响:每次读写都会触发 PHP 方法调用,比纯 cast 多一次函数开销,但通常可忽略;重点是别在访问器里做 DB 查询或 http 请求。

  • 定义修改器:public function setMetaAttribute($value) { $this->attributes['meta'] = json_encode(Array_merge(['version' => 1], (array) $value)); }
  • 定义访问器:public function getMetaAttribute($value) { return json_decode($value, true) ?: ['version' => 1]; }
  • 注意:一旦定义了 setMetaAttribute$casts 里的 'meta' => 'json' 就失效了,两者不能共存

前端传来的 JSON 字符串,入库前务必验证结构

用户提交的 meta 字段可能是任意字符串,json_decode($input, true) 返回 NULL 时 Laravel 默认会存 NULL 或空字符串,容易埋坑。

容易踩的坑:request()->input('meta') 是字符串,但没校验就直接赋给模型,可能存入非法 JSON 导致后续 json_decode() 失败、页面炸开。

  • 在 Form Request 中加验证:'meta' => 'required|json'(Laravel 5.5+ 自带 json 规则)
  • 若需更细粒度校验(比如要求必须有 theme 键),用 required_with:meta + 自定义规则
  • 避免在控制器里写 json_decode(request('meta'), true) ?? [] 再赋值——这绕过了 cast 和验证,且 null 合并操作掩盖了原始错误

最常被忽略的是数据库兼容性:本地 SQLite 开发时一切正常,上线 MySQL 5.6 就发现 -> 操作符不识别,或者 JSON 函数报错。别只信本地表现,部署前确认目标环境的 JSON 支持级别。

text=ZqhQzanResources