Skip to content

Постоянный обмен с 1С — как избежать сброса кэша

Yuri edited this page Nov 21, 2016 · 1 revision

Техническая реализация заключается в следующем:

Отменяем сброс кэша при импорте каталога и при редактировании элемента каталога. Для этого модифицируется файл bitrix\modules\main\classes\general\cache.php ядра Битрикс (меняем метод ClearByTag):

function ClearByTag($tag)
	{
        if (function_exists('isClearCacheDenied')){
            $clearDenied = isClearCacheDenied();
        }
        else{
            $clearDenied = false;
        }

		if(defined("BX_COMP_MANAGED_CACHE") && !$clearDenied)
		{
// Можно включить логирование сброса по тегу инфоблока (в данном примере это iblock_id_41)
            if ($tag == 'iblock_id_41'){
//                \Bitrix\Main\Diag\Debug::writeToFile($tag, date('Y-m-d H:i:s ') . "Кэш сброшен с тегом", "/bitrix/tmp/Cache_ClearByTag.log");
            }

			$this->taggedCache->clearByTag($tag);
		}
	}

Пример определения функции для отмены сброса кэша:

function isClearCacheDenied () {
    $requestUri = $_SERVER["REQUEST_URI"];
    if (strpos($requestUri, "/bitrix/admin") !== false
        && (strpos($requestUri, "/bitrix/admin/1c_exchange") !== false || strpos($requestUri, "IBLOCK_ID=".IBLOCK_ID_CATALOG) !== false)
        )
    {
        return true;
    }
    return false;
}

В шаблонах компонентов списка товаров и детальной страницы товара вместо значений цен подставляется шаблон #price-ITEM_ID#, где ITEM_ID это ID элемента инфоблока каталога товаров.

После формирования html-кода страницы по событию OnEndBufferContent шаблоны цен заменяются на актуальные цены из базы данных, с учетом скидок, конвертации валюты и прочего стандартного функционала Битрикс.

Пример замены шаблонов цен:

/**
* Замена шаблонов цен при выводе контента
*/
Main\EventManager::getInstance()->addEventHandler(
    'main',
    'OnEndBufferContent',
    'replacePrices'
);

function replacePrices(&$content){
    $bufferHandler = new BufferHandler($content);
    $bufferHandler->replacePrices();
    $content = $bufferHandler->content;
}

class BufferHandler{
    public $content;
    private $priceCode;


    public function __construct($content)
    {
        \Bitrix\Main\Loader::IncludeModule('catalog');
        $this->content = $content;

        $data = catalogHelper::getCityData();
        $this->priceCode = $data['PRICE'];
    }


    public function replacePrices()
    {
        $pattern = '/#price-([0-9]*)#/i';
        $this->replacePattern($pattern);

        $pattern = '/#price-discount-([0-9]*)#/i';
        $this->replacePattern($pattern, true);
    }


    private function replacePattern($pattern, $isDiscount = false)
    {
        $arMatches = array();
        $countMatches = preg_match_all($pattern, $this->content, $arMatches);

        if ($countMatches > 0 && count($arMatches[1]) > 0) {
            $arPriceCodes = array($this->priceCode);

            $arResult["PRICES"] = CIBlockPriceTools::GetCatalogPrices(CATALOG_ID, $arPriceCodes);

            foreach($arResult["PRICES"] as &$value)
            {
                if (!$value['CAN_VIEW'] && !$value['CAN_BUY'])
                    continue;
                $arSelect[] = $value["SELECT"];
            }

            $arOrder = array();
            $arFilter = array('IBLOCK_ID' => CATALOG_ID, 'ID' => $arMatches[1]);
            $arSelectFields = array("ID", "IBLOCK_ID");
            $arSelectFields = array_merge($arSelectFields, $arSelect);

            $rsElements = CIBlockElement::GetList($arOrder, $arFilter, FALSE, FALSE, $arSelectFields);
            while($arItem = $rsElements->Fetch())
            {
                $arPrices = CIBlockPriceTools::GetItemPrices(CATALOG_ID, $arResult["PRICES"], $arItem);
                $priceValue = $arPrices[$this->priceCode]['VALUE'];
                $pricePrintValue = $arPrices[$this->priceCode]['PRINT_VALUE'];
                $priceDiscountValue = $arPrices[$this->priceCode]['DISCOUNT_VALUE'];
                $pricePrintDiscountValue = $arPrices[$this->priceCode]['PRINT_DISCOUNT_VALUE'];

                $key = array_search($arItem['ID'], $arMatches[1]);
                if ($isDiscount){
                    // Цена со скидкой
                    $this->content = str_replace($arMatches[0][$key], $pricePrintDiscountValue, $this->content);
                }
                else{
                    // Цена без скидки
                    $this->content = str_replace($arMatches[0][$key], $pricePrintValue, $this->content);
                }
            }
        }
    }
}

Для возможности ручного сброса кэша создается скрипт (/bitrix/admin/clear_catalog_cache.php), по обращению к которому сбрасывается кэш каталога товаров, без сброса кэша других инфоблоков. Доступ к скрипту должен быть только у авторизованных пользователей сайта с правами администратора.

Пример файла сброса кэша:

<? require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");

$cache_manager = Bitrix\Main\Application::getInstance()->getTaggedCache();
$cache_manager->ClearByTag("iblock_id_".CATALOG_ID);
Clone this wiki locally