Розширення логіки стандартних компонентів без копіювання у 1С-Бітрікс
Скопіювати компонент із /bitrix/components/ до /local/components/ — робочий, але дорогий спосіб. Копія перестає отримувати оновлення ядра: виправлення багів, підтримку нових API, сумісність із новими редакціями. Через рік-два копія розходиться з оригіналом настільки, що мерджити неможливо. 1С-Бітрікс надає кілька механізмів розширення логіки без повного копіювання.
Розширення логіки стандартних компонентів без копіювання у 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)
З'явилися в 1С-Бітрікс з 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;
}
}
1С-Бітрікс автоматично знайде /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 днів (залежить від кількості) |







