Кешування — Laravel
Деякі завдання з отримання чи обробки даних, що їх виконує ваш застосунок, можуть бути ресурсомісткими для CPU або тривати кілька секунд. Коли це так, зазвичай кешують отримані дані на певний час, щоб їх можна було швидко отримати під час наступних запитів по ті самі дані. Кешовані дані зазвичай зберігаються у дуже швидкому сховищі даних, як-от Memcached або Redis.
На щастя, Laravel надає виразний уніфікований API для різних кеш-бекендів, що дозволяє скористатися їхньою блискавичною швидкістю отримання даних і пришвидшити ваш вебзастосунок.
Конфігурація
Конфігураційний файл кешу вашого застосунку розташований за шляхом config/cache.php. У цьому файлі ви можете вказати, яке сховище кешу (cache store) має використовуватися за замовчуванням у всьому застосунку. Laravel «з коробки» підтримує популярні кеш-бекенди, як-от Memcached, Redis, DynamoDB, реляційні бази даних і диски файлової системи. Крім того, доступний файловий драйвер кешу, а драйвери array і null є зручними кеш-бекендами для ваших автоматизованих тестів.
Конфігураційний файл кешу також містить низку інших опцій, які варто переглянути. За замовчуванням Laravel налаштовано на використання драйвера кешу database, який зберігає серіалізовані кешовані обʼєкти в базі даних вашого застосунку.
Передумови для драйверів
Database
Під час використання драйвера кешу database вам знадобиться таблиця бази даних для зберігання даних кешу. Зазвичай вона входить до стандартної міграції бази даних Laravel 0001_01_01_000001_create_cache_table.php; однак, якщо ваш застосунок не містить цієї міграції, ви можете скористатися Artisan-командою make:cache-table, щоб її створити:
php artisan make:cache-table
php artisan migrate
Memcached
Для використання драйвера Memcached потрібно встановити пакет Memcached PECL. Ви можете перелічити всі свої сервери Memcached у конфігураційному файлі config/cache.php. Цей файл уже містить запис memcached.servers, щоб ви могли почати:
'memcached' => [
// ...
'servers' => [
[
'host' => env('MEMCACHED_HOST', '127.0.0.1'),
'port' => env('MEMCACHED_PORT', 11211),
'weight' => 100,
],
],
],
За потреби ви можете встановити опцію host у шлях до UNIX-сокета. Якщо ви так робите, опцію port слід встановити в 0:
'memcached' => [
// ...
'servers' => [
[
'host' => '/var/run/memcached/memcached.sock',
'port' => 0,
'weight' => 100
],
],
],
Redis
Перед використанням кешу Redis із Laravel вам потрібно або встановити PHP-розширення PhpRedis через PECL, або встановити пакет predis/predis через Composer. Laravel Sail уже містить це розширення. Крім того, офіційні платформи для застосунків Laravel, як-от Laravel Cloud і Laravel Forge, мають розширення PhpRedis установленим за замовчуванням.
Докладніше про налаштування Redis дивіться на сторінці документації Laravel.
Storage
Драйвер кешу storage дозволяє зберігати кешовані значення на будь-якому зі сконфігурованих у вашому застосунку дисків файлової системи. Це може бути корисно, коли ви хочете використати наявний диск, наприклад диск S3, як сховище кешу типу ключ / значення:
'storage' => [
'driver' => 'storage',
'disk' => env('CACHE_STORAGE_DISK'),
'path' => env('CACHE_STORAGE_PATH', 'framework/cache/data'),
],
DynamoDB
Перед використанням драйвера кешу DynamoDB ви маєте створити таблицю DynamoDB для зберігання всіх кешованих даних. Зазвичай ця таблиця має називатися cache. Однак вам слід назвати таблицю на основі значення конфігураційної опції stores.dynamodb.table у конфігураційному файлі cache. Імʼя таблиці також можна задати через змінну середовища DYNAMODB_CACHE_TABLE.
Ця таблиця також повинна мати рядковий ключ розділу (partition key) з іменем, що відповідає значенню конфігураційного елемента stores.dynamodb.attributes.key у конфігураційному файлі cache вашого застосунку. За замовчуванням ключ розділу має називатися key.
Зазвичай DynamoDB не видаляє прострочені елементи з таблиці проактивно. Тому вам слід увімкнути Time to Live (TTL) для таблиці. Налаштовуючи параметри TTL таблиці, вкажіть імʼя TTL-атрибута expires_at.
Далі встановіть AWS SDK, щоб ваш застосунок Laravel міг взаємодіяти з DynamoDB:
composer require aws/aws-sdk-php
Крім того, вам слід переконатися, що для конфігураційних опцій сховища кешу DynamoDB надано значення. Зазвичай ці опції, як-от AWS_ACCESS_KEY_ID і AWS_SECRET_ACCESS_KEY, мають бути визначені у конфігураційному файлі .env вашого застосунку:
'dynamodb' => [
'driver' => 'dynamodb',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
'endpoint' => env('DYNAMODB_ENDPOINT'),
],
MongoDB
Якщо ви використовуєте MongoDB, драйвер кешу mongodb надається офіційним пакетом mongodb/laravel-mongodb і може бути налаштований за допомогою зʼєднання з базою даних mongodb. MongoDB підтримує TTL-індекси, які можна використовувати для автоматичного очищення прострочених елементів кешу.
Докладніше про налаштування MongoDB дивіться в документації MongoDB Cache and Locks.
Використання кешу
Отримання екземпляра кешу
Щоб отримати екземпляр сховища кешу, ви можете скористатися фасадом Cache, який ми й використовуватимемо в цій документації. Фасад Cache надає зручний, лаконічний доступ до реалізацій контрактів кешу Laravel:
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Cache;
class UserController extends Controller
{
/**
* Show a list of all users of the application.
*/
public function index(): array
{
$value = Cache::get('key');
return [
// ...
];
}
}
Доступ до кількох сховищ кешу
За допомогою фасада Cache ви можете отримати доступ до різних сховищ кешу через метод store. Ключ, переданий у метод store, має відповідати одному зі сховищ, перелічених у конфігураційному масиві stores у вашому конфігураційному файлі cache:
$value = Cache::store('file')->get('foo');
Cache::store('redis')->put('bar', 'baz', 600); // 10 Minutes
Отримання елементів із кешу
Метод get фасада Cache використовується для отримання елементів із кешу. Якщо елемента немає в кеші, буде повернено null. За бажання ви можете передати методу get другий аргумент, що вказує значення за замовчуванням, яке ви хочете отримати, якщо елемента не існує:
$value = Cache::get('key');
$value = Cache::get('key', 'default');
Ви навіть можете передати замикання як значення за замовчуванням. Результат замикання буде повернено, якщо вказаного елемента немає в кеші. Передавання замикання дозволяє відкласти отримання значень за замовчуванням із бази даних чи іншого зовнішнього сервісу:
$value = Cache::get('key', function () {
return DB::table(/* ... */)->get();
});
Визначення наявності елемента
Метод has можна використовувати, щоб визначити, чи існує елемент у кеші. Цей метод також поверне false, якщо елемент існує, але його значення — null:
if (Cache::has('key')) {
// ...
}
Збільшення / зменшення значень
Методи increment і decrement можна використовувати для коригування значення цілочисельних елементів у кеші. Обидва ці методи приймають необовʼязковий другий аргумент, що вказує величину, на яку слід збільшити або зменшити значення елемента:
// Ініціалізуємо значення, якщо його не існує...
Cache::add('key', 0, now()->plus(hours: 4));
// Збільшуємо або зменшуємо значення...
Cache::increment('key');
Cache::increment('key', $amount);
Cache::decrement('key');
Cache::decrement('key', $amount);
Отримати й зберегти
Іноді ви можете захотіти отримати елемент із кешу, але водночас зберегти значення за замовчуванням, якщо запитуваного елемента не існує. Наприклад, ви можете захотіти отримати всіх користувачів із кешу або, якщо їх там немає, отримати їх із бази даних і додати до кешу. Це можна зробити за допомогою методу Cache::remember:
$value = Cache::remember('users', $seconds, function () {
return DB::table('users')->get();
});
Якщо елемента немає в кеші, буде виконано замикання, передане в метод remember, а його результат буде поміщено в кеш.
Якщо вам потрібно знати, чи був елемент отриманий із кешу, а не шляхом виконання переданого замикання, ви можете скористатися методом rememberWithWarmth. Цей метод повертає масив, що містить кешоване значення і булеве значення, яке вказує, чи був елемент «теплим» (warm), тобто чи був він отриманий із кешу, а не обчислений із замикання:
[$value, $warm] = Cache::rememberWithWarmth('users', $seconds, function () {
return DB::table('users')->get();
});
Ви можете скористатися методом rememberForever, щоб отримати елемент із кешу або зберегти його назавжди, якщо його не існує:
$value = Cache::rememberForever('users', function () {
return DB::table('users')->get();
});
Stale While Revalidate
Під час використання методу Cache::remember деякі користувачі можуть відчувати повільний час відповіді, якщо кешоване значення застаріло. Для певних типів даних може бути корисно дозволити віддавати частково застарілі дані, поки кешоване значення перераховується у фоновому режимі — це запобігає тому, щоб частина користувачів стикалася з повільними відповідями, поки обчислюються кешовані значення. Це часто називають патерном «stale-while-revalidate», і метод Cache::flexible надає реалізацію цього патерну.
Метод flexible приймає масив, який вказує, як довго кешоване значення вважається «свіжим» (fresh) і коли воно стає «застарілим» (stale). Перше значення масиву визначає кількість секунд, протягом яких кеш вважається свіжим, а друге значення визначає, як довго його можна віддавати як застарілі дані, доки не стане необхідним перерахунок.
Якщо запит надходить у межах періоду свіжості (до першого значення), кеш повертається негайно без перерахунку. Якщо запит надходить під час періоду застарілості (між двома значеннями), користувачеві віддається застаріле значення, і реєструється відкладена функція, яка оновлює кешоване значення після того, як відповідь надіслано користувачеві. Якщо запит надходить після другого значення, кеш вважається простроченим, і значення перераховується негайно, що може призвести до повільнішої відповіді для користувача:
$value = Cache::flexible('users', [5, 10], function () {
return DB::table('users')->get();
});
Отримати й видалити
Якщо вам потрібно отримати елемент із кешу, а потім видалити його, ви можете скористатися методом pull. Як і метод get, він поверне null, якщо елемента немає в кеші:
$value = Cache::pull('key');
$value = Cache::pull('key', 'default');
Збереження елементів у кеші
Ви можете використати метод put фасада Cache, щоб зберігати елементи в кеші:
Cache::put('key', 'value', $seconds = 10);
Якщо час зберігання не передано в метод put, елемент зберігатиметься безстроково:
Cache::put('key', 'value');
Замість передавання кількості секунд цілим числом ви також можете передати екземпляр DateTime, що представляє бажаний час спливання терміну дії кешованого елемента:
Cache::put('key', 'value', now()->plus(minutes: 10));
Зберегти, якщо відсутнє
Метод add додасть елемент до кешу лише тоді, коли він ще не існує у сховищі кешу. Метод поверне true, якщо елемент справді було додано до кешу. Інакше метод поверне false. Метод add є атомарною операцією:
Cache::add('key', 'value', $seconds);
Продовження часу життя елемента
Метод touch дозволяє продовжити час життя (TTL) наявного елемента кешу. Метод touch поверне true, якщо елемент кешу існує і його час спливання успішно продовжено. Якщо елемента немає в кеші, метод поверне false:
Cache::touch('key', 3600);
Ви можете передати екземпляр DateTimeInterface, DateInterval або Carbon, щоб указати точний час спливання:
Cache::touch('key', now()->addHours(2));
Збереження елементів назавжди
Метод forever можна використовувати для постійного зберігання елемента в кеші. Оскільки термін дії таких елементів не спливає, їх потрібно видаляти з кешу вручну за допомогою методу forget:
Cache::forever('key', 'value');
Зверніть увагу Якщо ви використовуєте драйвер Memcached, елементи, збережені «назавжди», можуть бути видалені, коли кеш досягне обмеження за розміром.
Видалення елементів із кешу
Ви можете видаляти елементи з кешу за допомогою методу forget:
Cache::forget('key');
Ви також можете видаляти елементи, передавши нульову або відʼємну кількість секунд до спливання терміну дії:
Cache::put('key', 'value', 0);
Cache::put('key', 'value', -5);
Ви можете очистити весь кеш за допомогою методу flush:
Cache::flush();
Ви можете очистити всі атомарні блокування в кеші за допомогою методу flushLocks:
Cache::flushLocks();
Попередження Очищення кешу не враховує сконфігурований «префікс» кешу і видалить із кешу всі записи. Добре обміркуйте це, коли очищаєте кеш, який спільно використовується з іншими застосунками.
Мемоізація кешу
Драйвер кешу memo у Laravel дозволяє тимчасово зберігати отримані значення кешу в памʼяті протягом одного запиту або виконання завдання (job). Це запобігає повторним зверненням до кешу в межах одного виконання, значно покращуючи продуктивність.
Щоб скористатися мемоізованим кешем, викличте метод memo:
use Illuminate\Support\Facades\Cache;
$value = Cache::memo()->get('key');
Метод memo необовʼязково приймає імʼя сховища кешу, яке вказує базове сховище кешу, що його декоруватиме мемоізований драйвер:
// Using the default cache store...
$value = Cache::memo()->get('key');
// Using the Redis cache store...
$value = Cache::memo('redis')->get('key');
Перший виклик get для заданого ключа отримує значення з вашого сховища кешу, але наступні виклики в межах того самого запиту чи завдання (job) отримуватимуть значення з памʼяті:
// Hits the cache...
$value = Cache::memo()->get('key');
// Does not hit the cache, returns memoized value...
$value = Cache::memo()->get('key');
Під час виклику методів, які змінюють значення кешу (як-от put, increment, remember тощо), мемоізований кеш автоматично забуває мемоізоване значення і делегує виклик змінювального методу базовому сховищу кешу:
Cache::memo()->put('name', 'Taylor'); // Writes to underlying cache...
Cache::memo()->get('name'); // Hits underlying cache...
Cache::memo()->get('name'); // Memoized, does not hit cache...
Cache::memo()->put('name', 'Tim'); // Forgets memoized value, writes new value...
Cache::memo()->get('name'); // Hits underlying cache again...
Хелпер cache
Окрім використання фасада Cache, ви також можете застосовувати глобальну функцію cache, щоб отримувати й зберігати дані через кеш. Коли функцію cache викликано з одним рядковим аргументом, вона поверне значення заданого ключа:
$value = cache('key');
Якщо ви передасте функції масив пар ключ / значення і час спливання, вона збереже значення в кеші на вказаний період:
cache(['key' => 'value'], $seconds);
cache(['key' => 'value'], now()->plus(minutes: 10));
Коли функцію cache викликано без жодних аргументів, вона повертає екземпляр реалізації Illuminate\Contracts\Cache\Factory, що дозволяє вам викликати інші методи кешування:
cache()->remember('users', $seconds, function () {
return DB::table('users')->get();
});
Зверніть увагу Тестуючи виклики глобальної функції
cache, ви можете скористатися методомCache::shouldReceiveтак само, як якби ви тестували фасад.
Теги кешу
Попередження Теги кешу не підтримуються під час використання драйверів кешу
file,dynamodb,databaseабоstorage.
Збереження тегованих елементів кешу
Теги кешу дозволяють тегувати повʼязані елементи в кеші, а потім очищати всі кешовані значення, яким призначено заданий тег. Ви можете отримати доступ до тегованого кешу, передавши впорядкований масив імен тегів. Наприклад, отримаймо доступ до тегованого кешу і збережімо (put) значення в кеш:
use Illuminate\Support\Facades\Cache;
Cache::tags(['people', 'artists'])->put('John', $john, $seconds);
Cache::tags(['people', 'authors'])->put('Anne', $anne, $seconds);
Доступ до тегованих елементів кешу
До елементів, збережених через теги, не можна отримати доступ без надання тих самих тегів, які використовувалися для збереження значення. Щоб отримати тегований елемент кешу, передайте той самий упорядкований список тегів у метод tags, а потім викличте метод get із ключем, який ви хочете отримати:
$john = Cache::tags(['people', 'artists'])->get('John');
$anne = Cache::tags(['people', 'authors'])->get('Anne');
Видалення тегованих елементів кешу
Ви можете очистити всі елементи, яким призначено тег або список тегів. Наприклад, наведений нижче код видалив би всі кеші, теговані people, authors або обома. Отже, і Anne, і John були б видалені з кешу:
Cache::tags(['people', 'authors'])->flush();
Натомість наведений нижче код видалив би лише кешовані значення, теговані authors, тож Anne було б видалено, а John — ні:
Cache::tags('authors')->flush();
Атомарні блокування
Попередження Щоб скористатися цією можливістю, ваш застосунок має використовувати драйвер кешу
memcached,redis,dynamodb,database,fileабоarrayяк драйвер кешу за замовчуванням. Крім того, усі сервери мають взаємодіяти з тим самим центральним сервером кешу.
Керування блокуваннями
Атомарні блокування дозволяють маніпулювати розподіленими блокуваннями, не турбуючись про стан гонитви (race conditions). Наприклад, Laravel Cloud використовує атомарні блокування, щоб гарантувати, що на сервері одночасно виконується лише одне віддалене завдання. Ви можете створювати блокування і керувати ними за допомогою методу Cache::lock:
use Illuminate\Support\Facades\Cache;
$lock = Cache::lock('foo', 10);
if ($lock->get()) {
// Lock acquired for 10 seconds...
$lock->release();
}
Метод get також приймає замикання. Після виконання замикання Laravel автоматично звільнить блокування:
Cache::lock('foo', 10)->get(function () {
// Lock acquired for 10 seconds and automatically released...
});
Якщо блокування недоступне в момент, коли ви його запитуєте, ви можете вказати Laravel зачекати вказану кількість секунд. Якщо блокування не вдається отримати протягом указаного часового обмеження, буде викинуто виняток Illuminate\Contracts\Cache\LockTimeoutException:
use Illuminate\Contracts\Cache\LockTimeoutException;
$lock = Cache::lock('foo', 10);
try {
$lock->block(5);
// Lock acquired after waiting a maximum of 5 seconds...
} catch (LockTimeoutException $e) {
// Unable to acquire lock...
} finally {
$lock->release();
}
Наведений вище приклад можна спростити, передавши замикання в метод block. Коли в цей метод передано замикання, Laravel намагатиметься отримати блокування протягом указаної кількості секунд і автоматично звільнить блокування після виконання замикання:
Cache::lock('foo', 10)->block(5, function () {
// Lock acquired for 10 seconds after waiting a maximum of 5 seconds...
});
Керування блокуваннями між процесами
Іноді вам може знадобитися отримати блокування в одному процесі, а звільнити його в іншому. Наприклад, ви можете отримати блокування під час вебзапиту і захотіти звільнити його наприкінці завдання (job) у черзі, яке ініціюється цим запитом. У такому сценарії вам слід передати «токен власника» (owner token) із областю дії блокування в завдання (job) у черзі, щоб завдання могло повторно створити екземпляр блокування за допомогою цього токена.
У прикладі нижче ми відправимо завдання (job) у чергу, якщо блокування успішно отримано. Крім того, ми передамо токен власника блокування у завдання (job) через метод owner блокування:
$podcast = Podcast::find($id);
$lock = Cache::lock('processing', 120);
if ($lock->get()) {
ProcessPodcast::dispatch($podcast, $lock->owner());
}
У завданні (job) ProcessPodcast нашого застосунку ми можемо відновити і звільнити блокування за допомогою токена власника:
Cache::restoreLock('processing', $this->owner)->release();
Якщо ви хочете звільнити блокування без урахування його поточного власника, ви можете скористатися методом forceRelease:
Cache::lock('processing')->forceRelease();
Оновлення блокувань
Якщо вам потрібно продовжити термін дії блокування, яким ви наразі володієте, ви можете скористатися методом refresh. Якщо кількість секунд не вказано, буде використано початкову тривалість блокування. Це корисно для тривалих операцій, коли ви віддаєте перевагу отриманню короткого блокування з періодичним його продовженням замість отримання блокування з дуже довгим терміном дії:
$lock = Cache::lock('generate-reports', 60);
if ($lock->get()) {
foreach ($reports as $report) {
$report->generate();
// Extend the lock for another 60 seconds...
$lock->refresh();
}
$lock->release();
}
Обмеження паралельності
Функціональність атомарних блокувань Laravel також надає кілька способів обмежити паралельне виконання замикань. Використовуйте withoutOverlapping, коли хочете дозволити лише один запущений екземпляр у межах усієї вашої інфраструктури:
Cache::withoutOverlapping('foo', function () {
// Lock acquired after waiting a maximum of 10 seconds...
});
За замовчуванням блокування утримується, доки замикання не завершить виконання, а метод чекає на отримання блокування до 10 секунд. Ви можете налаштувати ці значення за допомогою додаткових аргументів:
Cache::withoutOverlapping('foo', function () {
// Lock acquired for 120 seconds after waiting a maximum of 5 seconds...
}, lockFor: 120, waitFor: 5);
Якщо блокування не вдається отримати протягом указаного часу очікування, буде викинуто виняток Illuminate\Contracts\Cache\LockTimeoutException.
Якщо вам потрібна контрольована паралельність, скористайтеся методом funnel, щоб задати максимальну кількість одночасних виконань. Метод funnel працює з будь-яким драйвером кешу, що підтримує блокування:
Cache::funnel('foo')
->limit(3)
->releaseAfter(60)
->block(10)
->then(function () {
// Concurrency lock acquired...
}, function () {
// Could not acquire concurrency lock...
});
Ключ funnel ідентифікує ресурс, який обмежується. Метод limit визначає максимальну кількість одночасних виконань. Метод releaseAfter задає запобіжний таймаут у секундах, після якого отриманий слот автоматично звільняється. Метод block задає, скільки секунд чекати на доступний слот.
Якщо ви віддаєте перевагу обробці таймауту через винятки замість надання замикання для випадку невдачі, ви можете опустити друге замикання. Буде викинуто виняток Illuminate\Cache\Limiters\LimiterTimeoutException, якщо блокування не вдасться отримати протягом указаного часу очікування:
use Illuminate\Cache\Limiters\LimiterTimeoutException;
try {
Cache::funnel('foo')
->limit(3)
->releaseAfter(60)
->block(10)
->then(function () {
// Concurrency lock acquired...
});
} catch (LimiterTimeoutException $e) {
// Unable to acquire concurrency lock...
}
Якщо ви хочете використати конкретне сховище кешу для обмежувача паралельності, ви можете викликати метод funnel на потрібному сховищі:
Cache::store('redis')->funnel('foo')
->limit(3)
->block(10)
->then(function () {
// Concurrency lock acquired using the "redis" store...
});
Зверніть увагу Метод
funnelвимагає, щоб сховище кешу реалізовувало інтерфейсIlluminate\Contracts\Cache\LockProvider. Якщо ви спробуєте використатиfunnelзі сховищем кешу, яке не підтримує блокування, буде викинуто винятокBadMethodCallException.
Failover кешу
Драйвер кешу failover надає функціональність автоматичного перемикання при відмові під час взаємодії з кешем. Якщо основне сховище кешу у сховищі failover з будь-якої причини відмовляє, Laravel автоматично спробує використати наступне сконфігуроване сховище зі списку. Це особливо корисно для забезпечення високої доступності у продакшн-середовищах, де надійність кешу критична.
Щоб налаштувати failover-сховище кешу, вкажіть драйвер failover і надайте масив імен сховищ, які слід пробувати по черзі. За замовчуванням Laravel включає приклад конфігурації failover у конфігураційний файл config/cache.php вашого застосунку:
'failover' => [
'driver' => 'failover',
'stores' => [
'database',
'array',
],
],
Після того як ви налаштували сховище, що використовує драйвер failover, вам потрібно встановити failover-сховище як сховище кешу за замовчуванням у файлі .env вашого застосунку, щоб скористатися функціональністю failover:
CACHE_STORE=failover
Коли операція зі сховищем кешу зазнає невдачі й активується failover, Laravel відправить подію Illuminate\Cache\Events\CacheFailedOver, що дозволяє вам звітувати або логувати те, що сховище кешу відмовило.
Додавання власних драйверів кешу
Написання драйвера
Щоб створити наш власний драйвер кешу, спершу нам потрібно реалізувати контракт Illuminate\Contracts\Cache\Store. Отже, реалізація кешу на MongoDB могла б виглядати приблизно так:
<?php
namespace App\Extensions;
use Illuminate\Contracts\Cache\Store;
class MongoStore implements Store
{
public function get($key) {}
public function many(array $keys) {}
public function put($key, $value, $seconds) {}
public function putMany(array $values, $seconds) {}
public function increment($key, $value = 1) {}
public function decrement($key, $value = 1) {}
public function forever($key, $value) {}
public function forget($key) {}
public function flush() {}
public function getPrefix() {}
}
Нам просто потрібно реалізувати кожен із цих методів, використовуючи зʼєднання з MongoDB. Приклад того, як реалізувати кожен із цих методів, дивіться в класі Illuminate\Cache\MemcachedStore у вихідному коді фреймворку Laravel. Щойно наша реалізація буде завершена, ми можемо завершити реєстрацію нашого власного драйвера, викликавши метод extend фасада Cache:
Cache::extend('mongo', function (Application $app) {
return Cache::repository(new MongoStore);
});
Зверніть увагу Якщо вам цікаво, куди помістити код вашого власного драйвера кешу, ви можете створити простір імен
Extensionsусередині каталогуapp. Однак памʼятайте, що Laravel не має жорсткої структури застосунку, і ви вільні організовувати свій застосунок відповідно до власних уподобань.
Реєстрація драйвера
Щоб зареєструвати власний драйвер кешу в Laravel, ми скористаємося методом extend фасада Cache. Оскільки інші сервіс-провайдери можуть намагатися читати кешовані значення у своєму методі boot, ми зареєструємо наш власний драйвер усередині колбека booting. Використовуючи колбек booting, ми можемо гарантувати, що власний драйвер буде зареєстровано безпосередньо перед викликом методу boot на сервіс-провайдерах нашого застосунку, але після виклику методу register на всіх сервіс-провайдерах. Ми зареєструємо наш колбек booting усередині методу register класу App\Providers\AppServiceProvider нашого застосунку:
<?php
namespace App\Providers;
use App\Extensions\MongoStore;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
$this->app->booting(function () {
Cache::extend('mongo', function (Application $app) {
return Cache::repository(new MongoStore);
});
});
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
// ...
}
}
Перший аргумент, переданий у метод extend, — це імʼя драйвера. Воно відповідатиме вашій опції driver у конфігураційному файлі config/cache.php. Другий аргумент — це замикання, яке має повертати екземпляр Illuminate\Cache\Repository. У замикання буде передано екземпляр $app, який є екземпляром контейнера сервісів.
Щойно ваше розширення зареєстроване, оновіть змінну середовища CACHE_STORE або опцію default у конфігураційному файлі config/cache.php вашого застосунку на імʼя вашого розширення.
Події
Щоб виконувати код під час кожної операції з кешем, ви можете слухати різні події, які відправляє кеш:
| Імʼя події |
|---|
Illuminate\Cache\Events\CacheFlushed |
Illuminate\Cache\Events\CacheFlushing |
Illuminate\Cache\Events\CacheFlushFailed |
Illuminate\Cache\Events\CacheLocksFlushed |
Illuminate\Cache\Events\CacheLocksFlushing |
Illuminate\Cache\Events\CacheLocksFlushFailed |
Illuminate\Cache\Events\CacheHit |
Illuminate\Cache\Events\CacheMissed |
Illuminate\Cache\Events\ForgettingKey |
Illuminate\Cache\Events\KeyForgetFailed |
Illuminate\Cache\Events\KeyForgotten |
Illuminate\Cache\Events\KeyWriteFailed |
Illuminate\Cache\Events\KeyWritten |
Illuminate\Cache\Events\RetrievingKey |
Illuminate\Cache\Events\RetrievingManyKeys |
Illuminate\Cache\Events\WritingKey |
Illuminate\Cache\Events\WritingManyKeys |
Щоб підвищити продуктивність, ви можете вимкнути події кешу, встановивши конфігураційну опцію events у false для конкретного сховища кешу в конфігураційному файлі config/cache.php вашого застосунку:
'database' => [
'driver' => 'database',
// ...
'events' => false,
],
Виправити терміни, дописати розділ або взяти нову главу може кожен. Термінологію узгоджуємо в глосарії, щоб переклад лишався однорідним.