Настройка
Laravel предоставляет выразительный, универсальный API для различных систем кэширования. Настройки кэша находятся в файле config/cache.php. Здесь вы можете указать драйвер, используемый по умолчанию в вашем приложении. Laravel изначально поддерживает многие популярные системы, такие как Memcached и Redis.
Этот файл также содержит множество других настроек, которые в нём же документированы, поэтому обязательно ознакомьтесь с ними. По умолчанию, Laravel настроен для использования драйвера file, который хранит сериализованные объекты кэша в файловой системе. Для больших приложений рекомендуется использование более надёжных драйверов, таких как Memcached или Redis. Вы можете настроить даже несколько конфигураций кэширования для одного драйвера.
Необходимые условия для драйверов
Перед использованием драйвера database вам нужно создать таблицу для хранения элементов кэша. Ниже приведён пример объявления структуры Schema:
Schema::create('cache', function ($table) {
$table->string('key')->unique();
$table->text('value');
$table->integer('expiration');
});
Для использования системы кэширования Memcached необходим установленный пакет Memcached PECL. Вы можете перечислить все свои сервера Memcached в файле настроек config/cache.php:
'memcached' => [
[
'host' => '127.0.0.1',
'port' => 11211,
'weight' => 100
],
],
Вы также можете задать параметр host для пути UNIX-сокета. В этом случае в параметр port следует записать значение 0:
'memcached' => [
[
'host' => '/var/run/memcached/memcached.sock',
'port' => 0,
'weight' => 100
],
],
Перед тем, как использовать систему Redis необходимо установить пакет predis/predis (~1.0) с помощью Composer.
Загляните в раздел по настройке Redis
Использование кэша
Получение экземпляра кэша
Контракты Illuminate\Contracts\Cache\Factory и Illuminate\Contracts\Cache\Repository предоставляют доступ к службам кэша Laravel. Контракт Factory предоставляет доступ ко всем драйверам кэша, определённым для вашего приложения. А контракт Repository обычно является реализацией драйвера кэша по умолчанию для вашего приложения, который задан в файле настроек cache.
А также вы можете использовать фасад Cache, который мы будем использовать в данной статье. Фасад Cache обеспечивает удобный и лаконичный способ доступа к лежащим в его основе реализациям контрактов кэша Laravel:
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Cache;
//для версии 5.2 и ранее:
//use Cache;
class UserController extends Controller
{
/**
* Вывод списка всех пользователей приложения.
*
* @return Response
*/
public function index()
{
$value = Cache::get('key');
//
}
}
В этом примере для версии 5.1 и ранее использовался ещё один контроллер PHPuse Illuminate\Routing\Controller;
— прим. пер.
Доступ к нескольким хранилищам кэша
Используя фасад Cache можно обращаться к разным хранилищам кэша с помощью метода PHPstore()
. Передаваемый в метод ключ должен соответствовать одному из хранилищ, перечисленных в массиве stores в вашем файле настроек cache:
$value = Cache::store('file')->get('foo');
Cache::store('redis')->put('bar', 'baz', 10);
Получение элементов из кэша
Для получения элементов из кэша используется метод PHPget()
фасада Cache. Если элемента в кэше не существует, будет возвращён PHPnull
. При желании вы можете указать другое возвращаемое значение, передав его вторым аргументом метода PHPget()
:
$value = Cache::get('key');
$value = Cache::get('key', 'default');
А также вы можете передать замыкание в качестве значения по умолчанию. Тогда, если элемента не существует, будет возвращён результат замыкания. С помощью замыкания вы можете настроить получение значений по умолчанию из базы данных или внешнего сервиса:
$value = Cache::get('key', function () {
return DB::table(...)->get();
});
Проверка существования элемента
Для определения существования элемента в кэше используется метод PHPhas()
. Он вернёт PHPfalse
, если значение равно PHPnull
:
if (Cache::has('key')) {
//
}
Увеличение/уменьшение значений
Для изменения числовых элементов кэша используются методы PHPincrement()
и PHPdecrement()
. Оба они могут принимать второй необязательный аргумент, определяющий значение, на которое нужно изменить значение элемента:
Cache::increment('key');
Cache::increment('key', $amount);
Cache::decrement('key');
Cache::decrement('key', $amount);
Иногда необходимо получить элемент из кэша и при этом сохранить значение по умолчанию, если запрашиваемый элемент не существует. Например, когда необходимо получить всех пользователей из кэша, а если они не существуют, получить их из базы данных и добавить в кэш. Это можно сделать с помощью метода PHPCache::remember()
:
$value = Cache::remember('users', $minutes, function () {
return DB::table('users')->get();
});
Если элемента нет в кэше, будет выполнено переданное в метод PHPremember()
замыкание, а его результат будет помещён в кэш.
При необходимости получить элемент и удалить его из кэша используется метод PHPpull()
. Как и метод PHPget()
, данный метод вернёт PHPnull
, если элемента не существует:
$value = Cache::pull('key');
Сохранение элементов в кэш
Для помещения элементов в кэш используется метод PHPput()
фасада Cache. При помещении элемента в кэш необходимо указать, сколько минут его необходимо хранить:
Cache::put('key', 'value', $minutes);
Вместо указания количества минут, можно передать экземпляр PHP-типа PHPDateTime
, для указания времени истечения срока хранения:
$expiresAt = Carbon::now()->addMinutes(10);
Cache::put('key', 'value', $expiresAt);
Метод PHPadd()
просто добавит элемент в кэш, если его там ещё нет. Метод вернёт true, если элемент действительно будет добавлен в кэш. Иначе — false:
Cache::add('key', 'value', $minutes);
Для бесконечного хранения элемента кэша используется метод PHPforever()
. Поскольку срок хранения таких элементов не истечёт никогда, они должны удаляться из кэша вручную с помощью метода PHPforget()
:
Cache::forever('key', 'value');
При использовании драйвера Memcached элементы, сохранённые «навсегда», могут быть удалены, когда размер кэша достигнет своего лимита.
Удаление элементов из кэша
Можно удалить элементы из кэша с помощью метода PHPforget()
:
Cache::forget('key');
Вы можете очистить весь кэш методом PHPflush()
:
Cache::flush();
Очистка не поддерживает префикс кэша и удаляет из него все элементы. Учитывайте это при очистке кэша, которым пользуются другие приложения.
добавлено в 5.3 ()
Вспомогательная функция PHPCache()
Помимо использования фасада Cache или контракта кэша, вы также можете использовать глобальную функцию PHPcache()
для получения данных из кэша и помещения данных в него. При вызове функции PHPcache()
с одним строковым аргументом она вернёт значение данного ключа:
$value = cache('key');
Если вы передадите в функцию массив пар ключ/значение и время хранения, она сохранит значения в кэше на указанное время:
cache(['key' => 'value'], $minutes);
cache(['key' => 'value'], Carbon::now()->addSeconds(10));
При тестировании вызова глобальной функции PHPcache()
вы можете использовать метод PHPCache::shouldReceive()
, как при тестировании фасада.
Теги кэша
Теги кэша не поддерживаются драйверами file и database. Кроме того, при использовании нескольких тегов для кэшей, хранящихся «вечно», лучшая производительность будет достигнута при использовании такого драйвера как memcached, который автоматически зачищает устаревшие записи.
Сохранение элементов с тегами
Теги кэша позволяют отмечать связанные элементы в кэше, и затем сбрасывать все элементы, которые были отмеченны одним тегом. Вы можете обращаться к кэшу с тегами, передавая упорядоченный массив имён тегов. Например, давайте обратимся к кэшу с тегами и поместим в него значение методом PHPput()
:
Cache::tags(['people', 'artists'])->put('John', $john, $minutes);
Cache::tags(['people', 'authors'])->put('Anne', $anne, $minutes);
Обращение к элементам кэша с тегами
Для получения элемента с тегом передайте тот же упорядоченный список тегов в метод PHPtags()
, а затем вызовите метод PHPget()
с тем ключом, который необходимо получить:
$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();
Добавление своих драйверов кэша
Написание драйвера
Чтобы создать свой драйвер кэша, нам надо сначала реализовать контракт Illuminate\Contracts\Cache\Store. Итак, наша реализация кэша MongoDB будет выглядеть примерно так:
добавлено в 5.3 ()
<?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, $minutes) {}
public function putMany(array $values, $minutes);
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() {}
}
<?php
namespace App\Extensions;
class MongoStore implements \Illuminate\Contracts\Cache\Store
{
public function get($key) {}
public function put($key, $value, $minutes) {}
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 в исходном коде фреймворка. Когда наша реализация готова, мы можем завершить регистрацию нашего драйвера:
Cache::extend('mongo', function ($app) {
return Cache::repository(new MongoStore);
});
Если вы задумались о том, где разместить код вашего драйвера, то можете создать пространство имён Extensions в папке app. Но не забывайте, в Laravel нет жёсткой структуры приложения, и вы можете организовать его как пожелаете.
Регистрация драйвера
Чтобы зарегистрировать свой драйвер кэша в Laravel, мы будем использовать метод PHPextend()
фасада Cache. Вызов PHPCache::extend()
можно делать из метода PHPboot()
сервис-провайдера по умолчанию App\Providers\AppServiceProvider, который есть в каждом Laravel-приложении. Или вы можете создать свой сервис-провайдер для размещения расширения — только не забудьте зарегистрировать его в массиве провайдеров config/app.php:
<?php
namespace App\Providers;
use App\Extensions\MongoStore;
use Illuminate\Support\Facades\Cache;
//для версии 5.2 и ранее:
//use Cache;
use Illuminate\Support\ServiceProvider;
class CacheServiceProvider extends ServiceProvider
{
/**
* Выполнение после-регистрационной загрузки сервисов.
*
* @return void
*/
public function boot()
{
Cache::extend('mongo', function ($app) {
return Cache::repository(new MongoStore);
});
}
/**
* Регистрация привязок в контейнере.
*
* @return void
*/
public function register()
{
//
}
}
Первый аргумент метода PHPextend()
— имя драйвера. Оно будет соответствовать параметру driver в вашем файле настроек config/cache.php. Второй аргумент — замыкание, которое должно возвращать экземпляр Illuminate\Cache\Repository. В замыкание будет передан экземпляр PHP$app
, который является экземпляром сервис-контейнера.
Когда ваше расширение зарегистрировано, просто укажите его имя в качестве значения параметра driver в файле настроек config/cache.php.
События кэша
Для выполнения какого-либо кода при каждой операции с кэшем вы можете прослушивать события, инициируемые кэшем. Обычно вам необходимо поместить эти слушатели событий в ваш EventServiceProvider:
/**
* Отображения слушателей событий для приложения.
*
* @var array
*/
protected $listen = [
'Illuminate\Cache\Events\CacheHit' => [
'App\Listeners\LogCacheHit',
],
'Illuminate\Cache\Events\CacheMissed' => [
'App\Listeners\LogCacheMissed',
],
'Illuminate\Cache\Events\KeyForgotten' => [
'App\Listeners\LogKeyForgotten',
],
'Illuminate\Cache\Events\KeyWritten' => [
'App\Listeners\LogKeyWritten',
],
];
Для выполнения какого-либо кода при каждой операции с кэшем вы можете прослушивать события, инициируемые кэшем. Обычно вам необходимо поместить эти слушатели событий в метод PHPboot()
вашего EventServiceProvider:
/**
* Регистрация любых других событий для вашего приложения.
*
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function boot(DispatcherContract $events)
{
parent::boot($events);
$events->listen('cache.hit', function ($key, $value) {
//
});
$events->listen('cache.missed', function ($key) {
//
});
$events->listen('cache.write', function ($key, $value, $minutes) {
//
});
$events->listen('cache.delete', function ($key) {
//
});
}