Хлебные крошки в 1С-Битрикс

в 22:19, , рубрики: 1С-Битрикс

Здравствуйте, уважаемые читатели!
Хочу поделиться с вами опытом решения своей проблемы в нашем всеми любимом CMS 1C- Битрикс.

Задача: Необходимостью разместить хлебные крошки внутри кешируемого шаблона.

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

$APPLIACATION->IncludeComponent("bitrix:breadcrumb", ".default"); 

включает буферизацию методом AddBufferContent, который в свою очередь вешает событие onEndBufferContent. Это событие обрабатывается после кешированием, поэтому в кеш буферизированные данные попасть не могут. Это приводит к потере части контента. (В моем случае пропадал код шаблона, расположенный до вызова компонента bitrix:breadcrumb.)

Условие 2: Модификация хлебных крошек может производиться после вызова шаблона.

Сама по себе проблема не нова, но нормального решения так и не смог найти. Поэтому было предпринято создать свое.
Решение было найдено — использовать component_epilog.php.
Схема работы такая: В шаблоне делаем placeholder, например ##PLACEHOLDER_1##. Затем в не кешируемом component_epilog.php заменяем его на нужный нам контент.

Создаем класс, например ComponentHelper, со следующим содержимым:

<?php
#/bitrix/php_interface/classes/ComponentHelper.php
namespace PHPInterface;

/**
 * ComponentHelper
 *
 * Создает плейсхолдеры в шаблоне
 * При помощи статической функции handle обрабатывает их
 * Класс необходим для вызова некешируемых функций
 */
class ComponentHelper
{
    private $component = null;
    private $lastPlIndex = 0;
    private $pull = array();

    public function __construct(CBitrixComponent $component)
    {
        $this->component = $component;
        $this->component->SetResultCacheKeys(array('CACHED_TPL', 'CACHED_TPL_PULL'));
        ob_start();
    }

    public function deferredCall($callback, $args = array())
    {
        $plName = $this->getNextPlaceholder();
        echo $plName;
        $this->pull[$plName] = array('callback' => $callback, 'args' => $args);
    }

    public function saveCache()
    {
        $this->component->arResult['CACHED_TPL'] = @ob_get_contents();
        $this->component->arResult['CACHED_TPL_PULL'] = $this->pull;
        ob_get_clean();
        $this->component = null;
    }

    private function getNextPlaceholder()
    {
        return '##PLACEHOLDER_'.(++$this->lastPlIndex).'##';
    }

    public static function handle(CBitrixComponent $component)
    {
        $buf = &$component->arResult['CACHED_TPL'];
        foreach ($component->arResult['CACHED_TPL_PULL'] as $plName => $params) {
            list($prevPart, $nextPart) = explode($plName, $buf);
            echo $prevPart;
            call_user_func_array($params['callback'], $params['args']);
            $buf = &$nextPart;
        }
        echo $buf;
    }
}

Особенность работы скрипта в том, что функция handle выводит контент до плейсходера, обрабатывает сам плейсхолдер, затем переходит к следующему. Алгоритм поиска плейсходеров является итеративным.
Соотвественно, чтобы вывести хлебные крошки, понадобится создать функцию, например
ShowNavChain в файле init.php.

function ShowNavChain($template = '.default')
{
    global $APPLICATION;
    $APPLICATION->IncludeComponent('bitrix:breadcrumb', $template);
}

В шаблоне пишем такие строки:

$helper = new PHPInterfaceComponentHelper($component);
$helper->deferredCall('ShowNavChain', array('.default'));
//...
// И в конце шаблона обязательно вызвать 
$helper->saveCache();

Рядом с шаблоном располагаем файл component_epilog.php
и помещаем в него примерно такой код:

PHPInterfaceComponentHelper::handle($this);

Не забываем в /bitrix/php_interface/init.php добавить:

require_once(dirname(__FILE__).'/classes/ComponentHelper.php');

Автор: мастер слога

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js