• Час читання ~4 хв
  • 15.11.2023

Ви, ймовірно, кешували деякі дані моделі в контролері раніше, але я збираюся показати вам техніку кешування моделі Laravel, яка є трохи більш деталізованою з використанням моделей Active Record. Це техніка, про яку я спочатку дізнався на RailsCasts.

Використовуючи унікальний ключ кешу моделі, ви можете кешувати властивості та асоціації на своїх моделях, які автоматично оновлюються (і кеш стає недійсним), коли модель (або пов'язана з нею модель) оновлюється. Додатковою перевагою є те, що доступ до кешованих даних є більш переносним, ніж кешування даних у контролері, оскільки це відбувається за моделлю, а не в рамках одного методу контролера.

Ось суть техніки:Припустимо, у вас є Article модель,

яка має багато Comment моделей. Враховуючи наступний шаблон блейда Laravel, ви можете отримати кількість коментарів таким чином на своєму /article/:id маршруті:

<h3>{{ str_plural('Comment', $article->comments->count()) }}</h3>

Ви можете кешувати кількість коментарів у контролері, але контролер може бути досить потворним, коли у вас є кілька одноразових запитів і даних, які вам потрібно кешувати. За допомогою контролера доступ до кешованих даних також не дуже портативний.

Ми можемо створити шаблон, який потраплятиме до бази даних лише тоді, коли стаття оновлюється, і будь-який код, який має доступ до моделі, може отримати кешоване значення:

<h3>{{ str_plural('Comment', $article->cached_comments_count) }}</h3>

Використовуючи засіб доступу до моделі, ми кешуватимемо кількість коментарів на основі останнього оновлення статті.

Отже, як оновити колонку статтіupdated_at, коли додається або видаляється новий коментар?

Введіть сенсорний метод.

Торкаючись моделей

Використовуючи метод моделіtouch(), ми можемо оновити колонку статті:

$ 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

Ми можемо використовувати оновлену часову позначку, щоб зробити кеш недійсним, але як ми можемо торкнутися поля статті updated_at updated_at, коли додаємо або видаляємо коментар?

Так уже склалося, що красномовні моделі мають властивість, яка називається $touches. Ось як може виглядати наша модель коментарів:

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

Властивість $touches - це масив, що містить асоціацію, яка буде "зачеплена" при створенні, збереженні або видаленні коментаря.

Кешований атрибут

Повернімося до засобу доступу$article->cached_comments_count. Реалізація може виглядати так на App\Article моделі:

public function getCachedCommentsCountAttribute()
{
    return Cache::remember($this->cacheKey() . ':comments_count', 15, function () {
        return $this->comments->count();
    });
}

Ми кешуємо модель протягом п'ятнадцяти хвилин за допомогою унікального cacheKey() методу і просто повертаємо кількість коментарів всередині закриття.

Зауважте, що ми також можемо використовувати цей Cache::rememberForever() метод і покладатися на збір сміття нашого механізму кешування для видалення застарілих ключів. Я встановив таймер таким чином, щоб кеш був вражений більшу частину часу, з новим кешем кожні п'ятнадцять хвилин.

Метод cacheKey() повинен зробити модель унікальною і зробити кеш недійсним при оновленні моделі. Ось моя cacheKey реалізація:Приклад виведення методу моделі може повертати наступне представлення рядка:

public function cacheKey()
{
    return sprintf(
        "%s/%s-%s",
        $this->getTable(),
        $this->getKey(),
        $this->updated_at->timestamp
    );
}

articles/1-1515650910

Ключем є ім'я таблиці, ідентифікатор моделі cacheKey() та поточна часова позначкаupdated_at. Як тільки ми торкнемося моделі, часова позначка буде оновлена, а наш кеш моделі буде визнано недійсним відповідним чином.

Ось Article модель, якщо повна:І пов'язана Comment модель:

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

Що далі?

Я показав вам, як кешувати просту кількість коментарів, але як щодо кешування всіх коментарів?

public function getCachedCommentsAttribute()
{
    return Cache::remember($this->cacheKey() . ':comments', 15, function () {
        return $this->comments;
    });
}

Ви також можете перетворити коментарі на масив замість серіалізації моделей, щоб дозволити лише простий доступ масиву до даних на фронтенді:

public function getCachedCommentsAttribute()
{
    return Cache::remember($this->cacheKey() . ':comments', 15, function () {
        return $this->comments->toArray();
    });
}

Нарешті, я визначив cacheKey() метод на моделі, але ви захочете визначити цей метод за допомогою риси, яка називається чимось подібнимProvidesModelCacheKey, яку ви можете використовувати на кількох моделях, або визначити метод на Article базовій моделі, яку розширюють усі наші моделі. Можливо, ви навіть захочете використовувати контракт (інтерфейс) для моделей, які реалізують cacheKey() метод.

Сподіваюся, ця проста техніка була для вас корисною!

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

Про мене

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

Про автора CrazyBoy49z
WORK EXPERIENCE
Контакти
Ukraine, Lutsk
+380979856297