Кэширование фрагментов

Кэширование фрагментов относится к кешированию фрагмента веб-страницы. Например, если страница отображает сводку годовой продажи в таблице, эту таблицу можно сохранить в кеше, чтобы исключить время, необходимое для создания этой таблицы для каждого запроса. Кэширование фрагментов строится поверх кэширования данных.

Чтобы использовать кеширование фрагментов, используйте следующую конструкцию в представлении:

if ($this->beginCache($id)) {

    // ... generate content here ...

    $this->endCache();
}

То есть, приложите логику генерации контента в паре вызовов beginCache() и endCache(). Если содержимое найдено в кэше, beginCache() отобразит кэшированный контент и возвратит false, таким образом пропустив логику генерации содержимого. В противном случае будет вызвана ваша логика генерации контента, и когда вызывается endCache(), сгенерированный контент будет захвачен и сохранен в кеше.

Подобно кэшированию данных, уникальный идентификатор $id необходим для идентификации кэша содержимого.

Параметры кеширования

Вы можете указать дополнительные параметры кэширования фрагментов, передав массив параметров в качестве второго параметра метода beginCache(). За сценой этот массив параметров будет использоваться для настройки виджета yii\widgets\FragmentCache, который реализует функциональность фактического кэширования фрагментов.

Продолжительность

Возможно, наиболее часто используемым вариантом кэширования фрагментов является продолжительность. Он определяет, сколько секунд содержимое может оставаться в кеше. Следующий код кэширует фрагмент контента не более одного часа:

if ($this->beginCache($id, ['duration' => 3600])) {

    // ... generate content here ...

    $this->endCache();
}

Если этот параметр не установлен, значение по умолчанию будет равно 60, что означает, что кешированный контент будет истекать через 60 секунд.

Зависимости

Подобно кэшированию данных, фрагмент содержимого, кэшируемый, также может иметь зависимости. Например, содержание отображаемой записи зависит от того, была ли изменена запись.

Чтобы указать зависимость, установите параметр зависимости, который может быть либо объектом yii\caching\Dependency, либо массивом конфигурации для создания объекта зависимости. Следующий код указывает, что содержание фрагмента зависит от изменения значения column_at:

$dependency = [
    'class' => 'yii\caching\DbDependency',
    'sql' => 'SELECT MAX(updated_at) FROM post',
];

if ($this->beginCache($id, ['dependency' => $dependency])) {

    // ... generate content here ...

    $this->endCache();
}

Варианты

Содержимое, которое кэшируется, может изменяться в соответствии с некоторыми параметрами. Например, для веб-приложения, поддерживающего несколько языков, один и тот же фрагмент кода представления может генерировать контент на разных языках. Поэтому вы можете захотеть изменить содержимое кэша в соответствии с текущим языком приложения.

Чтобы указать варианты кэширования, установите параметр вариантов, который должен быть массивом скалярных значений, каждый из которых представляет конкретный фактор изменения. Например, чтобы сделать кешированное содержимое измененным по языку, вы можете использовать следующий код:

if ($this->beginCache($id, ['variations' => [Yii::$app->language]])) {

    // ... generate content here ...

    $this->endCache();
}

Переключение кеширования

Иногда вам может понадобиться включить кэширование фрагментов только при выполнении определенных условий. Например, для страницы, отображающей форму, вам нужно только кэшировать форму, когда она изначально запрашивается (с помощью запроса GET). Любое последующее отображение (через запрос POST) формы не должно кэшироваться, поскольку форма может содержать ввод пользователя. Для этого вы можете установить разрешенную опцию, например:

if ($this->beginCache($id, ['enabled' => Yii::$app->request->isGet])) {

    // ... generate content here ...

    $this->endCache();
}

Вложенное кэширование

Кэширование фрагментов может быть вложенным. То есть, кэшированный фрагмент может быть заключен в другой фрагмент, который также кэшируется. Например, комментарии кэшируются во внутреннем кэше фрагментов и кэшируются вместе с содержимым сообщения во внешнем кэше фрагментов. Следующий код показывает, как два кэша фрагментов могут быть вложены:

if ($this->beginCache($id1)) {

    // ...content generation logic...

    if ($this->beginCache($id2, $options2)) {

        // ...content generation logic...

        $this->endCache();
    }

    // ...content generation logic...

    $this->endCache();
}

Для вложенных кэшей могут быть заданы различные параметры кэширования. Например, внутренние кэши и внешние кэши могут использовать разные значения продолжительности кэша. Даже когда данные, кэшированные во внешнем кэше, становятся недействительными, внутренний кеш может все еще предоставлять действительный внутренний фрагмент. Однако это не так. Если внешний кеш оценивается как действительный, он будет продолжать предоставлять такую же кэшированную копию даже после того, как содержимое во внутреннем кэше будет аннулировано. Поэтому вы должны быть осторожны при настройке длительности или зависимостей вложенных кэшей, иначе устаревшие внутренние фрагменты могут храниться во внешнем фрагменте.

Динамическое содержимое

При использовании кэширования фрагментов вы можете столкнуться с ситуацией, когда большой фрагмент содержимого является относительно статическим, за исключением одного или нескольких мест. Например, заголовок страницы может отображать панель главного меню вместе с именем текущего пользователя. Другая проблема заключается в том, что содержимое, которое кэшируется, может содержать PHP-код, который должен быть выполнен для каждого запроса (например, код для регистрации комплекта активов). Обе проблемы могут быть решены с помощью так называемой функции динамического контента.

Динамический контент означает фрагмент вывода, который не следует кэшировать, даже если он заключен в кеш фрагментов. Чтобы сделать контент динамичным все время, он должен быть сгенерирован путем выполнения некоторого кода PHP для каждого запроса, даже если содержимое содержимого будет обслуживаться из кэша.

Вы можете вызвать yii\base\View::renderDynamic() внутри кэшированного фрагмента, чтобы вставить динамический контент в нужное место, например:

if ($this->beginCache($id1)) {

    // ...content generation logic...

    echo $this->renderDynamic('return Yii::$app->user->identity->name;');

    // ...content generation logic...

    $this->endCache();
}

В методе renderDynamic() в качестве параметра берется часть кода PHP. Возвращаемое значение кода PHP рассматривается как динамическое содержимое. Тот же PHP-код будет выполняться для каждого запроса, независимо от того, обслуживается ли вложенный фрагмент из кэшированного или нет.