Меню

Некэшируемые области компанента Битрикс

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

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

Специально для решения задачи создания некэшируемых областей в шаблоне компанента разработчики Битрикмс ввели в состав шаблока компонента файл component_epilog.php. Только он никогда не кэшируется в компоненте. Именно использование этого файла и позволяет по всем канонам Битрикса реализовать некэшируемые области шаблона компонента. При этом нам не приходится выходить за пределы кода шаблона или перестраивать страницу уже после ее загрузки. Этот метод уже описан другими авторами, но немного заумно и смазано, поэтому попробуем описать его подробнее.

Задач по этому вопросу может быть сколько угодно. Это и компоненты встроенные в шаблон другого, и произвольный код, который постоянно динамически меняется. Рассмотрим решение на примере кнопки В корзину/Уже в корзине компонента catalog.section. При включенном кэшировании могут возникать ситуации, когда кнопки показывают неверное значение так как шаблон был закеширован в определенном состоянии.

Итак, для решения задачи нам надо внести изменения в три файла. Файл result_modifier.php (если нет, то создайте):
<? if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();

/**
 * @var CBitrixComponentTemplate $this
 * @var CatalogSectionComponent $component
 */

// Вставляем эту строчку
$this->__component->SetResultCacheKeys(array("CACHED_TPL"));

$component = $this->getComponent();
$arParams = $component->applyTemplateModifications();

// Остальной код

Меняем template.php:
<? if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();

/**
 * @global CMain $APPLICATION
 * @var array $arParams
 * @var array $arResult
 * @var CatalogSectionComponent $component
 * @var CBitrixComponentTemplate $this
 * @var string $templateName
 * @var string $componentPath
 */

// Вставляем в начало
ob_start();

$this->setFrameMode(true);



// Ваш код шаблона компонента
.......

?>

<!-- Вместо кода кнопки ставим  -->
#BUY_BUTTON_ID_<?=$arItem["ID"]?>#

<?

// Ваш код шаблона компонента
.......

?>

// В самом конце шаблона
<?
$this->__component->arResult["CACHED_TPL"] = @ob_get_contents();
ob_get_clean();
?>
<!-- component-end -->
И, наконец, файл component_epilog.php (если нет, то создайте):
<? if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();

/**
 * @var array $arParams
 * @var array $templateData
 * @var string $templateFolder
 * @var CatalogSectionComponent $component
 */

// Получаем массив ID товаров в корзине
global $arInBasket;
$arInBasket = [];
$basket = Bitrix\Sale\Basket::loadItemsForFUser(Bitrix\Sale\Fuser::getId(), Bitrix\Main\Context::getCurrent()->getSite());
$basketItems = $basket->getBasketItems();
foreach ($basketItems as $basketItem) {
	$arInBasket[] = $basketItem->getProductId();
}

// Функция получения кода кнопки для конкретного товара
function set_buttons($matches) {
	global $arInBasket;
	ob_start();
	if(in_array($matches[1], $arInBasket)) {
		echo "<a href=\"/cart/\"><button>Уже в корзине</button></a>";
	} else {
		echo "<a href=\"/cart/\" class=\"add-to-basket\" data-id=\"".$matches[1]."\"><button>В корзину</button></a>";
	}
	$retrunStr = @ob_get_contents();
	ob_get_clean();
	return $retrunStr;
}

// Собственно подстановка некэшированного кода
echo preg_replace_callback(
	"/#BUY_ID_([\d]+)#/is" . BX_UTF_PCRE_MODIFIER,
	'set_buttons',
	$arResult["CACHED_TPL"]
);
Здесь мы обрабатываем предварительный кэшированный код компонента и заменяем нужные области некэшированными вставками. Массив $matches содержит части заменяемой конструкции, которые могут меняться. В нашем случае это ID товара. Таким образом для каждого товара будет установлено актуальное некэшированное значение кнопки добавления в корзину.

Так же можно вставлять и компоненты в шаблон в этом случае функция set_buttons будет содержать примерно следующее:

function set_buttons($matches) {
     ob_start();
     $GLOBALS["APPLICATION"]->IncludeComponent(
          "iplogic:buy_button", 
          "", 
          array(
               "PRODUCT_ID" => $matches[1],
               "USE_AJAX" => "Y",
               "SHOW_ERRORS" => "N",
               "CACHE_TYPE" => "N",
               "COMPONENT_TEMPLATE" => ""
          ),
          $component,
          array("HIDE_ICONS" => "N")
     );
     $retrunStr = @ob_get_contents();
     ob_get_clean();
     return $retrunStr;
}


Всех тонкостей и частных случаев не опишешь, но надеюсь логика этого метода вставки некэшируемых областей в шаблон компонента понятна.

18.08.2022

Возврат к списку

Оставаясь на этом сайте Вы соглашаетесь с использованием файлов cookie, а также принимаете все пользовательские соглашения данного сайта.