PHP-события
Модуль отправляет собственные события D7 от имени модуля slytek.skyshop. Обработчики позволяют менять данные и добавлять функции, не трогая код модуля и шаблона, — такие доработки не теряются при обновлениях и синхронизации шаблона.
Как подписаться
Обработчики регистрируются стандартным менеджером событий «Битрикса», обычно в файле /local/php_interface/init.php:
<?php
use Bitrix\Main\Event;
use Bitrix\Main\EventManager;
use Bitrix\Main\EventResult;
$eventManager = EventManager::getInstance();
$eventManager->addEventHandler('slytek.skyshop', 'onBeforeBasketAdd', function (Event $event) {
$product = $event->getParameters();
// ...меняем данные...
return new EventResult(EventResult::SUCCESS, $product);
});Вместо анонимной функции можно указать метод своего класса: [\My\Project\SkyshopHandlers::class, 'onBeforeBasketAdd'].
- Параметры события получайте через
$event->getParameters()или$event->getParameter('имя'). - Чтобы изменить данные, верните
new EventResult(EventResult::SUCCESS, $data). Если менять ничего не нужно, ничего не возвращайте. - Если обработчиков несколько, их ответы применяются по очереди, в порядке регистрации.
Как модуль применяет ответ обработчика
| Режим | Что происходит с ответом | События |
|---|---|---|
| Изменение | Ответ сливается с исходными данными через array_replace_recursive. Достаточно вернуть только изменённые ключи. | onBuildSettingsList, onLoadSettingsValues, onBeforeBasketAdd, onAjaxData |
| Замена | Непустой массив из ответа целиком заменяет результат. Пустой ответ ничего не меняет. | onAjaxResult |
| Шаблон | Ключи arResult и arParams из ответа заменяют соответствующие массивы компонента. | onBeforeTemplateModify, onAfterTemplateModify |
| Контент | Строки из ответов всех обработчиков склеиваются и выводятся на страницу. | onContent… |
Список событий
| Событие | Когда вызывается | Параметры |
|---|---|---|
| onBuildSettingsList | При построении списка настроек: страница настроек, панель «Настройки темы», чтение значений | Массив описаний всех настроек |
| onLoadSettingsValues | При загрузке сохранённых значений настроек, один раз за запрос | Массив всех значений |
| onBeforeBasketAdd | Перед добавлением товара в корзину кнопками шаблона | PRODUCT_ID, QUANTITY, PROPS |
| onAjaxData | Перед обработкой AJAX-запроса шаблона | Массив действий: 'cart:add' => параметры |
| onAjaxResult | После выполнения каждого AJAX-действия | type, params, result |
| onBeforeTemplateModify | В result_modifier.php шаблонов SkyShop до обработки данных модулем | arResult, arParams, name, template, component |
| onAfterTemplateModify | То же, после обработки данных модулем | Те же |
| onContentProductDetail… | В точках вывода карточки товара | TYPE, arResult, arParams |
onBuildSettingsList — свои настройки
Событие получает описание всех настроек (структура как в /bitrix/modules/slytek.skyshop/data/options.php). Добавьте свои поля или вкладки — они появятся на странице настроек сайта, будут сохраняться вместе с остальными и читаться через Settings::get().
$eventManager->addEventHandler('slytek.skyshop', 'onBuildSettingsList', function (Event $event) {
return new EventResult(EventResult::SUCCESS, [
// новая вкладка на странице настроек
'promo' => [
'name' => 'Промо',
'type' => 'tab',
'items' => [
'on' => ['name' => 'Показывать промо-блок', 'type' => 'checkbox', 'constructor' => true],
'title' => ['name' => 'Заголовок'],
'text' => ['name' => 'Текст', 'type' => 'html'],
'image' => ['name' => 'Картинка', 'type' => 'image'],
],
],
]);
});Чтение значения в любом месте сайта:
use Bitrix\Main\Loader;
use Slytek\Skyshop\Settings;
Loader::includeModule('slytek.skyshop');
if (Settings::get('promo->on') === 'Y') {
echo Settings::get('promo->title');
}
// встроенные настройки читаются так же
$phone = Settings::get('contacts->phone');
$showStock = Settings::get('catalog->available->on');Путь к значению записывается через ->. Второй аргумент Settings::get() — код сайта; по умолчанию берётся текущий.
Типы полей
| Тип | Поле в настройках |
|---|---|
| не указан | Однострочное текстовое поле. |
checkbox | Галочка, значение Y или N. |
text | Многострочное поле. |
html | Визуальный редактор. |
image | Загрузка картинки, значение — путь к файлу. |
radio, select | Выбор из списка values: ['code' => ['value' => 'code', 'name' => 'Название']]. С флагом 'multiple' => true можно выбрать несколько. |
colorpicker | Выбор цвета. |
iblock, property, element, price, form, agreement | Списки из данных сайта: инфоблоки, свойства, элементы, типы цен, веб-формы, соглашения. Источник задаётся ключом source, например 'source' => 'catalog' для свойств каталога. |
tab | Вкладка; её поля перечисляются в items. Группа полей без вкладки — элемент с items без type. |
| Флаг | Что делает |
|---|---|
constructor | Показывать поле в панели «Настройки темы» на сайте. Для полей внутри групп флаг нужен и у группы. |
sortable | Поля группы можно перетаскивать, порядок сохраняется. |
css-variables | Значение выводится как CSS-переменная на :root; имя переменной — код поля, где подчёркивания заменены дефисами. У вариантов radio вместо этого можно задать свой набор переменных ключом variables. |
onLoadSettingsValues — подмена значений
Срабатывает, когда модуль загружает сохранённые значения. Верните изменённые ключи, чтобы подменить настройки «на лету», не сохраняя их. Например, свой телефон для оптового домена:
$eventManager->addEventHandler('slytek.skyshop', 'onLoadSettingsValues', function (Event $event) {
if (defined('ADMIN_SECTION')) {
return; // не подменяем в админке, иначе подмена сохранится в настройки
}
if ($_SERVER['HTTP_HOST'] === 'opt.example.ru') {
return new EventResult(EventResult::SUCCESS, [
'contacts' => ['phone' => '+7 (495) 000-00-00'],
]);
}
});ADMIN_SECTION подменённые значения попадут в форму и сохранятся в файл при нажатии «Сохранить».onBeforeBasketAdd — перед добавлением в корзину
Вызывается, когда покупатель добавляет товар кнопками шаблона. Параметры — данные будущей позиции корзины: PRODUCT_ID, QUANTITY и PROPS — свойства позиции (массивы с ключами NAME, CODE, VALUE).
$eventManager->addEventHandler('slytek.skyshop', 'onBeforeBasketAdd', function (Event $event) {
$product = $event->getParameters();
// добавляем к позиции свойство с меткой источника
$product['PROPS'][] = [
'NAME' => 'Источник',
'CODE' => 'SOURCE',
'VALUE' => 'Сайт',
];
return new EventResult(EventResult::SUCCESS, $product);
});onAjaxData — перед AJAX-запросом
Все AJAX-действия шаблона (корзина, избранное, сравнение, формы, подгрузка блоков) приходят на сервер одним запросом в виде массива 'тип:действие' => параметры, например 'cart:add' или 'favorite:trigger'. Событие получает этот массив до обработки: можно изменить параметры, добавить или убрать действия.
$eventManager->addEventHandler('slytek.skyshop', 'onAjaxData', function (Event $event) {
$actions = $event->getParameters();
if (isset($actions['compare:clear'])) {
\Bitrix\Main\Diag\Debug::writeToFile('Пользователь очистил сравнение');
}
});Ответ обработчика сливается с исходным массивом, поэтому через это событие можно изменить параметры или добавить действие, но не убрать его. Чтобы отменить действие, используйте JS-событие data::<действие>.
onAjaxResult — после AJAX-действия
Срабатывает для каждого действия после его выполнения. Параметры: type — ключ действия, params — его параметры, result — результат. Если обработчик вернёт непустой массив, он полностью заменит результат.
Так удобно делать свои AJAX-действия без отдельного обработчика запросов. На странице — кнопка с атрибутом data-ajaxaction:
<button type="button" class="btn" data-ajaxaction="promo:coupon" data-params='{"code":"SPRING"}'>
Получить купон
</button>На сервере — обработчик, который отвечает только на своё действие:
$eventManager->addEventHandler('slytek.skyshop', 'onAjaxResult', function (Event $event) {
if ($event->getParameter('type') !== 'promo:coupon') {
return; // чужие действия не трогаем
}
$params = $event->getParameter('params'); // ['code' => 'SPRING']
return new EventResult(EventResult::SUCCESS, [
'success' => true,
'message' => 'Ваш купон: ' . htmlspecialcharsbx($params['code']),
]);
});Если в ответе есть message, шаблон сам покажет его во всплывающем окне: при success: true — как сообщение об успехе, иначе — как ошибку. Ответ доступен и в JS-событии AjaxHandler | action.
promo:, mycompany:), чтобы ваши действия не пересекались со встроенными cart:, favorite:, compare:.onBeforeTemplateModify и onAfterTemplateModify — данные компонентов
Вызываются в result_modifier.php шаблонов SkyShop: списки и детальные страницы инфоблоков, каталог и разделы, умный фильтр, корзина. onBeforeTemplateModify срабатывает до того, как модуль подготовит данные, onAfterTemplateModify — после.
| Параметр | Что содержит |
|---|---|
arResult | Результат компонента. |
arParams | Параметры компонента. |
name | Имя компонента, например bitrix:catalog.section. |
template | Имя шаблона компонента. |
component | Объект компонента. |
$eventManager->addEventHandler('slytek.skyshop', 'onAfterTemplateModify', function (Event $event) {
if ($event->getParameter('name') !== 'bitrix:catalog.section') {
return;
}
$arResult = $event->getParameter('arResult');
// не показываем в списках товары без картинок
foreach ($arResult['ITEMS'] as $key => $item) {
if (empty($item['PREVIEW_PICTURE']) && empty($item['DETAIL_PICTURE'])) {
unset($arResult['ITEMS'][$key]);
}
}
return new EventResult(EventResult::SUCCESS, ['arResult' => $arResult]);
});result_modifier.php выполняется внутри кеша компонента, поэтому изменения кешируются вместе с ним. Не добавляйте сюда данные, зависящие от пользователя, и сбрасывайте кеш после правки обработчика.onContent… — свой HTML в карточке товара
В карточке товара есть точки, куда можно вывести свой HTML без правки шаблона. Имя события — onContent плюс название точки:
| Событие | Где выводится |
|---|---|
onContentProductDetailAfterTitle | Под названием товара |
onContentProductDetailAfterPrice | Под ценой |
onContentProductDetailBeforeButtons | Перед кнопками покупки |
onContentProductDetailAfterButtons | После кнопок покупки |
Параметры: TYPE — название точки, arResult и arParams карточки товара. Обработчик возвращает строку HTML.
$eventManager->addEventHandler('slytek.skyshop', 'onContentProductDetailAfterPrice', function (Event $event) {
$arResult = $event->getParameter('arResult');
$weight = $arResult['PROPERTIES']['WEIGHT']['VALUE'] ?? '';
if ($weight === '') {
return;
}
return new EventResult(
EventResult::SUCCESS,
'<div class="product-note">Вес: ' . htmlspecialcharsbx($weight) . '</div>'
);
});Вывод кешируется вместе с карточкой товара, как и в событиях шаблонов.
Какие стандартные события обрабатывает модуль
Справочно — чтобы ваши обработчики не конфликтовали с модулем:
| Модуль | Событие | Что делает SkyShop |
|---|---|---|
| main | OnPageStart, OnBeforeProlog, OnEpilog | Подготовка страницы, обработка AJAX-запросов шаблона, вывод служебных данных |
| main | OnAfterUserAdd, OnAfterUserUpdate | Подписка на рассылку по галочке согласия |
| sale | OnSaleOrderBeforeSaved | Проверка минимальной суммы заказа |
| sale | OnSaleComponentOrderProperties | Заполнение свойств заказа |
| sale | OnSaleOrderSaved | Подписка на рассылку из оформления заказа |
| catalog | Product::OnAfterAdd, Product::OnAfterUpdate | Обновление служебного свойства наличия у товара |
| catalog | OnGetOptimalPrice | Цены по типу цен выбранного города |
| iblock | OnIBlockPropertyBuildList | Свои типы свойств: тип цены, склад, местоположение |