Битрикс. Отложенные функции

08.12.2018

Теги: CMSWeb-разработкаБитриксБуферизацияОтложенныеФункции

Отложенные функции — технология, позволяющая задавать заголовок страницы, пункты навигационной цепочки, CSS стили, дополнительные кнопки в панель управления, мета-теги и т.п. с помощью функций, используемых непосредственно в теле страницы. Соответствующие результаты работы этих функций выводятся в прологе, то есть выше по коду, чем они были заданы.

Технология была создана в первую очередь для использования в компонентах, которые, как правило, выводятся в теле страницы, но при этом внутри них могут быть заданы заголовок страницы, добавлен пункт в навигационную цепочку, добавлена кнопка в панель управления и так далее. Отложенные функции нельзя использовать в файлах шаблона компонента template.php и result_modifier.php (так как результаты их выполнения кешируются).

Алгоритм работы

Любой исходящий поток из PHP скрипта буферизируется. Как только в коде встречается одна из следующих функций:

  • CMain::ShowTitle()
  • CMain::ShowCSS()
  • CMain::ShowNavChain()
  • CMain::ShowProperty()
  • CMain::ShowMeta()
  • CMain::ShowPanel()

Весь буферизированный до этого контент запоминается в очередном элементе стека КонтентСтраницы. И сразу полсе этого в стек КонтентСтраницы добавляется пустой элемент. В дальнейшем этот пустой элемент будет заполнен результатом выполнения отложенной функции. Имя этой отложенной функции запоминается в стеке ОтложенныеФункции. Буфер очищается и буферизация снова включается.

Таким образом, существует стек КонтентСтраницы, в котором находится весь контент страницы, разбитый на части. В этом же стеке есть пустые элементы, предназначенные для их дальнейшего заполнения результатами отложенных функций. Также существует стек ОтложенныеФункции, в котором запоминаются имена и параметры отложенных функции в порядке их следования в коде.

В конце страницы, в служебной части эпилога, выполняются следующие действия:

  • все отложенные функции из стека ОтложенныеФункции начинают выполняться одна за другой;
  • результаты их выполнения вставляются в специально предназначенные для этого места в стек КонтентСтраницы;
  • весь контент из стека КонтентСтраницы «склеивается» (конкатенируется) и выводится на экран.

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

Пример использования

Давайте рассмотрим пример установки заголовка страницы и заголовка окна браузера.

<?php
/*
 * Файл /local/templates/page/header.php
 */
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();
?>

<!DOCTYPE html>
<html>
<head>
    <title><?php $APPLICATION->ShowTitle(); /* показываем заголовок браузера */ ?></title>
</head>
<?php
/*
 * Файл /test/index.php
 */
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php");
?>
<h1><?php $APPLICATION->ShowTitle(false); /* показываем заголовок страницы */ ?></h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore...
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore...
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore...
</p>
<?php
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/footer.php");
?>

Поскольку мы нигде не вызываем методы SetTitle() и SetPageProperty(), заголовок браузера и заголовок страницы у нас пустые. Давайте установим значения заголовков:

<?php
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php");
// устанавливаем заголовок страницы
$APPLICATION->SetTitle('Какой-то заголовок (старый)');
// устанавливаем заголовок браузера
$APPLICATION->SetPageProperty('title', 'Какой-то заголовок (старый)');
?>
<h1><?php $APPLICATION->ShowTitle(false); /* показываем заголовок страницы */ ?></h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore...
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore...
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore...
</p>
<?php
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/footer.php");
?>

Переопределим значения заголовков браузера и страницы ниже по коду:

<?php
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php");
// устанавливаем заголовок страницы
$APPLICATION->SetTitle('Какой-то заголовок (старый)');
// устанавливаем заголовок браузера
$APPLICATION->SetPageProperty('title', 'Какой-то заголовок (старый)');
?>
<h1><?php $APPLICATION->ShowTitle(false); /* показываем заголовок страницы */ ?></h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore...
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore...
</p>
<?php
// устанавливаем заголовок страницы
$APPLICATION->SetTitle('Какой-то заголовок (новый)');
// устанавливаем заголовок браузера
$APPLICATION->SetPageProperty('title', 'Какой-то заголовок (новый)');
?>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore...
</p>
<?php
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/footer.php");
?>

В компонентах Битрикс часто можно увидеть такой код, который устанавливает значения заголовков и значенния мета-тегов keywords и description:

