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

如何让Laravel属性转换仅获取单个JSON字段值?

解决Laravel模型JSON字段获取指定语言值的问题

问题分析

你遇到的核心问题:

  1. 定义与字段同名的访问器时,Laravel会跳过casts的自动转换规则,访问器拿到的是数据库中原始的JSON字符串而非数组,因此用$value['en']会触发"Cannot access offset of type string on string"错误。
  2. 直接在访问器中调用$this->title会触发访问器自身,形成循环引用,最终拿到的是访问器返回的字符串而非原始数组,同样引发错误。

解决方案

方案1:使用独立命名的访问器(推荐)

保留原有的casts配置,创建新的访问器处理本地化内容,避免和字段名冲突:

// 保留原有casts配置
protected function casts(): array
{
    return [
        'title' => 'json',
        'resume' => 'json',
        'content' => 'json',
    ];
}

// 创建本地化标题的访问器
protected function localizedTitle(): Attribute
{
    return Attribute::make(
        get: fn () => $this->title[app()->getLocale()] ?? $this->title['en'],
    );
}

// 自动将本地化字段加入模型的JSON输出
protected $appends = ['localized_title'];

这样模型转为JSON时,会自动包含localized_title字段,值为当前语言的标题。如果不需要保留原始title字段,可在资源类中隐藏它。

方案2:在访问器中手动处理JSON转换

若一定要复用title字段名,需在访问器中手动将JSON字符串转为数组:

// 移除casts中的title配置,由访问器处理转换
protected function casts(): array
{
    return [
        'resume' => 'json',
        'content' => 'json',
    ];
}

protected function title(): Attribute
{
    return Attribute::make(
        get: function ($value) {
            $titleArray = json_decode($value, true);
            return $titleArray[app()->getLocale()] ?? $titleArray['en'];
        },
        // 如需保存值,根据需求调整,示例为按当前语言保存多语言结构
        set: function ($value) {
            return json_encode([app()->getLocale() => $value]);
        },
    );
}

方案3:在资源类中处理(适合API场景)

如果是给前端返回API数据,推荐直接在资源类中处理本地化逻辑:

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class ArticleResource extends JsonResource
{
    public function toArray($request)
    {
        // 优先从请求头取语言, fallback到系统默认语言
        $locale = $request->header('Accept-Language') ?? app()->getLocale();
        
        return [
            'id' => $this->id,
            'title' => $this->title[$locale] ?? $this->title['en'],
            'resume' => $this->resume[$locale] ?? $this->resume['en'],
            // 其他需要返回的字段
        ];
    }
}

控制器中使用资源类返回数据:

return ArticleResource::collection(Article::all());

前端就能直接拿到仅含目标语言内容的JSON结构,比如[{"id":1,"title":"English Title"}]。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 19:53:15