Здравствуйте, уважаемые читатели!
Хочу поделиться с вами опытом решения своей проблемы в нашем всеми любимом 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');
Автор: мастер слога