if ($this->StartResultCache(false, ($arParams['CACHE_GROUPS']==='N' ? false: $USER->GetGroups()))) {
    /*
     * Данных в кеше нет, выполняем запрос к БД
     */

    /* ...получаем данные... */

    if (isset($arResult['ID'])) { // данные успешно получены
        $this->SetResultCacheKeys(
            array(
                'ID',
                'NAME',
                'IPROPERTY_VALUES'
            )
        );
        $this->IncludeComponentTemplate();
    } else { // что-то пошло не так
        $this->AbortResultCache();
        \Bitrix\Iblock\Component\Tools::process404(
            trim($arParams['MESSAGE_404']) ?: 'Элемент инфоблока не найден',
            true,
            $arParams['SET_STATUS_404'] === 'Y',
            $arParams['SHOW_404'] === 'Y',
            $arParams['FILE_404']
        );
    }
}

// кэш не затронет все действия ниже, здесь работаем уже с другим $arResult
if (isset($arResult['ID'])) {
    if ($arParams['SET_PAGE_TITLE'] == 'Y') { // установить заголовок страницы?
        if ($arResult['IPROPERTY_VALUES']['ELEMENT_PAGE_TITLE'] != '') {
            $APPLICATION->SetTitle($arResult['IPROPERTY_VALUES']['ELEMENT_PAGE_TITLE']);
        } else {
            $APPLICATION->SetTitle($arResult['NAME']);
        }
    }
    if ($arParams['SET_BROWSER_TITLE'] == 'Y') { // установить заголовок окна браузера?
        if ($arResult['IPROPERTY_VALUES']['ELEMENT_META_TITLE'] != '') {
            $APPLICATION->SetPageProperty('title', $arResult['IPROPERTY_VALUES']['ELEMENT_META_TITLE']);
        } else {
            $APPLICATION->SetPageProperty('title', $arResult['NAME']);
        }
    }
    // установить мета-тег keywords?
    if ($arParams['SET_META_KEYWORDS'] == 'Y' && $arResult['IPROPERTY_VALUES']['ELEMENT_META_KEYWORDS'] != '') {
        $APPLICATION->SetPageProperty('keywords', $arResult['IPROPERTY_VALUES']['ELEMENT_META_KEYWORDS']);
    }
    // установить мета-тег description?
    if ($arParams['SET_META_DESCRIPTION'] == 'Y' && $arResult['IPROPERTY_VALUES']['ELEMENT_META_DESCRIPTION'] != '') {
        $APPLICATION->SetPageProperty('description', $arResult['IPROPERTY_VALUES']['ELEMENT_META_DESCRIPTION']);
    }
    return $arResult['ID'];
}

Методы ShowViewContent и AddViewContent

Метод CMain::ShowViewContent() добавляет в стек КонтентСтраницы пустой элемент. А метод CMain::AddViewContent() добавляет в этот элемент контент, который формируется ниже:

<?php
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php");
?>
<h1>Случайные элементы</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore...
</p>
<?php
// здесь выводим контент с меткой «random-elements», который будет сфорирован ниже
$APPLICATION->ShowViewContent('random-elements');
?>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore...
</p>
<?php
// включаем буферизацию вывода, все идет в отдельный буфер
ob_start();
// вызываем компонент, который формирует список блок случайных элементов инфоблока
$GLOBALS['APPLICATION']->IncludeComponent(
    "tokmakov:iblock.random",
    "",
    Array(
        "ELEMENT_COUNT" => "4",
        "ELEMENT_URL" => "#SITE_DIR#/#IBLOCK_CODE#/element/code/#ELEMENT_CODE#/",
        "IBLOCK_ID" => "5",
        "IBLOCK_TYPE" => "content"
    )
);
// выключаем буферизацию и помечаем этот контент меткой «random-elements»
$APPLICATION->AddViewContent('random-elements', ob_get_clean());
?>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore...
</p>
<?php
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/footer.php");
?>

Методы SetViewTarget и EndViewTarget

В шаблоне компонента вместо функций ob_start() и ob_get_clean() можно использовать методы SetViewTarget() и EndViewTarget():

<?php
// включаем буферизацию и помечаем этот контент меткой «smart-filter»
$this->SetViewTarget('smart-filter');
?>
<div class="smart-filter">
    <?php
    $APPLICATION->IncludeComponent(
        'bitrix:catalog.smart.filter',
        '',
        Array(
            // параметры компонента
        ),
        $component
    );
    ?>
</div>
<?php
// выключаем буферизацию
$this->EndViewTarget();
?>

В том месте, где нам нужно вывести контент, добавляем в стек КонтентСтраницы пустой элемент:

<div class="left sidebar">
    <?php $APPLICATION->ShowViewContent('smart-filter'); ?>
</div>

Поиск: CMS • Web-разработка • Битрикс • Буферизация • Отложенные функции • ShowTitle • ShowCSS • ShowNavChain • ShowProperty • ShowMeta • ShowPanel • ShowViewContent • AddViewContent • SetViewTarget • EndViewTarget

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.