Битрикс. Управляемый кеш
05.11.2018
Теги: CMS • Web-разработка • Битрикс • Кеширование
Кеш имеет определенный период жизни и какой-то идентификатор — нечто, что уникально идентифицирует именно эту совокупность данных. Пока период жизни кеша не истек — нужно обращаться к кешу, а после истечения срока жизни кеша нужно снова получить данные из БД и сохранить на указанный период.
Суть управляемого кеша в том, чтобы пометить какой-то кеш какой-то меткой и иметь возможность по тегу управлять этим кешем (в основном для очистки). Т.е. помимо идентификатора, кеш может быть идентифицирован и по тегу. Один и тот же кеш может иметь разные теги, а один и тот же тег может быть назначен разным кешам. Таким образом, имея какой-то тег, можно почистить все кеши, связанные с данным тегом.
Работа с управляемым кешем состоит из 3-х операций:
- Cвязь объекта кеша с директорией хранения кеша
- Задание одного или нескольких тегов
- Очистка кеша по тегу
Для начала нужно включить механизм управляемого кеширования. Определяем в dbconn.php
константу:
define('BX_COMP_MANAGED_CACHE', true);
И проверим, что механизм теперь работает:
if (defined('BX_COMP_MANAGED_CACHE')) { ShowNote('Управляемый кеш включен'); } else { ShowError('Управляемый кеш не включен'); }
За работу кеша отвечает глобальный объект $CACHE_MANAGER
, который является экземпляром класса CCacheManager
:
// тип инфоблока, откуда будем получать элементы $iblockType = ARTICLES_IBLOCK_TYPE; // идентификатор инфоблока, откуда будем получать элементы $iblockId = ARTICLES_IBLOCK_ID; // символьный код инфоблока, откуда будем получать элементы $iblockCode = ARTICLES_IBLOCK_CODE; // условия выборки элементов инфоблока с помощью метода ElementTable::getList() $getListParams = array( 'select' => array('ID', 'NAME', 'CODE', 'PREVIEW_TEXT'), 'filter' => array('=IBLOCK_ID' => $iblockId), 'limit' => 3 ); // уникальный идентификатор кеша $cacheId = md5('\\Bitrix\\Iblock\\ElementTable::getList' . serialize($getListParams)); // время жизни кеша $cacheTime = 3600; // путь к директории кеша $cachePath = '/iblock/' . $iblockType . '/' . $iblockCode; // создаем объект кеша $phpCache = new CPHPCache(); if (!$phpCache->InitCache($cacheTime, $cacheId, $cachePath)) { /* * Если кеш пустой или утратил актуальность, получаем данные из базы данных */ // Получаем CACHE_MANAGER из $GLOBALS и привязываем его к нашей директории кеша $GLOBALS['CACHE_MANAGER']->StartTagCache($cachePath); // Вешаем тег на текущий кеш. У нас тут будет выборка элементов инфоблока, // поэтому имеет смысл зарегистрировать тег, зависящий от ID инфоблока $GLOBALS['CACHE_MANAGER']->RegisterTag('iblock_id_' . $iblockId); // Делаем выборку из базы данных элементов инфоблока $result = \Bitrix\Iblock\ElementTable::getList($getListParams); while ($arItem = $result->fetch()) { $arResult['ITEMS'][] = $arItem; // Можно пометить кеш тегами всех выбранных элементов инфоблока $GLOBALS['CACHE_MANAGER']->RegisterTag('article_id_' . $arItem['ID']); } // Можно повесить и какой-то другой (более понятный) тег с говорящим именем $GLOBALS['CACHE_MANAGER']->RegisterTag('iblock_code_' . $iblockCode); // Завершаем тегирование кеша $GLOBALS['CACHE_MANAGER']->EndTagCache(); // После чего сохраняем результат выборки в кеш if ($phpCache->StartDataCache()) { $phpCache->EndDataCache(array('dbResult' => $arResult)); } } else { /* * Иначе, получаем данные из кеша */ $arResult = $phpCache->GetVars(); }
Выводим полученные данные:
<section> <?php foreach ($arResult['ITEMS'] as $arItem): ?> <article> <h3><?= $arItem['NAME']; ?></h3> <p><?= $arItem['PREVIEW_TEXT']; ?></p> </article> <?php endforeach; ?> <section>
Файл кеша bitrix/cache/content/articles/7c/7cb8ee7684eef61a2bf9e6abb07aca9a.php
:
<? if ($INCLUDE_FROM_CACHE!='Y') return false; $datecreate = '001541417904'; $dateexpire = '001541421504'; $ser_content = 'a:2:{s:7:"CONTENT";s:0:"";s:4:"VARS";a:1:{s:8:"dbResult";a:1:{s:5:"ITEMS";a:3:{i:0;a:4:{s:2:"ID"; s:3:"347";s:4:"NAME";s:35:"Английский бульдог";s:4:"CODE";s:17:"angliyskiy-buldog";s:12:"PREVIEW_TEXT";s:665:"По названию («bull» переводится «бык», «dog» — собака) понятно, что бульдог был предназначен для травли быков. Это зрелище со времён Рима было очень популярно в Европе вплоть до начала девятнадцатого столетия. По вышедшему в Англии в 1835 году закону были запрещены все бои, в которых участвовали животные. В связи с этим количество бульдогов в стране резко сократилось.";}i:1;a:4:{s:2:"ID";s:3:"348";s:4:"NAME";s:16:"Далматин";s:4:"CODE"; s:8:"dalmatin";s:12:"PREVIEW_TEXT";s:566:"О точном происхождении далматинов известно мало. Считается, что их родиной была Далмация, область Балканского полуострова, в честь которой, собственно, и была названа порода, существующая уже больше двух тысячелетий. Собаки, напоминающие далматинов, украшают древние египетские барельефы и греческие фрески.";}i:2;a:4:{s:2:"ID";s:3:"349";s:4:"NAME";s:31:"Афганская борзая";s:4:"CODE";s:18: "afganskaya-borzaya";s:12:"PREVIEW_TEXT";s:565:"Изящная красавица с длинной развевающейся на бегу шелковистой шерстью, афганская борзая, полна энергии и готова каждую минуту стремительно мчаться наперегонки с ветром. Наблюдая за её необычайно грациозными движениями, нетрудно представить себе такой элегантный силуэт на фоне бескрайней азиатской степи.";}}}}}'; return true; ?>
В результате работы приведенного выше кода мы закешируем выборку элементов инфоблока. Сформированный кеш будет находиться в директории bitrix/cache/content/articles
, и этот кеш будет помечен тегами iblock_id_5
и iblock_code_articles
, а также набором тегов, зависящих от идентификатора элемента, т.е. article_id_347
, article_id_348
, article_id_349
.
Осталось прикрутить возможность очистки данного кеша. В нашем примере кеш устаревает сразу же при изменении любого элемента инфоблока. Соответственно, при изменении, удалении или добавлении какого-либо элемента нам нужно кеш очищать. Для этого создадим обработчики для этих событий и будем очищать кеш по любому из ранее заданных тегов:
<?php /* * Файл local/php_interface/init.php */ define('ARTICLES_IBLOCK_TYPE', 'content'); define('ARTICLES_IBLOCK_ID', 5); define('ARTICLES_IBLOCK_CODE', 'articles'); // регистрируем три обработчика событий AddEventHandler( // при добавлении элемента 'iblock', 'OnAfterIBlockElementAdd', array( 'IblockElementEventHandler', 'OnAfterIBlockElementAdd' ) ); AddEventHandler( // при изменении элемента 'iblock', 'OnAfterIBlockElementUpdate', array( 'IblockElementEventHandler', 'OnAfterIBlockElementUpdate' ) ); AddEventHandler( // при удалении элемента 'iblock', 'OnAfterIBlockElementDelete', array( 'IblockElementEventHandler', 'OnAfterIBlockElementDelete' ) ); class IblockElementEventHandler { // создаем обработчик события OnAfterIBlockElementAdd function OnAfterIBlockElementAdd(&$arFields) { \Bitrix\Main\Diag\Debug::writeToFile( 'Добавлен новый элемент с идентификатором ' . $arFields['ID'] ); if (defined('BX_COMP_MANAGED_CACHE')) { $GLOBALS['CACHE_MANAGER']->ClearByTag('iblock_id_' . ARTICLES_IBLOCK_ID); // $GLOBALS['CACHE_MANAGER']->ClearByTag('iblock_code_' . ARTICLES_IBLOCK_CODE); } } // создаем обработчик события OnAfterIBlockElementUpdate function OnAfterIBlockElementUpdate(&$arFields) { \Bitrix\Main\Diag\Debug::writeToFile( 'Элемент с идентификатором ' . $arFields['ID'] . ' был изменен' ); if (defined('BX_COMP_MANAGED_CACHE')) { $GLOBALS['CACHE_MANAGER']->ClearByTag('iblock_id_' . ARTICLES_IBLOCK_ID); // $GLOBALS['CACHE_MANAGER']->ClearByTag('iblock_code_' . ARTICLES_IBLOCK_CODE); } } // создаем обработчик события OnAfterIBlockElementDelete function OnAfterIBlockElementDelete(&$arFields) { \Bitrix\Main\Diag\Debug::writeToFile( 'Удален элемент инфоблока с идентификатором ' . $arFields['ID'] ); if (defined('BX_COMP_MANAGED_CACHE')) { $GLOBALS['CACHE_MANAGER']->ClearByTag('iblock_id_' . ARTICLES_IBLOCK_ID); // $GLOBALS['CACHE_MANAGER']->ClearByTag('iblock_code_' . ARTICLES_IBLOCK_CODE); } } }
Привязка тега кеша к директории кеша хранится в таблице b_cache_tag
базы данных. После создания кеша в ней будут такие записи:
SITE_ID CACHE_SALT RELATIVE_PATH TAG ------------------------------------------------------------------- NULL NULL 0:1541594962 ** s1 /464 /iblock/content/articles iblock_id_5 s1 /464 /iblock/content/articles iblock_code_articles s1 /464 /iblock/content/articles article_id_347 s1 /464 /iblock/content/articles article_id_348 s1 /464 /iblock/content/articles article_id_349
Если мы зайдем теперь в панель управления и отредактируем (создадим, удалим) элемент инфоблока, директория хранения кеша будет переименована:
/bitrix/cache/iblock/content/articles.~539735
А в таблице таблице b_cache_tag
теперь будут записи:
SITE_ID CACHE_SALT RELATIVE_PATH TAG ----------------------------------------------------------------------- NULL NULL 2:1541595584 ** * * /bitrix/cache/iblock/content/articles.~539735 * * * /bitrix/managed_cache/MYSQL/agents.~139166 *
В файле лога __bx_log.log
появятся записи:
Элемент с идентификатором 354 был изменен Добавлен новый элемент с идентификатором 357 Удален элемент инфоблока с идентификатором 357
Кеширование в нативных компонентах, использующих инфоблоки
Управляемый кеш обеспечивает обновление кеша нативных компонентов Битрикс, использующих инфоблоки. Реализация крайне проста — в ядре, внутри методов CIBlockResult::Fetch()
и CIBlockResult::GetNext()
(для элементов и разделов) спрятана регистрация тега вида
'iblock_id_' . $res['IBLOCK_ID']
Соответственно, если компонент использует автокеширование, то при вызове Fetch()
или GetNext()
будет зарегистрирован кеш с идентификатором инфоблока. А уже внутри методов Add()
, Update()
и Delete()
для разделов и элементов спрятаны вызовы очистки кешей, связанных с этим тегом.
Соответственно, даже если компонент закеширован на год, то при обновлении элементов или разделов — кеш будет сброшен, и на сайте будут всегда актуальные данные.
Поиск: CMS • Web-разработка • Битрикс • Кeширование • CACHE_MANAGER • CCacheManager • CPHPCache • InitCache • StartTagCache • RegisterTag • EndTagCache • ClearByTag • StartDataCache • EndDataCache • ElementTable::getList • Инфоблок • AddEventHandler • OnAfterIBlockElementAdd • OnAfterIBlockElementUpdate • OnAfterIBlockElementDelete • BX_COMP_MANAGED_CACHE • Событие