Laravel模型多语言查询优化:如何省略控制器中with关联查询语句
完全可以将多语言关联的查询逻辑封装到Point模型中,省略控制器里的with查询子句,推荐以下实现方式:
方案1:新增自动匹配当前语言的一对一关联
因为你已经设置了point_id和lang的联合唯一索引,每个点位对应每种语言只会有一条详情记录,所以可以直接定义hasOne类型的关联,自动注入语言过滤条件:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Auth; class Point extends Model { // 原有一对多关联保留,可用于后台管理多语言内容的场景 public function details() { return $this->hasMany(PointDetail::class); } // 新增当前语言的一对一关联 public function currentLangDetail() { // 优先取登录用户的语言,没有的话用默认 fallback 语言 $targetLang = Auth::check() ? Auth::user()->lang : config('app.fallback_locale', 'it'); return $this->hasOne(PointDetail::class)->where('lang', $targetLang); } // 如果需要所有Point查询都自动预加载当前语言的详情,加上这行即可 protected $with = ['currentLangDetail']; }
修改后控制器的代码可以简化为:
public function show($id) { $point = Point::find($id); return view('points.show', compact('point')); }
视图中可以直接通过$point->currentLangDetail->name、$point->currentLangDetail->description获取对应语言的内容。
方案2:追加访问器实现直接调用多语言属性
如果希望直接通过$point->name、$point->description获取多语言内容,可以在Point模型中追加访问器:
// 在Point模型中新增以下代码 protected $appends = ['name', 'description']; public function getNameAttribute() { return $this->currentLangDetail?->name ?? ''; } public function getDescriptionAttribute() { return $this->currentLangDetail?->description ?? ''; }
注意事项
- 不要硬编码默认语言,建议用Laravel自带的
config('app.fallback_locale')配置,便于全局统一管理 - 关联逻辑中已经加了
Auth::check()判断,避免未登录场景下调用Auth::user()抛出错误 - 如果部分场景不需要自动预加载多语言详情,删除模型中的
$with属性即可,需要用到的时候手动调用Point::with('currentLangDetail')->find($id)查询即可
内容的提问来源于stack exchange,提问作者Gimbo
相关产品推荐
相关产品推荐

