Cache - uniqcle/Bitrix GitHub Wiki
- API Caching
CPHPCache
-
CCacheManager
(Tagged Cache) CPageCache
-
StartResultCache
- Memcached
Классы API
CPHPCache
- основной класс для кеширования PHP и HTML
CPageCache
- класс для кеширования HTML
CBitrixComponent
- класс компонента, содержащий оптимизированные методы кеширования (StartResultCache)
CCacheManager
- класс управления кешем
Cache Type
CACHE_TYPE CACHE_TIME
Неуправляемое кэш-е Y V // По времени
Кеш-е комп-в (автокеш-е) А V // По времени + настройки сайта
Управляемое кеш-е А V // Если были изменения в БД
Кеш-е меню
Для избавления от лишней нагрузки, запросы записываем в кэш с помощью класса CPHPCache
Methods
InitCache
- инициализация кеширования. Возвращает false
если нет актуального файла кеша.
StartDataCache
- старт буферизации для последующего сохранения в файл, вывод кеша
EndDataCache
- завершение буферизации, сохранение в файл кеша. Принимает массив параметров для сохранения в кеше.
GetVars
- возвращает php-переменные, сохраненные в кеше
Output
- вывод html содержимого файла кеша, если тот существует
IsCacheExpired
Проверяет истек ли период жизни кэша.
CleanDir
Метод очищает кеш по параметру basedir.
AbortDataCache
Отменяет создание текущего кэша.
$obCache = new CPHPCache(); //Объект
$cacheLifetime = $arParams['CACHE_TIME']; //Время кеширования
$cacheID = $arParams['IBLOCK_ID'] . $arParams['ELEMENT_ID']; // Уник. ID кэша
$cachePath = "/cache_test/"; // Директория кеша
if($obCache->InitCache( $cacheLifetime, $cacheID, $cachePath )){ // Проверяем наличие актуального кеша
$arVars = $obCache->GetVars(); // Выводим данные из кеша в случае его наличия
$arResult = $arVars['arResult'];
$templateCachedData = $arVars['templateCachedData'];
$this->SetTemplateCachedData( $templateCachedData ); // Передадим параметры шаблона (скрипты, стили)
$obCache->Output(); // Хранимый html выведем через Output
} elseif($obCache->StartDataCache()){
//Делаем выборку из базы и сохраняем результат выборки в кеш
$this->IncludeComponentTemplate();
//Получим закешированные параметры шаблона (скрипты, стили) из шаблона
$templateData = $this->GetTemplateCachedData();
$obCache->EndDataCache(
array(
"arResult" => $arResult,
"templateCachedData" => $templateCachedData
)
);
}
При таком подходе, чтобы изминения приняли силу, необходимо либо сбросить кеш, либо пока не истечет время активного кеша.
Компонент с кешированием CPHPCache
description.php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
$arComponentDescription = array(
'NAME' => 'CPHPCache',
'DESCRIPTION' => 'CPHPCache',
'ICON' => '',
'CACHE_PATH' => 'Y',
'SORT' => 10,
'PATH' => array(
'ID' => 'other',
'NAME' => 'Решения UNIQCLE'
)
);
.parameters.php
<? if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
use Bitrix\Main\Loader;
if (!Loader::includeModule('iblock'))
return;
$arTypes = CIBlockParameters::GetIBlockTypes(['-' => ' ']);
$arIBlocks = [];
if (
isset($arCurrentValues['IBLOCK_TYPE'])
&& trim($arCurrentValues['IBLOCK_TYPE'])
&& trim($arCurrentValues['IBLOCK_TYPE']) != '-'
) {
$rsIBlocks = CIBlock::GetList(
['SORT' => 'ASC'],
['SITE_ID' => $_REQUEST['site'], 'TYPE' => trim($arCurrentValues['IBLOCK_TYPE'])]
);
while ($arIBlock = $rsIBlocks->Fetch()) {
$arIBlocks[$arIBlock['ID']] = '[' . $arIBlock['ID'] . '] ' . $arIBlock['NAME'];
}
}
$arSections = [];
if (
isset($arCurrentValues['IBLOCK_ID'])
&& intval($arCurrentValues['IBLOCK_ID']) > 0
) {
$rsSections = CIBlockSection::GetList(
[],
['IBLOCK_ID' => intval($arCurrentValues['IBLOCK_ID'])]
);
while ($arSection = $rsSections->Fetch()) {
$arSections[$arSection['ID']] = '[' . $arSection['ID'] . '] ' . $arSection['NAME'];
}
}
$arComponentParameters = [
'GROUPS' => [
],
'PARAMETERS' => [
'CACHE_TIME' => [
'DEFAULT' => '36001'
],
'IBLOCK_TYPE' => [
'PARENT' => 'BASE',
'NAME' => 'Тип инфоблока',
'TYPE' => 'LIST',
'VALUES' => $arTypes,
'DEFAULT' => 'offers',
'REFRESH' => 'Y'
],
'IBLOCK_ID' => [
'PARENT' => 'BASE',
'NAME' => 'Инфоблок',
'TYPE' => 'LIST',
'VALUES' => $arIBlocks,
'DEFAULT' => '',
'ADDITIONAL_VALUES' => 'Y',
'REFRESH' => 'Y'
],
'SECTION_ID' => [
'PARENT' => 'BASE',
'NAME' => 'Раздел инфоблока',
'TYPE' => 'LIST',
'VALUES' => $arSections,
'DEFAULT' => '',
'ADDITIONAL_VALUES' => 'Y',
'REFRESH' => 'Y'
],
'ELEMENT_ID' => [
'PARENT' => 'BASE',
'NAME' => 'ID Статьи',
'TYPE' => 'STRING',
'DEFAULT' => ''
],
'COUNT' => [
'PARENT' => 'BASE',
'NAME' => 'Кол-во элементов',
'TYPE' => 'STRING',
'DEFAULT' => '1'
],
]
];
component.php
<? if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
//Проверяем входящие параметры в компоненте
$arParams['IBLOCK_ID'] = intval($arParams['IBLOCK_ID']);
if($arParams['IBLOCK_ID'] == 0)
return;
$arParams['ELEMENT_ID'] = intval($arParams['ELEMENT_ID']);
if($arParams['ELEMENT_ID'] == 0)
return;
//Подключаем модуль инфоблоков
CModule::IncludeModule('iblock');
//Объект
$obCache = new CPHPCache();
//Время кеширования
$cacheLifetime = $arParams['CACHE_TIME'];
// Индентификатор кэша, уникальный
$cacheID = $arParams['IBLOCK_ID'] . $arParams['ELEMENT_ID'];
// Директория кеша
$cachePath = "/cache_test/";
// Проверяем наличие актуального кеша
if($obCache->InitCache( $cacheLifetime, $cacheID, $cachePath )){
// Выводим данные из кеша в случае его наличия
$arVars = $obCache->GetVars();
$arResult = $arVars['arResult'];
$templateCachedData = $arVars['templateCachedData'];
// Передадим параметры шаблона (скрипты, стили) в кеш
$this->SetTemplateCachedData( $templateCachedData );
// Хранимый html выведем через Output
$obCache->Output();
} elseif($obCache->StartDataCache()){
// Код, кот. должен быть закеширован
$rsDB = CIBlockElement::GetList(
['ID' => 'ASC'], // Порядок
['ACTIVE' => 'Y', 'IBLOCK_ID' => $arParams['IBLOCK_ID'], 'ID' => $arParams['ELEMENT_ID'] ], // Фильтрация
false,
false, // Кол-во на странице
['IBLOCK_ID', 'ID', 'NAME', 'PREVIEW_TEXT', 'CODE'] // Выборка
);
if($arElem = $rsDB -> GetNext() ){
$arResult = $arElem;
}
$this->IncludeComponentTemplate();
//Получим закешированные параметры шаблона (скрипты, стили) из шаблона
$templateCachedData = $this->GetTemplateCachedData();
$obCache->EndDataCache(
array(
"arResult" => $arResult,
"templateCachedData" => $templateCachedData
)
);
}
template.php
<? if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();?>
<div class = "test">
<b><?=$arResult['NAME'];?></b>
<p><?=$arResult['PREVIEW_TEXT'];?></p>
</div>
style.css
.test{
color: #0a7ddd;
}
Компонент с кешированием CPHPCache D7
.description.php
<?
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
$arComponentDescription = array(
'NAME' => 'CPHPCache D7',
'DESCRIPTION' => 'CPHPCache D7',
'ICON' => '',
'CACHE_PATH' => 'Y',
'SORT' => 10,
'PATH' => array(
'ID' => 'other',
'NAME' => 'Решения UNIQCLE'
)
);
.parameters.php
<? if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
use Bitrix\Main\Loader;
if (!Loader::includeModule('iblock'))
return;
$arTypes = CIBlockParameters::GetIBlockTypes(['-' => ' ']);
$arIBlocks = [];
if (
isset($arCurrentValues['IBLOCK_TYPE'])
&& trim($arCurrentValues['IBLOCK_TYPE'])
&& trim($arCurrentValues['IBLOCK_TYPE']) != '-'
) {
$rsIBlocks = CIBlock::GetList(
['SORT' => 'ASC'],
['SITE_ID' => $_REQUEST['site'], 'TYPE' => trim($arCurrentValues['IBLOCK_TYPE'])]
);
while ($arIBlock = $rsIBlocks->Fetch()) {
$arIBlocks[$arIBlock['ID']] = '[' . $arIBlock['ID'] . '] ' . $arIBlock['NAME'];
}
}
$arSections = [];
if (
isset($arCurrentValues['IBLOCK_ID'])
&& intval($arCurrentValues['IBLOCK_ID']) > 0
) {
$rsSections = CIBlockSection::GetList(
[],
['IBLOCK_ID' => intval($arCurrentValues['IBLOCK_ID'])]
);
while ($arSection = $rsSections->Fetch()) {
$arSections[$arSection['ID']] = '[' . $arSection['ID'] . '] ' . $arSection['NAME'];
}
}
$arComponentParameters = [
'GROUPS' => [
],
'PARAMETERS' => [
'CACHE_TIME' => [
'DEFAULT' => '36001'
],
'IBLOCK_TYPE' => [
'PARENT' => 'BASE',
'NAME' => 'Тип инфоблока',
'TYPE' => 'LIST',
'VALUES' => $arTypes,
'DEFAULT' => 'offers',
'REFRESH' => 'Y'
],
'IBLOCK_ID' => [
'PARENT' => 'BASE',
'NAME' => 'Инфоблок',
'TYPE' => 'LIST',
'VALUES' => $arIBlocks,
'DEFAULT' => '',
'ADDITIONAL_VALUES' => 'Y',
'REFRESH' => 'Y'
],
'SECTION_ID' => [
'PARENT' => 'BASE',
'NAME' => 'Раздел инфоблока',
'TYPE' => 'LIST',
'VALUES' => $arSections,
'DEFAULT' => '',
'ADDITIONAL_VALUES' => 'Y',
'REFRESH' => 'Y'
],
'ELEMENT_ID' => [
'PARENT' => 'BASE',
'NAME' => 'ID Статьи',
'TYPE' => 'STRING',
'DEFAULT' => ''
],
'COUNT' => [
'PARENT' => 'BASE',
'NAME' => 'Кол-во элементов',
'TYPE' => 'STRING',
'DEFAULT' => '1'
],
]
];
class.php
<? if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
use Bitrix\Main\Loader,
Bitrix\Iblock,
\Bitrix\Main\Data\Cache,
\Bitrix\Iblock\Component\Tools;
class FirstComponent extends CBitrixComponent {
// Обработка параметров
function onPrepareComponentParams($params){
if ($params['CACHE_TYPE'] == 'Y' || $params['CACHE_TYPE'] == 'A') {
$params['CACHE_TIME'] = intval($params['CACHE_TIME']);
} else {
$params['CACHE_TIME'] = 0;
}
#проверка входных параметров
$params['IBLOCK_ID'] = isset($params['IBLOCK_ID']) && intval($params['IBLOCK_ID']) > 0 ? intval($params['IBLOCK_ID']) : 0;
return $params;
}
public function executeComponent(){
try {
$cache = Cache::createInstance();
$cacheLifeTime = $this->arParams['CACHE_TIME'];
$cacheID = $this->arParams['IBLOCK_ID'].$this->arParams['ELEMENT_ID'];
$cachePath = "/cache_test1/";
if ($cache->initCache( $cacheLifeTime , $cacheID, $cachePath )) { // проверяем кеш и задаём настройки
$arVars = $cache->getVars(); // достаем переменные из кеша
$this->arResult = $arVars['arResult'];
// $this->templateCachedData = $vars['templateCachedData'];
// $this->SetTemplateCachedData($this->templateCachedData);
$cache->Output();
} elseif ($cache->startDataCache()) {
$this->checkModules();
$this->prepareData();
$this->doAction();
$this->includeComponentTemplate();
//$this->templateCachedData = $this->GetTemplateCachedData();
$cache->endDataCache(
[
"arResult" => $this->arResult,
//"templateCachedData" => $this->templateCachedData
]
);
}
} catch (Exception $e) { //Если произошла к-л ошибка, выводим ошибку
$cache->abortDataCache();
$this->arResult['ERROR'] = $e->getMessage();
}
}
protected function checkModules()
{
#подключаем нужные модули
if (!Loader::includeModule('iblock'))
throw new Exception('Модуль "Инфоблоки" не установлен');
}
protected function prepareData()
{
#проверки на существования
$this->arResult['IBLOCK'] = [];
if ($this->arParams['IBLOCK_ID']) {
$this->arResult['IBLOCK'] = CIBlock::GetByID($this->arParams['IBLOCK_ID'])->Fetch();
}
if (!$this->arResult['IBLOCK']) {
throw new Exception('Инфоблок не найден');
}
}
protected function doAction()
{
// Код, кот. должен быть закеширован
$rsDB = CIBlockElement::GetList(
['ID' => 'ASC'], // Порядок
['ACTIVE' => 'Y', 'IBLOCK_ID' => $this->arParams['IBLOCK_ID'], 'ID' => $this->arParams['ELEMENT_ID'] ], // Фильтрация
false,
false, // Кол-во на странице
['IBLOCK_ID', 'ID', 'NAME', 'PREVIEW_TEXT', 'CODE'] // Выборка
);
if($arElem = $rsDB -> GetNext() ){
$this->arResult = $arElem;
}
}
}
template.php
<? if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die(); ?>
<div class = "test">
<h2><?=$arResult['NAME'];?></h2>
<p><?=$arResult['PREVIEW_TEXT'];?></p>
</div>
Attantion! Стили лучше хранить в общем шаблоне, поскольку при кешировании они не подгружаются из компонента.
CCacheManager
- класс управления кешем.
global $CACHE_MANAGER; //Глоб. объект класса для обращения к методам
//Тегирования в рамках StartTagCache и EndTagCache
$CACHE_MANAGER->StartTagCache("/cache_tag/");
...
$CACHE_MANAGER->RegisterTag("my_tag"); // Регистрация тега
...
$CACHE_MANAGER->EndTagCache();
Вложенный выдов методов StartTagCache и EndTagCache
$CACHE_MANAGER->StartTagCache($cache_dir1);
$CACHE_MANAGER->StartTagCache($cache_dir2);
$CACHE_MANAGER->StartTagCache($cache_dir2);
$CACHE_MANAGER->EndTagCache();
$CACHE_MANAGER->EndTagCache();
$CACHE_MANAGER->EndTagCache();
Итоговая структура тегирования кеша
$global $CACHE_MANAGER;
$CACHE_MANAGER->StartTagCache($cache_dir);
while($arElement=$rsElements->Fetch()){
$CACHE_MANAGER->RegisterTag("iblock_id_".$arElement["ID"]);
$arElements[] = $arElement;
}
$CACHE_MANAGER->RegisterTag("iblock_id_new");
$CACHE_MANAGER->EndTagCache();
Компонент с тегированным кешем
Очистка кэша по тегу, привязанного к ID инфоблока, на событии изменения эл-та
.parameters.php
<? if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
use Bitrix\Main\Loader;
if (!Loader::includeModule('iblock'))
return;
$arTypes = CIBlockParameters::GetIBlockTypes(['-' => ' ']);
$arIBlocks = [];
if (
isset($arCurrentValues['IBLOCK_TYPE'])
&& trim($arCurrentValues['IBLOCK_TYPE'])
&& trim($arCurrentValues['IBLOCK_TYPE']) != '-'
) {
$rsIBlocks = CIBlock::GetList(
['SORT' => 'ASC'],
['SITE_ID' => $_REQUEST['site'], 'TYPE' => trim($arCurrentValues['IBLOCK_TYPE'])]
);
while ($arIBlock = $rsIBlocks->Fetch()) {
$arIBlocks[$arIBlock['ID']] = '[' . $arIBlock['ID'] . '] ' . $arIBlock['NAME'];
}
}
$arSections = [];
if (
isset($arCurrentValues['IBLOCK_ID'])
&& intval($arCurrentValues['IBLOCK_ID']) > 0
) {
$rsSections = CIBlockSection::GetList(
[],
['IBLOCK_ID' => intval($arCurrentValues['IBLOCK_ID'])]
);
while ($arSection = $rsSections->Fetch()) {
$arSections[$arSection['ID']] = '[' . $arSection['ID'] . '] ' . $arSection['NAME'];
}
}
$arComponentParameters = [
'GROUPS' => [
],
'PARAMETERS' => [
'CACHE_TIME' => [
'DEFAULT' => '36001'
],
'IBLOCK_TYPE' => [
'PARENT' => 'BASE',
'NAME' => 'Тип инфоблока',
'TYPE' => 'LIST',
'VALUES' => $arTypes,
'DEFAULT' => 'offers',
'REFRESH' => 'Y'
],
'IBLOCK_ID' => [
'PARENT' => 'BASE',
'NAME' => 'Инфоблок',
'TYPE' => 'LIST',
'VALUES' => $arIBlocks,
'DEFAULT' => '',
'ADDITIONAL_VALUES' => 'Y',
'REFRESH' => 'Y'
],
'SECTION_ID' => [
'PARENT' => 'BASE',
'NAME' => 'Раздел инфоблока',
'TYPE' => 'LIST',
'VALUES' => $arSections,
'DEFAULT' => '',
'ADDITIONAL_VALUES' => 'Y',
'REFRESH' => 'Y'
],
'ELEMENT_ID' => [
'PARENT' => 'BASE',
'NAME' => 'ID Статьи',
'TYPE' => 'STRING',
'DEFAULT' => ''
],
'COUNT' => [
'PARENT' => 'BASE',
'NAME' => 'Кол-во элементов',
'TYPE' => 'STRING',
'DEFAULT' => '1'
],
]
];
component.php
<? if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
//Проверяем входящие параметры в компоненте
$arParams['IBLOCK_ID'] = intval($arParams['IBLOCK_ID']);
if($arParams['IBLOCK_ID'] == 0)
return;
$arParams['ELEMENT_ID'] = intval($arParams['ELEMENT_ID']);
if($arParams['ELEMENT_ID'] == 0)
return;
CModule::IncludeModule('iblock');
$obCache = new CPHPCache();
$cacheLifetime = $arParams['CACHE_TIME'];
$cacheID = $arParams['IBLOCK_ID'] . $arParams['ELEMENT_ID'] . $USER->GetUserGroupString(); // Генерируем уник ID кэша, + ID группы пользователя
$cachePath = "/cache_test/";
if($obCache->InitCache( $cacheLifetime, $cacheID, $cachePath )){ // Проверяем наличие актуального кеша
$arVars = $obCache->GetVars(); // Выводим данные из кеша в случае его наличия
$arResult = $arVars['arResult'];
// $templateCachedData = $arVars['templateCachedData'];
// $this->SetTemplateCachedData( $templateCachedData ); // Передадим параметры шаблона (скрипты, стили) в кеш
$obCache->Output(); // Хранимый html выведем через Output
} elseif($obCache->StartDataCache()){
$rsDB = CIBlockElement::GetList( // Код, кот. должен быть закеширован
['ID' => 'ASC'],
['ACTIVE' => 'Y', 'IBLOCK_ID' => $arParams['IBLOCK_ID'], 'ID' => $arParams['ELEMENT_ID'] ],
false,
false,
['IBLOCK_ID', 'ID', 'NAME', 'PREVIEW_TEXT', 'CODE']
);
global $CACHE_MANAGER; // Установка Тегированного Кэша
$CACHE_MANAGER->StartTagCache($cachePath);
if($arElem = $rsDB -> GetNext() ){
$CACHE_MANAGER->RegisterTag('cache_test_iblock_id_'.$arElem['IBLOCK_ID']); // Регистрация тега
$arResult = $arElem;
}
$CACHE_MANAGER->RegisterTag('cache_test_iblock_id'); // Рег-ия общего кэша
$CACHE_MANAGER->EndTagCache(); ///////////////
$this->IncludeComponentTemplate();
//$templateCachedData = $this->GetTemplateCachedData(); //Получим закешированные параметры шаблона (скрипты, стили) из шаблона
$obCache->EndDataCache(
array(
"arResult" => $arResult,
// "templateCachedData" => $templateCachedData
)
);
}
template.php
<? if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();?>
<div class = "test">
<b><?=$arResult['NAME'];?></b>
<p><?=$arResult['PREVIEW_TEXT'];?></p>
</div>
init.php
// Обработчик при обновлении элемента
AddEventHandler("iblock", "OnAfterIBlockElementUpdate", array("CIBlockHandler", "OnAfterIBlockElementUpdateHandler"));
class CIBlockHandler{
function OnAfterIBlockElementUpdateHandler(&$arFields){
// Проверка на наличие глобально. объекта CACHE_MANAGER
if(is_object($GLOBALS['CACHE_MANAGER']) && $arFields['IBLOCK_ID'] == CONST_IBLOCK_NEWS){
// Очищаем все кэши, обладающие тегом cache_test_iblock_id_*
$GLOBALS['CACHE_MANAGER']->ClearByTag('cache_test_iblock_id_'.$arFields['IBLOCK_ID']);
}
}
}
Кеширование HTML результата выполнения скрипта.
Компонент с HTML-кешем
.description.php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
$arComponentDescription = array(
'NAME' => 'CPageCache',
'DESCRIPTION' => 'CPageCache',
'ICON' => '',
'CACHE_PATH' => 'Y',
'SORT' => 10,
'PATH' => array(
'ID' => 'other',
'NAME' => 'Решения UNIQCLE'
)
);
.parameters.php
<? if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
use Bitrix\Main\Loader;
if (!Loader::includeModule('iblock'))
return;
$arTypes = CIBlockParameters::GetIBlockTypes(['-' => ' ']);
$arIBlocks = [];
if (
isset($arCurrentValues['IBLOCK_TYPE'])
&& trim($arCurrentValues['IBLOCK_TYPE'])
&& trim($arCurrentValues['IBLOCK_TYPE']) != '-'
) {
$rsIBlocks = CIBlock::GetList(
['SORT' => 'ASC'],
['SITE_ID' => $_REQUEST['site'], 'TYPE' => trim($arCurrentValues['IBLOCK_TYPE'])]
);
while ($arIBlock = $rsIBlocks->Fetch()) {
$arIBlocks[$arIBlock['ID']] = '[' . $arIBlock['ID'] . '] ' . $arIBlock['NAME'];
}
}
$arSections = [];
if (
isset($arCurrentValues['IBLOCK_ID'])
&& intval($arCurrentValues['IBLOCK_ID']) > 0
) {
$rsSections = CIBlockSection::GetList(
[],
['IBLOCK_ID' => intval($arCurrentValues['IBLOCK_ID'])]
);
while ($arSection = $rsSections->Fetch()) {
$arSections[$arSection['ID']] = '[' . $arSection['ID'] . '] ' . $arSection['NAME'];
}
}
$arComponentParameters = [
'GROUPS' => [
],
'PARAMETERS' => [
'CACHE_TIME' => [
'DEFAULT' => '36001'
],
'IBLOCK_TYPE' => [
'PARENT' => 'BASE',
'NAME' => 'Тип инфоблока',
'TYPE' => 'LIST',
'VALUES' => $arTypes,
'DEFAULT' => 'offers',
'REFRESH' => 'Y'
],
'IBLOCK_ID' => [
'PARENT' => 'BASE',
'NAME' => 'Инфоблок',
'TYPE' => 'LIST',
'VALUES' => $arIBlocks,
'DEFAULT' => '',
'ADDITIONAL_VALUES' => 'Y',
'REFRESH' => 'Y'
],
'SECTION_ID' => [
'PARENT' => 'BASE',
'NAME' => 'Раздел инфоблока',
'TYPE' => 'LIST',
'VALUES' => $arSections,
'DEFAULT' => '',
'ADDITIONAL_VALUES' => 'Y',
'REFRESH' => 'Y'
],
'ELEMENT_ID' => [
'PARENT' => 'BASE',
'NAME' => 'ID Статьи',
'TYPE' => 'STRING',
'DEFAULT' => ''
],
'COUNT' => [
'PARENT' => 'BASE',
'NAME' => 'Кол-во элементов',
'TYPE' => 'STRING',
'DEFAULT' => '1'
],
]
];
component.php
<? if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
$obCache = new CPageCache();
$cacheTime = $arParams['CACHE_TIME'];
$cacheID = 'weather_parse';
$cacheDir = '/weather_cache/';
if($obCache->StartDataCache($cacheTime, $cacheID, $cacheDir)){
$cityID = "23642"; //Москва
$urlRoot = "https://export.yandex.ru/bar/reginfo.xml?region={$cityID}.xml";
$data = simplexml_load_file($urlRoot);
$city= $data->region->title;
$temp = $data->weather->day->tomorrow->temperature;
$url = $data->weather->url;
?>
Город: <a href = "<?=$url;?>"><?=$city;?></a> </br>
Температура: <b><?=$temp;?></b>
<?php
$obCache->EndDataCache();
}
?>
Гаджет с кешированием
<?
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
?>
<?
// pre($arGadgetParams);
#
# INPUT PARAMS
#
$arGadgetParams["IBLOCK_ID"] = intval($arGadgetParams["IBLOCK_ID"]);
if ($arGadgetParams["IBLOCK_ID"] <= 0)
return false;
$arGadgetParams["ELEMENT_COUNT"] = intval($arGadgetParams["ELEMENT_COUNT"]);
if ($arGadgetParams["ELEMENT_COUNT"] <= 0)
$arGadgetParams["ELEMENT_COUNT"] = 5;
$arGadgetParams["SHOW_UNACTIVE_ELEMENTS"] = $arGadgetParams["SHOW_UNACTIVE_ELEMENTS"]!="N";
$arNavParams = array(
"nPageSize" => $arGadgetParams["ELEMENT_COUNT"],
);
#
# CACHE
#
$obCache = new CPageCache;
$cacheTime = 5*60;
$cacheId = $arGadgetParams["IBLOCK_ID"].$arGadgetParams["ELEMENT_COUNT"].$arGadgetParams["ELEMENT_COUNT"];
if($obCache->StartDataCache($cacheTime, $cacheId, "/")):
if(!CModule::IncludeModule("iblock"))
{
ShowError(GetMessage("IBLOCK_MODULE_NOT_INSTALLED"));
return;
}
$arSelect = array(
"ID",
"ACTIVE",
"DATE_CREATE",
"IBLOCK_ID",
"DETAIL_PAGE_URL",
"NAME",
"PREVIEW_PICTURE",
);
$arFilter = array (
"IBLOCK_ID" => $arGadgetParams["IBLOCK_ID"],
"CHECK_PERMISSIONS" => "Y",
);
if(!$arGadgetParams["SHOW_UNACTIVE_ELEMENTS"])
$arFilter["ACTIVE"] = "Y";
$arSort = array("DATE_CREATE"=>"DESC");
$rsElement = CIBlockElement::GetList($arSort, $arFilter, false, $arNavParams, $arSelect);
while($arElement = $rsElement->GetNext()):
?>
<div style="margin-bottom: 10px;">
<div style="float: left; width: 50px; margin-right: 10px">
<a href="<?=$arElement['DETAIL_PAGE_URL']?>"><?=CFile::ShowImage($arElement['PREVIEW_PICTURE'],50,50)?></a>
</div>
<a href="<?=$arElement['DETAIL_PAGE_URL']?>"><?=$arElement['NAME']?></a><br/>
<small><?=$arElement['DATE_CREATE']?></small>
<div style="clear: both;"></div>
</div>
<?
endwhile;
$obCache->EndDataCache();
endif;
?>
Оптимизированный механизм кеширования. Содержит механизм тегирования и встроенный метод сохранения параметров шаблона GetTemplateCachedData
.
**При написании своих компонентов лучше использовать его. **
Methods
StartResultCache
вывод содержимого кеша или инициализация кеширования. Параметр false
- передача по-умолч. $arParams['CACHE_TIME']
.
Если есть актуальный кеш - возвращает false
. Выводит его на экран и заполняет arResult
данными из кеша.
Если нет актуального кеша - возвращает true
. Инициализирует процесс кеширования, который завершается подключением шаблона.
AbortResultCache
отмена кеширования.
ClearResultCache
очистка кеша.
По-умолч. кэш находится
bitrix/cache/site_id/namespace/component/
//Код, который должен быть закеширован, обернуть в блок
if ($this->StartResultCache()){
//Кешируемый код
}
По умолчанию кеш зависит от набора входящих параметров. Т.е. если у компонента будет один параметр с каким-то значением, то именно для этого набора параметров и будет сгенерирован кеш. При изменении этого параметра будет сформирован другой кеш для компонента. В качестве времени для кеша будет браться по умолчанию значение параметра CACHE_TIME
компонента. При желании его можно изменить, передав первый параметр методу StartResultCache( $cacheTime )
.
Помимо параметров, можно еще и добавить зависимостей к идентификатору кеша с помощью второго параметра функции.
// сделать кеш зависимым от группы пользователя
global $USER;
if ($this->StartResultCache( false, $USER->GetUserGroupString() )){
//Кешируемый код
}
Автоматическое кеширование по умолчанию сохраняет только html вывод, который обрамлен блоком с вызовом метода StartResultCache()
. Соответственно, подключение шаблона также должно находиться внутри этого блока.
// Для того, чтобы включить шаблон в кеш, нужно подключение шаблона загнать внутрь нашего блока
global $USER;
if ($this->StartResultCache( false, $USER->GetUserGroupString() ))
{
//Кешируемый код
$this->IncludeComponentTemplate();
}
Подключение других компонентов в шаблоне
$cache_id = serialize(array($arParams, ($arParams['CACHE_GROUPS']==='N'? false: $USER->GetGroups())));
$obCache = new CPHPCache;
if ($obCache->InitCache($arParams['CACHE_TIME'], $cache_id, '/'))
{
$vars = $obCache->GetVars();
$arResult = $vars['arResult'];
}
elseif ($obCache->StartDataCache())
{
// делаем то, что надо
$obCache->EndDataCache(array(
'arResult' => $arResult,
));
}
// Подключение шаблона компонента
$this->IncludeComponentTemplate();
Если в компоненте используется стандартное кэширование, но при этом не подключается шаблон (по причине ненадобности), нужно использовать:
if ($this->startResultCache())
{
\\Код который модифицирует $arResult
$this->endResultCache();
}
В типовом механизме кеш-ия используется тегирование кеша с помощью методов StartTagCache
и EndTagCache
, а также Registertag
.
Есть возможность тегировать компонент по своему при использовании типового механизма StartResultCache
Можно тегировать кеш типовых компонентов в result_modifier.php
не меняя логики и не копируя в собственное пространство имен.
if (defined('BX_COMP_MANAGED_CACHE') && is_object($GLOBALS['CACHE_MANAGER'])){
$GLOBALS['CACHE_MANAGER']->RegisterTag('my_custom_tag');
}
Тег в типовом механизме кеширования имеет вид
iblock_id_#IBLOCK_ID#
. Сбрасывается в методахAdd/Update/Delete
элементов, разделов и инфоблоков.
Изменение св-в элемента через метод SetPropertyValueCode
При изминении только св-в элемента кеш не очищается.
Задача: товары привязаны к новостям. В списке новостей вывести значения к-л сво-ва всех товаров, привязанных к новости.
- Для товаров добавляем св-во NEWS (привязанные новости), MATERIALS.
- Для эл-в новостей добавляем txt св-во PRODUCT_MATERIALS (в него будут записываться измененные св-ва привязанных товаров).
- Далее создаются обработчики события на изменения товара
OnAfterIBlockElementAdd
,OnAfterIBlockElementUpdate
,OnAfterIBlockElementDelete
. - Получаем данные эл-в товаров, в частности привязки к новости NEWS, MATERIALS.
- Далее все сво-ва PRODUCT_MATERIALS данной новости. И если значения материала данного товара нет, то добавить материал к значениям данного св-ва.
init.php
define('NEWS_IBLOCK_ID', 1);
define('PRODUCT_IBLOCK_ID', 4);
define('PRODUCT_NEWS_PROP_ID', 977 ); //ID св-ва привязки к новостям из ИБ товаров
define('PRODUCT_MATERIAL_PROP_ID', 979 ); // ID сво-ва MATERIAL из ИБ товаров
// Обработчик при обновлении элемента
AddEventHandler("iblock", "OnAfterIBlockElementAdd", array("CIBlockHandler", "OnAfterIBlockElementUpdateHandler"));
AddEventHandler("iblock", "OnAfterIBlockElementUpdate", array("CIBlockHandler", "OnAfterIBlockElementUpdateHandler"));
AddEventHandler("iblock", "OnAfterIBlockElementDelete", array("CIBlockHandler", "OnAfterIBlockElementUpdateHandler"));
class CIBlockHandler{
function OnAfterIBlockElementUpdateHandler(&$arFields){
//Если изменяемый эл-т принадлежит ИБ продукции
if($arFields['IBLOCK_ID'] == PRODUCT_IBLOCK_ID ){
$newsIblockID = NEWS_IBLOCK_ID; //ID инфоблока новостей
//Получаем значение св-в NEWS и MATERIAL из ИБ товара
//current(), если txt поле
$arProductNews = current($arFields['PROPERTY_VALUES'][PRODUCT_NEWS_PROP_ID]);
$arProductMaterial = current($arFields['PROPERTY_VALUES'][PRODUCT_MATERIAL_PROP_ID]);
// Запрашиваем все текущие св-ва PRODUCT_MATERIAL из ИБ новостей.
$rsNewsProperty = CIBlockElement::GetProperty($newsIblockID, $arProductNews['VALUE'], array("SORT" => "ASC"), array("CODE" => "PRODUCT_MATERIALS"));
while( $arProperty = $rsNewsProperty->GetNext() ){
$arRsProperty[] = $arProperty['VALUE'];
}
if(!in_array($arProductMaterial['VALUE'], $arRsProperty)){
$arRsProperty[] = $arProductMaterial['VALUE'];
CIBlockElement::SetPropertyValueCode($arProductNews['VALUE'], "PRODUCT_MATERIALS", $arRsProperty );
if(defined("BX_COMP_MANAGED_CACHE") && is_object($GLOBALS['CACHE_MANAGER'])){
$GLOBALS['CACHE_MANAGER']->ClearByTag('news_list_tag');
}
}
}
}
}
result_modifier.php
в компоненте news.list
...
//Добавляем уник. тег к кешу списка новостей
if (defined('BX_COMP_MANAGED_CACHE') && is_object($GLOBALS['CACHE_MANAGER'])){
$GLOBALS['CACHE_MANAGER']->RegisterTag('news_list_tag');
}
Тегированный кеш
component.php
if ($this->StartResultCache(......)) {
if (defined('BX_COMP_MANAGED_CACHE') && is_object($GLOBALS['CACHE_MANAGER'])) {
$GLOBALS['CACHE_MANAGER']->RegisterTag('my_custom_tag');
}
// do something
$this->IncludeComponentTemplate();
} else {
$this->AbortResultCache();
}
result_modifier.php
<?
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
if (defined('BX_COMP_MANAGED_CACHE') && is_object($GLOBALS['CACHE_MANAGER'])) {
$cp =& $this->__component;
if (strlen($cp->__cachePath)) {
$GLOBALS['CACHE_MANAGER']->RegisterTag('my_custom_tag');
}
}
?>
//Сбросить кэш по тегу, например в обработчике
if (defined('BX_COMP_MANAGED_CACHE') && is_object($GLOBALS['CACHE_MANAGER']))
$GLOBALS['CACHE_MANAGER']->ClearByTag('my_custom_tag');
Важно избегать кеширования ошибочных данных. Если в процессе работы есть шанс получить некорректные данные, то вы должны обрабатывать данную ситуацию и сбрасывать автокеширование. Иначе в кеш запишется некорректный набор данных + шаблон и в течение всего времени жизни кеша пользователь будет видеть неверные данные.
// Для того чтобы сбросить кеш
global $USER;
if ($this->StartResultCache( false, $USER->GetUserGroupString() )){
//Кешируемый код
if ($productNotFound) {
$this->AbortResultCache();
return;
}
$this->SetResultCacheKeys(array('NAME'));
$this->IncludeComponentTemplate();
}
Важно понимать, что при закешированном компоненте его результат отдается из кеша, и весь код, который написан в коде компонента внутри блока кеширования, а также весь код шаблона исполняться повторно не будет, поэтому если вы вдруг используете отложенные функции внутри шаблонов компонентов (или в result_modifier.php
), то при кешировании они работать не будут. Поэтому никогда не используйте отложенные функции в шаблоне компонента (а точнее в файлах result_modifier.php
и template.php
). Если все же нужно использовать отложенные функции, вы можете произвести их вызов в файле component_epilog.php шаблона, т.к. его вызов не кешируется.
Особенности
- $arResult в
component_epilog
содержит меньше данных, чем в шаблоне иresult_modifier.php
. - Для дополнения $arResult, доступного в
component_epilog
используется API ф-ияSetResultCacheKeys()
вresult_modifier.php
.SetResultCacheKeys()
ограничивает ключи массива, которые передаются в кэш. -
component_epilog
подключается после исполнения шаблона, после него могут следовать вызовы API. -
component_epilog
выполняется на каждом хите, не стоит размещать в него "тяжелый код".
В автоматический кеш компонента битрикс включить также и данные. Для этого нужно использовать метод SetResultCacheKeys(). Данный метод принимает на вход массив ключей, которые содержатся в $arResult. Если вы хотите сохранить в кеш компонента какую-то строку, например название товара (чтобы использовать его после выполнения компонента, например в component_epilog.php), который выводит компонент, то вам нужно использовать следующую конструкцию:
global $USER;
if ($this->StartResultCache( false, $USER->GetUserGroupString() )){
//Кешируемый код
$this->SetResultCacheKeys(array('NAME'));
$this->IncludeComponentTemplate();
}
Когда проектируем свой компонент - сохраняем в кэш только те данные, которые будем использовать в некешируемой части. Сохранять ITEMS с данными всех элементов явно нет смысла.
Adding Keys in component
component.php
<? if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
//Проверяем входящие параметры в компоненте
$arParams['IBLOCK_ID'] = intval($arParams['IBLOCK_ID']);
if($arParams['IBLOCK_ID'] == 0)
return;
$arParams['ELEMENT_ID'] = intval($arParams['ELEMENT_ID']);
if($arParams['ELEMENT_ID'] == 0)
return;
//Подключаем модуль инфоблоков
CModule::IncludeModule('iblock');
$cacheID = $USER->GetUserGroupString();
if($this->StartResultCache(false, $cacheID)){
//Код, кот. должен быть закеширован
$rsDB = CIBlockElement::GetList(
['ID' => 'ASC'],
['ACTIVE' => 'Y', 'IBLOCK_ID' => $arParams['IBLOCK_ID'], 'ID' => $arParams['ELEMENT_ID'] ], // Фильтрация
false,
false, // Кол-во на странице
['IBLOCK_ID', 'ID', 'NAME', 'PREVIEW_TEXT', 'CODE']
);
if($arElem = $rsDB -> GetNext() ){
$arResult = $arElem;
} else {
$this->AbortResultCache();
}
//Добавление определенных полей в кеш.
$this->SetResultCacheKeys(array(
'ID',
'NAME',
'PREVIEW_TEXT'
));
$this->IncludeComponentTemplate();
}
Adding Keys in result_modifier
Различие arResult
между template
и component_epilog
в том, что в template
получаем из кэша.
В логике компонента есть метод $this->setResultCacheKeys
, куда попадают все свойства которые кэшируются.
Если нам необходимо получить в component_epilog
получить данные из кэша, то в result_modifier.php
эти свойства необходимо закэшировать с помощью метода $cp->setResultCacheKeys
result_modifier.php
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
$cp = $this->__component; // Объект компонента
// или так $cp = $this->getComponent();
// Сделаем проверку на наличие привязки к пользователю
if( $arResult['PROPERTIES']['AUTHOR']['VALUE'] ) {
$rsUser = CUser::GetByID($arResult['PROPERTIES']['AUTHOR']['VALUE']);
$arUser = $rsUser->Fetch();
$arResult['AUTHOR']['NAME'] = $arUser['NAME'];
// Кэшируем AUTHOR
$cp->setResultCacheKeys( array("AUTHOR") );
}
// Создаем новое обрезанное название
$arResult["NAME_10"] = substr( $arResult["NAME"], 0, 10).">>>";
$cp->setResultCacheKeys( array("NAME_10") ); // Закешируем новую переменную
component_epilog
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
// pre($arResult);
$str = $arResult["NAME"] . ' , '. $arResult["NAME_10"];
// Создаем закешированное мета-описание
$APPLICATION->SetPageProperty("description", $str);
Если кэшируем в классе компонента, то
$this->setResultCacheKeys();
, согласно доступным переменным
-
CBitrixComponentTemplate::getComponent
(или обращение к$this->__component
), позволяет получить объект компонента вtemplate.php
,result_modifier.php
и с помощьюSetResultCacheKeys
доложить данные в кэш. -
templateData
, специальная переменная для передачи даных изtemplate.php
вcomponent_epilog.php
с поддержкой кэширования.
Добирать данные в
component_epilog.php
- не верно, он не кешируется, вы будете нагружать сервер на каждом хите.
Подключение memcached осуществляется в файле dbconn.php
.
Для эффективной работы системы настройки по умолчанию нужно изменить. Примеры:
// Мемкеш с объемом памяти 2ГБ 8 потоками и работой через tcp
PORT="11211"
USER="memcached"
MAXCONN="10240"
CACHESIZE="2048"
OPTIONS="-t 8"
// настройки в dbconn.php
define("BX_CACHE_TYPE", "memcache");
define("BX_CACHE_SID", $_SERVER["DOCUMENT_ROOT"]."#01");
define("BX_MEMCACHE_HOST", "127.0.0.1");
define("BX_MEMCACHE_PORT", "11211");
// Мемкеш с объемом памяти 2ГБ 8 потоками и работой через сокет
PORT="11211"
USER="bitrix"
MAXCONN="10240"
CACHESIZE="2048"
OPTIONS="-t 8 -s /tmp/memcached.sock"
// настройки в dbconn.php
define("BX_CACHE_TYPE", "memcache");
define("BX_CACHE_SID", $_SERVER["DOCUMENT_ROOT"]."#01");
define("BX_MEMCACHE_HOST", "unix:///tmp/memcached.sock");
define("BX_MEMCACHE_PORT", "0");
Youtube link
https://hmarketing.ru/blog/bitrix/vsye-o-keshirovanii/