Laravel:如何缓存模型关联关系translations获取的数据?
如何缓存Laravel模型关联的翻译数据?
问题背景
现有Country模型及关联的翻译表代码如下:
<?php namespace Modules\User\Entities; use Astrotomic\Translatable\Translatable; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Cache; use Modules\Core\Traits\Rememberable; use Modules\User\Entities\Sentinel\User; class Country extends Model { use Rememberable; use Translatable; protected $table = 'countries'; public $translatedAttributes = ['name']; protected $fillable = [ 'name', 'code', 'weight', ]; // protected $rememberCacheTag = 'countries'; public function users() { return $this->hasMany(User::class, 'country_id'); } protected static function booted() { static::addGlobalScope('lang', function (Builder $builder) { $builder->whereHas('translations', function (Builder $q) { $q->where('locale', App::getLocale()); }); }); } public function translations(): HasMany { return $this->hasMany($this->getTranslationModelName(), $this->getTranslationRelationKey()); } }
尝试两种缓存翻译关联的方案均报错:
Call to undefined method Illuminate\Database\Eloquent\Relations\HasMany::remember()
方案一:查询时给关联加缓存
$c = Country::with([ 'translations' => function($q){ $q->remember(600); } ])->remember(600)->find($this->country_id);
方案二:在关联方法中直接加缓存
public function translations(): HasMany { return $this->hasMany($this->getTranslationModelName(), $this->getTranslationRelationKey())->remember(600); }
解决方案
原因分析
remember()是Rememberable trait给**查询构建器(Builder)**添加的方法,而关联返回的HasMany是关系类,并非直接的查询构建器,所以直接调用会报错。
正确实现方式
方法一:缓存包含关联的完整模型查询
直接在主模型查询上使用remember(),同时预加载关联,这样整个查询结果(包括关联的翻译数据)都会被缓存:
$c = Country::with('translations') ->remember(600) ->find($this->country_id);
这种方式操作简单,适合单次查询需要完整模型+关联数据的场景。
方法二:手动用缓存门面单独缓存关联数据
如果需要单独控制关联数据的缓存规则,可以通过Cache门面手动实现:
// 获取基础Country模型 $country = Country::find($this->country_id); // 生成带语言标识的唯一缓存键,避免多语言数据冲突 $cacheKey = "country_{$country->id}_translations_" . App::getLocale(); // 缓存翻译数据 $translations = Cache::remember($cacheKey, 600, function () use ($country) { return $country->translations()->get(); }); // 将缓存的关联数据绑定到模型上 $country->setRelation('translations', $translations);
这种方式灵活性更高,能针对关联数据单独设置缓存时长或更新规则。
方法三:让翻译模型启用Rememberable特性
如果你的翻译模型(比如CountryTranslation)也引入了Rememberable trait,可以修改关联方法,先获取查询构建器再调用remember():
public function translations(): HasMany { return $this->hasMany($this->getTranslationModelName(), $this->getTranslationRelationKey()) ->query() ->remember(600); }
注意:必须确保翻译模型本身已经使用Rememberable trait,否则该方法无效。
额外优化建议
- 启用缓存标签:取消
Country模型中protected $rememberCacheTag = 'countries';的注释,后续更新国家数据时,可通过Cache::tags('countries')->flush();批量清除相关缓存。 - 缓存键加入语言标识:由于你的查询带有语言全局作用域,缓存时把当前语言加入键名,能避免不同语言的数据互相覆盖。
内容的提问来源于stack exchange,提问作者M a m a D
相关产品推荐
相关产品推荐

