Расширение логики стандартных компонентов без копирования 1С-Битрикс
Скопировать компонент из /bitrix/components/ в /local/components/ — рабочий, но дорогой способ. Копия перестаёт получать обновления ядра: исправления багов, поддержку новых API, совместимость с новыми редакциями. Через год-два копия расходится с оригиналом настолько, что мержить невозможно. Битрикс предоставляет несколько механизмов расширения логики без полного копирования.
Расширение логики стандартных компонентов без копирования 1С-Битрикс
Механизм 1: result_modifier.php
Самый простой способ. Файл result_modifier.php в папке шаблона компонента выполняется после основной логики компонента, но до шаблона. В нём доступен $arResult по ссылке — можно добавлять, изменять, удалять данные.
/local/templates/my_site/components/bitrix/catalog.section/.default/result_modifier.php
<?php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
// Добавляем к каждому товару средний рейтинг из своей таблицы
$ids = array_column($arResult['ITEMS'], 'ID');
if ($ids) {
$ratings = MyRatingService::getAverageForItems($ids);
foreach ($arResult['ITEMS'] as &$item) {
$item['MY_RATING'] = $ratings[$item['ID']] ?? 0;
}
}
Ограничение: result_modifier.php работает только с результатом, но не может изменить параметры запроса к базе данных внутри компонента.
Механизм 2: Events (события компонента)
Большинство стандартных компонентов генерируют события через \Bitrix\Main\EventManager. Это мощнейший механизм — позволяет вмешаться в логику на уровне формирования запроса, фильтрации, подготовки результата.
Чтобы найти события конкретного компонента, ищем в его исходном коде:
grep -r "GetModuleEvents\|AddEventHandler\|fireEvent\|sendEvent" \
/bitrix/components/bitrix/catalog.section/
Пример: событие OnBeforeIBlockElementGetList в модуле iblock:
// В /local/php_interface/init.php
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
'iblock',
'OnBeforeIBlockElementGetList',
function (\Bitrix\Main\Event $event) {
$filter = $event->getParameter('filter');
// Добавляем скрытие товаров без цены
$filter['!CATALOG_PRICE_1'] = false;
$event->setParameter('filter', $filter);
return $event;
}
);
Механизм 3: Расширения компонентов (Extensions)
Появились в Битрикс с D7. Позволяют создать класс-расширение, который наследует или декорирует логику стандартного компонента без его копирования.
Создаём файл класса компонента в /local/:
/local/components/bitrix/catalog.section/class.php
<?php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
// Подключаем оригинальный класс
\Bitrix\Main\Loader::includeModule('iblock');
\Bitrix\Main\Loader::includeModule('catalog');
// Наследуем оригинальный компонент
class MyCatalogSectionComponent extends \Bitrix\Iblock\Component\ElementList
{
protected function getFilter(): array
{
$filter = parent::getFilter();
// Расширяем фильтр: скрываем товары без изображения
$filter['!PREVIEW_PICTURE'] = false;
return $filter;
}
protected function prepareElementData(array $element): array
{
$element = parent::prepareElementData($element);
// Добавляем вычисляемое поле
$element['IS_NEW'] = (time() - strtotime($element['DATE_CREATE'])) < 86400 * 30;
return $element;
}
}
Битрикс автоматически найдёт /local/components/bitrix/catalog.section/class.php и использует его вместо оригинального — при этом шаблоны из /bitrix/ всё ещё работают.
Механизм 4: Агрегация через обёртку
Когда нужно полностью переопределить логику, но сохранить возможность вызывать оригинал, создаём компонент-обёртку с другим именем:
/local/components/myproject/catalog.section.extended/component.php
<?php
// Вызываем оригинальный компонент внутри своего
$this->includeComponentTemplate();
// Или:
$APPLICATION->IncludeComponent(
'bitrix:catalog.section',
'.default',
$arParams,
$this
);
Механизм 5: Переопределение методов через /local/php_interface/init.php
Для случаев, когда компонент использует глобальные функции или статические методы:
// init.php — выполняется при каждом запросе
// Перехватываем метод подготовки SEO-данных
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
'main',
'OnPageStart',
function () {
// Инициализация кастомной логики
}
);
Что выбрать: сравнение подходов
| Задача | Механизм |
|---|---|
| Добавить вычисляемое поле к результату | result_modifier.php |
| Изменить SQL-фильтр компонента | Событие OnBefore* |
| Расширить бизнес-логику, наследовать методы | Класс-расширение в /local/ |
| Полная замена логики с сохранением шаблонов | Класс-расширение + переопределение методов |
| Переиспользовать компонент с другими параметрами | Компонент-обёртка |
Практический пример: расширение bitrix:catalog.section
Задача: в стандартный список товаров добавить количество активных отзывов без копирования компонента.
// /local/components/bitrix/catalog.section/class.php
class MyCatalogSectionComponent extends \Bitrix\Iblock\Component\ElementList
{
public function executeComponent(): void
{
parent::executeComponent();
// После выполнения родителя — обогащаем данные
$this->enrichWithReviewCounts();
}
private function enrichWithReviewCounts(): void
{
if (empty($this->arResult['ITEMS'])) return;
$ids = array_keys($this->arResult['ITEMS']);
$counts = \Bitrix\Main\Application::getConnection()->query(
'SELECT ELEMENT_ID, COUNT(*) as CNT FROM b_iblock_element_prop_s' . REVIEWS_IBLOCK_ID .
' WHERE ELEMENT_ID IN (' . implode(',', array_map('intval', $ids)) . ')' .
' AND PROPERTY_' . REVIEW_STATUS_PROP . " = 'approved'" .
' GROUP BY ELEMENT_ID'
)->fetchAll();
$countMap = array_column($counts, 'CNT', 'ELEMENT_ID');
foreach ($this->arResult['ITEMS'] as &$item) {
$item['REVIEW_COUNT'] = (int)($countMap[$item['ID']] ?? 0);
}
}
}
Оригинальный компонент получает обновления ядра, кастомная логика остаётся в /local/.
Сроки
| Задача | Сроки |
|---|---|
| Расширение одного компонента через result_modifier | 2–4 часа |
| Расширение через класс-наследник с переопределением методов | 1–3 дня |
| Рефакторинг: замена копий компонентов на расширения | 3–8 дней (зависит от количества) |







