Подробнее об этом можно почитать тут, а в этой заметке, я приведу несколько практических приемов работы с кэшем.
Общий кэш для backend и frontend.
По-умолчанию кэш в Yii2 (Advanced) сохраняется в виде файла в папки:- backend\runtime\cache;
- frontend\runtime\cache.
Yii::$app->cache
на экран. Чтобы иметь возможность работать с кэшем другого приложения (например из backend удалить кэш frontendа) можно указать для этих приложений общее хранилище в конфигурации. Например сделаем, чтобы backend хранил свой кэш там же где и frontend.
В файле common\config\main.php нужно дописать строку с "cachePath":
'components' => [ 'cache' => [ 'class' => 'yii\caching\FileCache', 'cachePath' => '@frontend/runtime/cache', ],
Кэш в базе данных, миграция.
Среди вариантов выбора мест хранения кэша, есть такой как хранение его в базе данных. Для этого необходимо указать в все том же файле common\config\main.php класс работающий с БД:'components' => [ 'cache' => [ 'class' => 'yii\caching\DbCache', ],Чтобы использовать этот кэш, нужно создать таблицу определенным образом. Если пользуетесь миграциями при работе с БД, или по-крайней мере умеете их запускать, вот готовый код миграции создающей такую таблицу:
public function safeUp() { $tableOptions = null; if ($this->db->driverName === 'mysql') { $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; } $this->createTable('{{%cache}}', [ 'id' => $this->primaryKey(), 'expire' => $this->integer(11), 'data' => $this->text(), ], $tableOptions); } public function safeDown() { $this->dropTable('{{%cache}}'); }
Автоматическое удаление кэша при обновлении записи в базе данных.
При внесении изменений в БД (например редактирование поста в админке), данные в кэше становятся не актуальными. Использование зависимостей (dependency) не всегда помогает (например если запись была изменена, а не добавлена). В этом случае можно к модели, которая отвечает за нужную таблицу используемую в кэшировании (например виджета), подключить поведение с событиями для ActiveRecord:EVENT_AFTER_INSERT
EVENT_AFTER_UPDATE
EVENT_AFTER_DELETE
которые при каждом срабатывании будут удалять нужный кэш. Для того, чтобы удалить кэш frontenda из админки, используется общее хранилище кэша для backend и frontend (как сделать - читать выше).
Создаем файл CachedBehavior.php в папке common\components\behaviors
<?php namespace common\components\behaviors; use Yii; use yii\base\Behavior; use yii\db\ActiveRecord; class CachedBehavior extends Behavior { //id кэша - название в виде массива public $cache_id; public function events() { return [ ActiveRecord::EVENT_AFTER_INSERT => 'deleteCache', ActiveRecord::EVENT_AFTER_UPDATE => 'deleteCache', ActiveRecord::EVENT_AFTER_DELETE => 'deleteCache', ]; } public function deleteCache() { //Удаление массива кэшированных элементов (виджеты, модели...) Foreach ($this->cache_id as $id){ Yii::$app->cache->delete($id); } } }Тут мы создали класс-поведение (подробнее про поведения тут), который с помощью метода events() устанавливает обработчики событий (про события тут) для класса работающего с БД (ActiveRecord). А именно - при вставке/обновлении/удалении данных, будет вызываться метод deleteCache(), который будет удалять нужный кэш (по переданному из модели названию кэша/id).
Подключение в модели, которая обновляет данные хранимые в кэше:
public function behaviors() { parent::behaviors(); return [ 'CachedBehavior' => [ 'class' => \common\components\behaviors\CachedBehavior::className(), 'cache_id' => ['CloudWidget'], ], ]; }тут в качестве элемента массива 'cache_id' нужно передать название кэша который нужно удалить (id кэша), в данном случае 'CloudWidget'. Можно передавать несколько значений.
Автоматическое удаление кэша при выполнении действий контроллера.
Если вы выполняете действия контроллера которые делают неактуальными файлы в кэше, стоит настроить автоматическое удаление таких файлов. Например в админке удаляете пост (действие actionDelete()) и желаете изменить файл карты сайта для поисковых служб, т.к. он становится неактуальным. Это можно сделать с помощью кода указанного в предыдущей главе, основываясь на событиях ActiveRecord, но данная модель с привязкой поведения используется и в frontend при выводе тех же постов, где привязка такого поведения не нужна. Поэтому есть вариант основанный на событии EVENT_BEFORE_ACTION контроллера. Причем того, который нужен - в backend.Для того, чтобы удалить кэш frontenda из админки, используется общее хранилище кэша для backend и frontend (как сделать - читать выше).
Вставляем класс поведения в backend\controllers\PostController.php
public function behaviors() { return [ //Класс удаление кэша при выполнении указанных действий [ 'class' => '\common\components\behaviors\DelcacheBehavior', 'cache_id' => ['CloudWidget'], 'actions' => ['create', 'update', 'delete'], ], ];Файл common\components\behaviors\DelcacheBehavior.php
<?php /* * Класс удаляющий кэш по переданным в массиве $cache_id названиям (id) кэша * перед выполнением указанных действий контроллера в массиве $actions */ namespace common\components\behaviors; use Yii; use yii\base\Behavior; use yii\web\Controller; class DelcacheBehavior extends Behavior { public $cache_id; //id кэша (названия в виде массива) public $actions; //для каких действий контроллера public function events() { return [ Controller::EVENT_BEFORE_ACTION => 'deleteCache', ]; } public function deleteCache() { $action_name = $this->owner->action->id; //название текущего действия if(array_search($action_name, $this->actions)=== FALSE) return; //Удаление массива кэшированных элементов (виджеты, модели...) Foreach ($this->cache_id as $id){ Yii::$app->cache->delete($id); } } }Все, файл кэша CloudWidget удален.
Примеры кэширования.
1. Кэширование фрагментов страницы.Применяется, если нужно закэшировать часть страницы, например вывод виджетов:
<?php //кеш на час if ($this->beginCache('TagListWidget', ['duration' => 3600])) { echo common\widgets\TagListWidget::widget(); $this->endCache(); } ?>
<?php //Зависимость кеша от кол-ва записей $dependency = [ 'class' => 'yii\caching\DbDependency', 'sql' => 'SELECT COUNT(*) FROM {{%comments}}', ]; if ($this->beginCache('LcommentsWidget', ['dependency' => $dependency])) { echo common\widgets\LcommentsWidget::widget(); $this->endCache(); } ?>
2. Кеширование данных (значения переменной).
$cache = Yii::$app->cache; //Кешируем массив $arr_tags if (!$arr_tags = $cache->get('TaglistWidget_init')){ //Получаем данные из таблицы (модель TagPost) $tag_post = TagPost::find() ->select('tag_id') ->where(['not',['post_id' => null]]) ->all(); $arr_tags = array(); foreach($tag_post as $tag_id){ $arr_tags[] = $tag_id->tag_id; } //Устанавливаем зависимость кеша от кол-ва записей в таблице $dependency = new \yii\caching\DbDependency(['sql' => 'SELECT COUNT(*) FROM {{%tag_post}}']); $cache->set('TaglistWidget_init', $arr_tags, null, $dependency); }
3. Кэширование запросов к БД.
Кэширование запросов может быть использовано как для DAO, так и для ActiveRecord
$result = $db->cache(function ($db) { // Результат SQL запроса будет возвращен из кэша если // кэширование запросов включено и результат запроса присутствует в кэше return $db->createCommand('SELECT * FROM customer WHERE id=1')->queryOne(); });
Не забудьте, что есть так же клиентское HTTP-кэширование и Gzip сжатие ресурсов на сервере перед отправкой клиенту. Подробнее тут.