Перейти к содержимому

Свой компонент - структура, параметры, кэш результата

Пишем свой компонент: разбираем обязательные файлы, параметры и кэширование, из-за которого чаще всего и заводят компонент вместо кода в шаблоне страницы.

Решение

Собираем каталог компонента:

Окно терминала
/home/bitrix/www/local/components/vendor/last.orders/
├── class.php # логика: получение и подготовка данных
├── .parameters.php # описание параметров для интерфейса
├── .description.php # имя и раздел в списке компонентов
└── templates/.default/template.php # разметка

Компонент - это каталог с заранее известным платформе набором файлов. Логика живёт в классе, а разметка в шаблоне. Именно это разделение позволяет менять внешний вид, вообще не трогая получение данных.

Описываем параметры:

.parameters.php
$arComponentParameters = ['PARAMETERS' => [
'COUNT' => ['NAME' => 'Сколько показывать', 'TYPE' => 'STRING', 'DEFAULT' => '5'],
'CACHE_TIME' => ['DEFAULT' => 3600],
]];
// без значения по умолчанию компонент падает сразу после вставки на страницу

Параметры описывают ровно то, что настраивается через обычный интерфейс страницы. Значение по умолчанию здесь не формальность: компонент, вставленный без настройки, должен работать, а не падать на пустом параметре.

Кэшируем результат с правильным ключом:

class.php
if ($this->startResultCache(false, [$USER->GetUserGroupArray(), $this->arParams['COUNT']])) {
$this->arResult['ITEMS'] = $this->loadOrders(); // всё дорогое внутри
$this->includeComponentTemplate();
}

В ключ кэша входят все значимые параметры и права текущего посетителя. Забытая группа пользователя - это чужие данные в кэше. Проявляется она обычно не сразу, а через жалобу «вижу не свои заказы».

Отдаём разметку шаблону:

templates/.default/template.php
foreach ($arResult['ITEMS'] as $item): ?>
<div class="order"><?= htmlspecialcharsbx($item['NAME']) ?></div>
<?php endforeach;
// запросов к базе в шаблоне быть не должно: они выполняются мимо кэша
// в ключ кэша попадают группы пользователя: иначе чужие данные уедут всем

Запрос к базе прямо в шаблоне выполняется мимо кэша компонента. Именно поэтому кэшированный компонент иногда не даёт ускорения: дорогая часть переехала в шаблон и считается на каждом показе.

Свой компонент оправдан только там, где меняется сама логика получения этих данных. Если нужен другой внешний вид, дешевле сделать свой шаблон штатного компонента и не поддерживать лишний код.

Логику стоит держать в классе своего модуля, а сам компонент оставлять тонким. Тогда её можно вызвать из агента, из обработчика и из другого компонента, а не копировать между тремя похожими каталогами.

Копию штатного компонента заводят только под новым собственным именем каталога. Правка компонента в каталоге платформы возвращается к исходному виду при первом же обновлении, и вместе с ней возвращается исходное поведение сайта.

Отладку компонента начинают с отключённого кэша и с включённой панели отладки страницы. Иначе половина правок не доходит до страницы, а вторая половина выглядит работающей ровно до сброса кэша.

Типичные проблемы

Посетители видят чужие данные.

В ключ кэша не вошли группы текущего пользователя сайта. Кэш собран первым зашедшим гостем и отдаётся дальше всем подряд.

Кэш включён, а быстрее не стало.

Дорогие запросы к базе выполняются прямо в шаблоне компонента. Шаблон компонента отрабатывает и при попадании в готовый кэш точно так же.

После обновления платформы правки пропали.

Правился штатный компонент платформы вместо собственной копии. Обновление возвращает все файлы платформы к исходному виду.

Компонент падает без настроек.

У параметров этого компонента нет значений по умолчанию. Вставленный без всякой настройки компонент обязан работать.

Правки не видны при отладке.

Компонент отдаёт уже готовый результат из своего кэша. На время правок кэширование этого компонента отключают.

Частые вопросы

Чем свой компонент лучше кода в шаблоне страницы?

Он переиспользуется, кэшируется и настраивается параметрами. Код в шаблоне страницы не даёт ничего из этого.

Где хранить свои компоненты?

В своём пространстве имён внутри каталога проекта. Каталог штатных компонентов обновление перезапишет.

Нужен ли компоненту класс?

На новых проектах - да: класс удобнее для наследования и тестирования. Старый формат с одним файлом тоже работает.

Как передать данные из компонента в шаблон?

Через массив результата: он и есть договор между ними. Прямое обращение к своим методам из шаблона ломает кэширование.

Смежное

Первоисточник