Laravel:如何缓存从模型关系中检索到的数据?

huangapple go评论60阅读模式
英文:

Laravel: How to cache the data retrieved from a relationship of a model?

问题

以下是您提供的代码的翻译部分:

有一个名为 `Country` 的模型和名为 `translations` 的关系,如下所示

<?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());
    }
}

如果您想要缓存translations关系的数据,您可以尝试以下两种方法:

第一种方法:

$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);
}

但是,如果您遇到以下错误:

Call to undefined method Illuminate\Database\Eloquent\Relations\HasMany::remember()

这意味着remember方法不适用于HasMany关系。您可以考虑在查询Country模型之后手动缓存translations关系的数据,而不是在关系定义中使用remember方法。这可以通过Laravel的缓存功能来实现。

英文:

There is a model Country and relation translations as follows

&lt;?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 = &#39;countries&#39;;
    public $translatedAttributes = [&#39;name&#39;];
    protected $fillable = [
        &#39;name&#39;,
        &#39;code&#39;,
        &#39;weight&#39;,
    ];

//    protected $rememberCacheTag = &#39;countries&#39;;

    public function users()
    {
        return $this-&gt;hasMany(User::class, &#39;country_id&#39;);
    }

    protected static function booted()
    {
        static::addGlobalScope(&#39;lang&#39;, function (Builder $builder) {
            $builder-&gt;whereHas(&#39;translations&#39;, function (Builder $q) {
                $q-&gt;where(&#39;locale&#39;, App::getLocale());
            });
        });
    }

    public function translations(): HasMany
    {
        return $this-&gt;hasMany($this-&gt;getTranslationModelName(), $this-&gt;getTranslationRelationKey());
    }
}

I need to cache the data of the translations relation. I have tried the following so far that taken from Link

$c = Country::with([
    &#39;translations&#39; =&gt; function($q){
        $q-&gt;remember(600);
    }
])-&gt;remember(600)-&gt;find($this-&gt;country_id);

and this solution too

public function translations(): HasMany
{
    return $this-&gt;hasMany($this-&gt;getTranslationModelName(), $this-&gt;getTranslationRelationKey())-&gt;remember(600);
}

But I got the error

> Call to undefined method Illuminate\Database\Eloquent\Relations\HasMany::remember()

How can I cache the data retrieved from a relation?

答案1

得分: 1

You should cache the entire query, since just caching the relation does not work. (At least out of the box, unsure if you can 'hack' it)

So, using Laravel Cache, it becomes as follows;

$countryId = $this->countryId;
return Cache::remember("<your_cache_key>", 600, function() use ($countryId) {
   return Country::with(['translations'])->find($countryId);
});

If you are using Redis/Predis (or anything else that supports cache tagging), you can even add cache tags to it;

$countryId = $this->countryId;
return Cache::tags([<array_of_cache_tags>])->remember("<your_cache_key>", 600, function() use ($countryId) {
   return Country::with(['translations'])->find($countryId);
});

In the example <your_cache_key> could be something along the lines of "country_translations:{$countryId}".

<array_of_cache_tags> could be something like ["country", "translations"].

英文:

You should cache the entire query, since just caching the relation does not work. (At least out of the box, unsure if you can 'hack' it)

So, using Laravel Cache, it becomes as follows;

$countryId = $this-&gt;countryId;
return Cache::remember(&quot;&lt;your_cache_key&gt;&quot;, 600, function() use ($countryId) {
   return Country::with([&#39;translations&#39;])-&gt;find($countryId);
});

If you are using Redis/Predis (or anything else that supports cache tagging), you can even add cache tags to it;

$countryId = $this-&gt;countryId;
return Cache::tags([&lt;array_of_cache_tags&gt;])-&gt;remember(&quot;&lt;your_cache_key&gt;&quot;, 600, function() use ($countryId) {
   return Country::with([&#39;translations&#39;])-&gt;find($countryId);
});

In the example &lt;your_cache_key&gt; could be something along the lines of &quot;country_translations:{$countryId}&quot;.

&lt;array_of_cache_tags&gt; could be something like [&quot;country&quot;, &quot;translations&quot;]

huangapple
  • 本文由 发表于 2023年4月19日 15:43:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76051894.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定