Компоненты — одна из основных логических строительных еденицв FW Bitrix.
Решают задачи:
- Инкапсуляция front-end + back-end в едином контейнере Вы всегда знаете где поправить нужный стиль или JS. Благодаря этому разнесению битрикс позволяет значительно оптимизировать скорость работы front-end загружая на страницу только нужные стили и нужный JS. Разработчики на платформе Битрикс, не соблюдающие данный стандарт очень часто значительно теряют в производительности.
- позволяют избежать дублирования логики и кусков шаблонов Вам нужно вывести один блок в двух местах? Компонент решит эту проблему. Даже если вам нужно вывести практически без логики компонент (один шаблон) — это легко можно сделать создав компонент с пустой логикой в классе, не бойтесь возможных повышенных затрат на очередную обертку — отсутствие дублирования кода в т.ч. шаблона — намного важнее.
Компоненты на классах
Мы не допускаем написание компонентов в стиле процедурной логики. Допускаются исключительно на классах. В связи с этим рассмотр старых компонентов битрикса на component.php как пример — не имеет особого смысла.
Современные приложения должны использовать только ООП. Разбиение логики компонента на удобные небольшие методы значительно повышают читаемость, скорость и защищенность кода.
Компонент не должен содержать в себе большой бизнес логики. Любая более-менее тяжелая логика должна выноситься в модуль. Это позволит ее в последствии переиспользовать и не делать толстые жирные компоненты. Впрочем как и в целом в парадигме ООП — класс который берет на себя слишком много логики — скорей всего декомпозировать, это точно также относится и к классам компонентов.
Кеширование
Внимательно ознакомьтесь с механизмом кеширования работы компонентов. По хорошему все компоненты которые не требуют актуальных и свежих запросов — должны быть закешированы. В каком то случаем обычным жестким кешем, в каких то — тегированным.
Смотри официальные видео-курсы для того чтобы лучше разобраться как работает кеширование.
В bbc есть упрощенный механизм для работы с кешем.
Нативные компоненты vs кастомные
Нативные компоненты битрикса могут выполнять ряд задач. Однако стоит понимать что они зачастую слишком универсальные и не гибкие.
Если вам нужно писать много логики в result_modifier или вы используете только лишь небольшую часть главное логики компонента — скорей всего вам следует лучше написать кастомный компонент.
Хорошо написанные кастомные компоненты проще в поддержке и развитии, а также более гибки, и почти всегда более производительны.
Название компонентов
Названия компонентов должны следовать парадигме движка
- нижний регистр
- разделители слов — тире
- группы компонентов разделяются точкой Например: news, news.list, news.detail
- Название вендора по умолчанию для кастомных компонентов — custom. Нет никакого смысла писать название webpratik в любом кастомном компоненте для проекта который вы пишете. Мы не страдаем звездной болезнью, и не превращаем проект который развивали 3-4 студии в логически несвязанные группы директорий. Если у вас много кастомных компонентов — лучше используйте вендорное пространство для логического разделения, например
- form (для компоненентов форм)
- lk (папка для компонентов личного кабинета)
- и.т.д.
- Для комплексных компонентов рекомендуется добавлять суффикс router. Например: В группе компонентов lk: lk.router, lk.settings, lk.cart
BBC
BBC — это удобная прослойка для работы с функционалом нативных компонентов.
Мы рекомендуем его использоваться для облегчения написания логики и уменьшения количества кода. Подробнее о его возможностях читайте в документации.
Подключается bbc через composer. Потом просто наследуемся от нужного нам компонента. Чтобы не инклюдить модуль персонально для каждого компонента и не нарушать PSR — допускается проинклюдить его в init.php.
Простой компонент
При написании компонентов следуем PSR — и вне класса не должно быть никакой доп логики. Подключение модулей должно быть внутри логики класса.
Пример простого компонента без bbc:
use \Bitrix\Main\Loader;
/**
* Компонент вывода списка статей
*/
class ArticleList extends CBitrixComponent
{
/** Execution component */
public function executeComponent()
{
Loader::includeModule('iblock');
$this->arResult['ITEMS'] = $this->getItems();
$this->setTitle('Список статей');
$this->includeComponentTemplate();
}
/**
* Получение статей
*/
public function getItems(): array
{
$articles = [];
// Здесь выбираем статьи
return $articles;
}
/**
* Установка заголовка страницы
* @param string $title
*/
public function setTitle(string $title)
{
global $APPLICATION;
$APPLICATION->SetTitle($title);
}
}
Минимальный компонент чтобы использовать только возможности шаблона. Пригодится для создания болванок для фронтов.
/**
* Компонент вывода списка статей
*/
class ArticleList extends CBitrixComponent
{
/** Execution component */
public function executeComponent()
{
$this->includeComponentTemplate();
}
}
Комплексный компонент
Комплексный компонент отличается от простого тем что он выполняет задачу роутинга в FW Bitrix.
Роутинг происходит следующим образом
- .htacess видит, что фактически файла нет и перенаправляет на системный файл urlrewirte.php в ядре Bitrix
- Последний подключает ядро и на основе правил описанных в /urlrewrite.php подключает нужный исполняемый файл
- В нужном исполняемом файле компонент роутинга (он же комплексный компонент) берет на себя задачу разруливания роутинга.
Используя приведенный выше механизм вы можете легко отдебажить проблему неработоспособности комплексного компонента.
Пример комплексного компонента на BBC
/** * Роутер алертов */
class AlertsRouter extends Bbc\BasisRouter
{
protected function setSefDefaultParams()
{
$this->defaultUrlTemplates404 = [
'list-project' => 'projects/',
'list' => '',
'detail' => '#ELEMENT_ID#/',
];
$this->componentVariables = [
'PROJECT_ID',
'ELEMENT_ID',
];
}
}
404 страница и области ответственности
- Комплексный компонент если шаблон адреса не обработан — должен выдать 404 ошибку.
- Компонент детальной страницы берет на себя обработку соответствия переданного идентификатора на наличие в базе, и отдает 404 страницу в случае если он был не найден.
Простой способ отдать 404 страницу
\Bitrix\Main\Loader::includeModule('iblock');
\Bitrix\Iblock\Component\Tools::process404(false, true, true, true);
Шаблон компонента
Шаблон компонента имеет уже определенный ряд переменных и ссылка на объект шаблона текущего компонента в виде $this
. Для того чтобы PHPStorm правильно подсвечивал переменные рекомендуем в шаблоны вставлять следующую шапку
/**
* @global CMain $APPLICATION
* @var array $arParams
* @var array $arResult
* @var CBitrixComponent $component
* @var CBitrixComponentTemplate $this
* @var string $templateName
* @var string $componentPath
*/
Данная шапка уже вшита в нашу сборку PHPStorm, и можно ее вызвать набирая ключ bxcomponent в контексте php.
Наследование компонентов
Если вы видите что у вас несколько компонентов похожие, но все же логика будет отличаться — можно сделать общий класс и наследовать его. Абстрактный класс с общей логикой лучше положить в модуль, а не компонент, тогда при наследовании не прийдется подключать компонент перед самим наследованием.
Кастомизация нативных компонентов
В случае если вам пришлось это делать (а делать это нужно в очень крайних случаях, и лучше посоветоваться со старшим разработчиком, скорей всего это вам не нужно, почти всегда это костыль), то нужно сделать это обязательно 2 коммитами, первым вынос компонента в свою область, вторым закоммитить его модификацию, тогда по аннотациям другой разработчик сможет легко увидеть модифицированные строчки кода.
Еще стоит добавить в корень такого компонента readme.md, в котором объяснить почему вы решились на такой шаг и что там изменили. В общем сразу подуймайте, как облегчить вашим коллегам понять, почему и что там было кастомизированно, и как вы докатились до такой жизни.
Ajax & Api
Устаревшие Bitrix компоненты используют очень неудачную модель API, подробнее читай в нашей статье про проектирование API. Использовать старую логику для API — derpecated. Использование нового механизма контроллеров в компонентах — допустимо лишь в тех случаях когда логика контроллера очень тесно связанно с логикой компонента, в остальных случаях выносим в контроллеры модулей.