Prawdopodobnie zbuforowałeś już niektóre dane modelu w kontrolerze, ale pokażę Ci technikę buforowania modeli Laravel, która jest nieco bardziej szczegółowa przy użyciu modeli Active Record. Jest to technika, o której po raz pierwszy dowiedziałem się na RailsCasts.
Korzystając z unikatowego klucza pamięci podręcznej w modelu, można buforować właściwości i skojarzenia w modelach, które są automatycznie aktualizowane (a pamięć podręczna unieważniana) po zaktualizowaniu modelu (lub skojarzonego modelu). Dodatkową korzyścią jest to, że dostęp do danych w pamięci podręcznej jest bardziej przenośny niż buforowanie danych w kontrolerze, ponieważ znajduje się on w modelu, a nie w ramach jednej metody kontrolera.
Oto istota techniki:
Załóżmy, że masz model, Article
który ma wiele Comment
modeli. Biorąc pod uwagę następujący szablon ostrza Laravel, możesz pobrać liczbę komentarzy w ten sposób na swojej /article/:id
trasie:
<h3>{{ str_plural('Comment', $article->comments->count()) }}</h3>
Możesz buforować liczbę komentarzy w kontrolerze, ale kontroler może być dość brzydki, gdy masz wiele jednorazowych zapytań i danych, które musisz buforować. Korzystając z kontrolera, dostęp do danych w pamięci podręcznej również nie jest zbyt przenośny.
Możemy zbudować szablon, który trafi do bazy danych tylko wtedy, gdy artykuł zostanie zaktualizowany, a każdy kod, który ma dostęp do modelu, może pobrać wartość z pamięci podręcznej:
<h3>{{ str_plural('Comment', $article->cached_comments_count) }}</h3>
Korzystając z metody dostępu do modelu, zbuforujemy liczbę komentarzy na podstawie czasu ostatniej aktualizacji artykułu.
Jak więc zaktualizować kolumnę updated_at
artykułu, gdy zostanie dodany lub usunięty nowy komentarz?
Wprowadź metodę dotykową.
Dotykanie modeli
Korzystając z metody modelutouch()
, możemy zaktualizować kolumnę updated_at
artykułu:
$ php artisan tinker
>>> $article = \App\Article::first();
=> App\Article {#746
id: 1,
title: "Hello World",
body: "The Body",
created_at: "2018-01-11 05:16:51",
updated_at: "2018-01-11 05:51:07",
}
>>> $article->updated_at->timestamp
=> 1515649867
>>> $article->touch();
=> true
>>> $article->updated_at->timestamp
=> 1515650910
Możemy użyć zaktualizowanego znacznika czasu, aby unieważnić pamięć podręczną, ale jak możemy dotknąć pola artykułuupdated_at
, gdy dodajemy lub usuwamy komentarz?
Tak się składa, że modele Eloquent mają właściwość o nazwie $touches
. Oto, jak może wyglądać nasz model komentarzy:
namespace App;
use App\Article;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
protected $guarded = [];
protected $touches = ['article'];
public function article()
{
return $this->belongsTo(Article::class);
}
}
Właściwość $touches
jest tablicą zawierającą skojarzenie, które zostanie "dotknięte" podczas tworzenia, zapisywania lub usuwania komentarza.
Atrybut
buforowany Wróćmy do $article->cached_comments_count
akcesora. Implementacja może wyglądać następująco App\Article
w modelu:
public function getCachedCommentsCountAttribute()
{
return Cache::remember($this->cacheKey() . ':comments_count', 15, function () {
return $this->comments->count();
});
}
Buforujemy model przez piętnaście minut przy użyciu unikalnej cacheKey()
metody i po prostu zwracamy liczbę komentarzy wewnątrz zamknięcia.
Pamiętaj, że możemy również użyć tej Cache::rememberForever()
metody i polegać na wyrzucaniu śmieci naszego mechanizmu buforowania, aby usunąć stare klucze. Ustawiłem licznik czasu tak, aby pamięć podręczna była trafiana przez większość czasu, z nową pamięcią podręczną co piętnaście minut.
Metoda cacheKey()
musi sprawić, że model będzie unikatowy i unieważnić pamięć podręczną po zaktualizowaniu modelu. Oto moja cacheKey
implementacja:Przykładowe dane wyjściowe metody modelu mogą zwrócić następującą reprezentację ciągu:
public function cacheKey()
{
return sprintf(
"%s/%s-%s",
$this->getTable(),
$this->getKey(),
$this->updated_at->timestamp
);
}
articles/1-1515650910
Klucz to nazwa tabeli, identyfikator modelu cacheKey()
i bieżący updated_at
znacznik czasu. Gdy dotkniemy modelu, znacznik czasu zostanie zaktualizowany, a nasza pamięć podręczna modelu zostanie odpowiednio unieważniona.
Oto model, Article
jeśli jest pełny:I powiązany Comment
model:
namespace App;
use App\Comment;
use Illuminate\Support\Facades\Cache;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
public function cacheKey()
{
return sprintf(
"%s/%s-%s",
$this->getTable(),
$this->getKey(),
$this->updated_at->timestamp
);
}
public function comments()
{
return $this->hasMany(Comment::class);
}
public function getCachedCommentsCountAttribute()
{
return Cache::remember($this->cacheKey() . ':comments_count', 15, function () {
return $this->comments->count();
});
}
}
namespace App;
use App\Article;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
protected $guarded = [];
protected $touches = ['article'];
public function article()
{
return $this->belongsTo(Article::class);
}
}
Co dalej?
Pokazałem ci, jak buforować prostą liczbę komentarzy, ale co z buforowaniem wszystkich komentarzy?
public function getCachedCommentsAttribute()
{
return Cache::remember($this->cacheKey() . ':comments', 15, function () {
return $this->comments;
});
}
Możesz również zdecydować się na konwersję komentarzy na tablicę zamiast serializacji modeli, aby umożliwić tylko prosty dostęp do tablicy do danych w interfejsie użytkownika:Na koniec zdefiniowałem metodę na Article
modelu, ale chciałbyś zdefiniować tę metodę za pomocą cechy o nazwie coś takiegoProvidesModelCacheKey
,
public function getCachedCommentsAttribute()
{
return Cache::remember($this->cacheKey() . ':comments', 15, function () {
return $this->comments->toArray();
});
}
której możesz użyć w wielu modelach lub zdefiniować cacheKey()
metodę w modelu podstawowym, który rozszerzają wszystkie nasze modele. Możesz nawet użyć kontraktu (interfejsu) dla modeli, które implementują metodęcacheKey()
.
Mam nadzieję, że ta prosta technika okazała się przydatna!