Зачем это нужно?
Для достижения максимальной гибкости без потери производительности. Кэширование выгодно только тогда, когда данные редко изменяются. Но что делать, если в целом содержимое компонента хорошо кэшируется, но в нем присутствует область, где выводятся некие персональные для каждого пользователя данные либо просто часто изменяющиеся данные? Например, нам хотелось бы взять стандартный компонент новостей и вставить в середину списка динамически генерируемый рекламный блок. В таких ситуациях помогут некэшируемые области.
Как это сделать?
Следующий код нужно подключить в вашем файле /bitrix/php_interface/init.php:
Использование некэшируемых областей в шаблоне компонента проиллюстрируем примером.
template.php:
Код
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?>
<?nciStart();?>
<?=ConvertTimeStamp(false, "FULL")?> - компонент закэширован<br />
<[#INSERT#]> - текущее время<br />
<?nciFinish($component)?> |
component_epilog.php:
Код
<?if (!defined ("B_PROLOG_INCLUDED") || true !== B_PROLOG_INCLUDED) die();?>
<?=nciDisplay($component)?> |
insert.php:
Код
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?>
<?=ConvertTimeStamp(false, "FULL")?> |
Обработка некэшируемых областей будет проводиться только в тех шаблонах компонентов, где вы укажете данный код, все остальные компоненты будут работать, как раньше.
Если вы пользуетесь каким-нибудь пользовательским движком шаблонизации, то весь служебный код можно вынести туда. Если кому-то интересно, могу предоставить код для Smarty.
Как это работает?
Некэшируемый файл component_epilog.php, появившийся в девятке, не имеет доступа к закэшированному HTML-коду шаблона. Поэтому в файле template.php вывод буферизуется и помещается в переменную $arResult["RESULT_HTML"], после чего данная переменная помечается как кэшируемая с помощью метода CBitrixComponent::SetResultCacheKeys. В component_epilog.php содержимое данной переменной просто выводится, предварительно заменяя некэшируемые вставки на результат выполнения соответствующего php-файла в папке шаблона (по методу Виталия Оборина).
Преимущества метода
Подобную задачу можно решать различными способами, каждый из которых обладает своими положительными и отрицательными сторонами. Основные преимущества продемонстрированного подхода: простота, легкость использования и главное - он действительно работает =)
Домашнее задание
Для достижения простоты и наглядности я не стал реализовывать некоторые фичи. Что можно усовершенствовать:
- добавить возможность использования в некэшируемых областях массивов $arParams и $arResult
- посыпать некэшируемые вставки солью, чтобы исключить даже малейшую вероятность ложного срабатывания
- произвести интеграцию с движками шаблонизации
Disclaimer
Автор не несет ответственности за непреднамеренное порабощение Вселенной, которое может произойти при выполнении вышеуказанного кода =)
Приветствуются конструктивная критика, пожелания и готовые примеры доработки.










Посмотрел в код nciDisplay() и сразу скажу, что не будет он корректно работать с методом $GLOBALS['APPLICATION']->ShowBanner() (а только он из коробки умеет выводить рекламу с таргетингом по ключевикам) или любыми другими отложенными функциями.
Всё будет, писал я о подобной проблеме
Надеюсь, Евгений будет не против, если я приведу код этой функции здесь для наглядности:
function nciDisplay (&$component) { $html = $component->arResult["RESULT_HTML"]; preg_match_all ("~<[#(w+)#]>~", $html, $matches); if (is_array ($matches)) { $template_path = $_SERVER["DOCUMENT_ROOT"].$component->arResult["TEMPLATE_PATH"]; $keys = $matches[0]; $vars = $matches[1]; foreach ($keys as $key_index => $key_name) { ob_start(); include ($template_path."/".(strtolower ($vars[$key_index])).".php"); $mini_template_data = ob_get_clean (); $html = str_replace ($key_name, $mini_template_data, $html); } } return $html; }То что описано у вас - это фактически этот же подход только более глобальный и вызываемый непосредственно перед самым выводом буффера. Как недостаток - не имеет защиты от вставок пользователем и парсит весь контент страницы.
А... или вы предлагаете в подключаемом файле из эпилога компонента возвращать еще один маркер и добавлять обработчик события OnEndBufferContent для вывода баннера или содержимого отложенной функции? Ололо!
То что для вас недостаток, для меня преимущество
Не исключено, что если есть component_after, то скоро появится component_before это решение тоже утратит актуальность.
Цитата$GLOBALS['APPLICATION']->ShowBanner()
ShowBanner это буферизированный результат ф-ции CAdvBanner::Show
Вот какое дело. А мой комментарий относился к посту. Значит у меня сложилость верное впечатление, что вы увидели знакомую вам проблему и неразобравшись в сути моего комментария сказали, что я не прав.
Весьма сомнительное преимущество, но хозяин - барин.
В моем случае, когда области оформляются символами <[# #]>, пользователь не сможет их вставить, потому что присутствует символ <.
Для особо параноидальных можно посыпать вставки солью. А именно, в шаблоне вставка будет выглядеть как-то так:
<?=nciInsert("INSERT")?>Функция nciStart будет генерировать случайную строку, которая будет запоминаться в кэше и которая будет дописываться к коду всех вставок (например, <#[INSERT_a77c5d4904372a6893cae61531901ee1]#>). А в nciFinish будут производиться замены только тех вставок, к которым дописана именно та соль, которая сохранена в кэше.
А про особо параноидальных отвечу, что поиск каких-либо решений этой якобы проблемы, затронутой в вашем топике, тоже не меньшая паранойя.
Нужны динамические вставки - выносите код шаблона из template.php в component_epilog.php шаблона, предварительно добавив нужные кэшируемые ключи, и не мучайтесь. Вот мое мнение.
Интересна ваша идея, можно по подробней?
Если позарез нужны отложенные функции, видимо, придется воспользоваться обработчиком OnEndBufferContent
Вы бы не могли подсказать, как добавить возможность использования массивов $arParams и $arResult?