Оборачиваем обработчики событий коробки Битрикс24 в стандартный модуль

от автора

Привет, Хабр. Недавно я написал целый цикл статей по работе со смарт‑процессами, помогающий погрузить «непосвященного» человека в азы API коробочной версии, реализующего возможности управления смарт‑процессами и связанными с ними элементами. В рамках последней статьи, разъясняющей применение обработчиков события, от слушателей и интересующихся получил в личку много вопросов, связанных в целом с применением обработчиков событий в Битрикс24. В сегодняшней статье рассмотрим один из популярных практических кейсов — реализовать возможность управлять какими‑либо настройками обработчиков события из стандартной панели администратора Битрикс24.

Я понимаю, что руководств по сборке модулей Битрикс и на Хабре и в официальной документации достаточно много. Но на мой взгляд основная проблема таких руководств — это их объем (автор руководства пытается расписать все возможные файлы в составе модуля), что для начинающего неподготовленного пользователя (вспоминаю тут себя в начале карьеры Битрикс разработчика) может быть трудным к пониманию. Я ни в коем случае не утверждаю, что авторы данных материалов написали их плохо, на определенном этапе развития специалистам нужны и полные материалы целиком, поэтому своих читателей такие материалы конечно же найдут. Мои же статьи в данном цикле рассчитаны на аудиторию, только начинающую делать первые шаги в Битрикс разработке, потому упрощение пойдет им определенно на пользу.

Если что, основная статья начинается отсюда 🙂

В сегодняшней статье‑туториале мы соберем модуль для Битрикс24, реализующий добавление и удаление обработчиков события, а также страницу настроек, позволяющую включать и отключать эти обработчики для определенных воронок сделки. Многоязычность пока для простоты понимания реализовывать не будем. Может, разберем данный вопрос в следующих статьях. Пишите в комментариях, если хотите что‑то разобрать в следующих статьях цикла.

Если обратиться к принятым стандартам разработки BitrixFramework, системные модули и модули, загружаемые из 1С‑Битрикс: Маркетплейс, располагаются в папке /bitrix/modules/. У нас же модуль полностью кастомный, его структуру мы будем создавать в папке /local/modules/.

Начинаем создание модуля

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

Соответственно создаем папку для нашего модуля по пути /local/modules/learnevents.

Разбирать полный состав файлов модуля мы не будем, писал выше почему. Далее будем создавать минимальный набор файлов, который нам понадобится для решения нашей задачи.

Папка install

Первой создаем папку /local/modules/learnevents/install. В ней будут находиться файлы, отвечающие за установку и удаление нашего модуля.

Первым в папке создаем файл /local/modules/learnevents/install/version.php следующего содержания:

<?php $arModuleVersion = [ 'VERSION' => '1.0.0', 'VERSION_DATE' => '2025-05-13', ];

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

Далее создаем основной файл установщика модуля /local/modules/learnevents/install/index.php. В коде будут поясняющие комментарии:

<?php  use Bitrix\Main\ModuleManager;  //Основной класс установщика модуля, должен наследоваться от системного класса CModule class learnevents extends CModule {     //Системный идентификатор модуля, должен совпадать с названием класса     public $MODULE_ID = 'learnevents';     //Версия модуля и дата. Оставляем пустыми так как подгрузим нужные в конструкторе     public $MODULE_VERSION;     public $MODULE_VERSION_DATE;     //Название модуля, выводимое в админ панели     public $MODULE_NAME = 'Управляемые обработчики';     //Описание модуля, выводимое в админ панели     public $MODULE_DESCRIPTION = 'Тестовый модуль, показывающий возможности управления обработчиками события';     //Адрес сайта разработчика модуля     public $PARTNER_URI = 'https://site.ru';     //Не использовать права доступа к модулю на основе групп пользователей     public $MODULE_GROUP_RIGHTS = 'N';      //Основной конструктор класса, в котором мы читаем файл version.php и берем оттуда версию модуля и дату релиза     public function __construct()     {         $arModuleVersion = [];          include __DIR__ . '/version.php';          if (is_array($arModuleVersion) && array_key_exists('VERSION', $arModuleVersion)) {             $this->MODULE_VERSION = $arModuleVersion['VERSION'];             $this->MODULE_VERSION_DATE = $arModuleVersion['VERSION_DATE'];         }     }      //Метод, устанавливающий обработчики события при установке модуля     public function InstallEvents()     {         $eventManager = \Bitrix\Main\EventManager::getInstance();         $eventManager->registerEventHandler("crm",             "OnBeforeCrmDealAdd",//Событие, на которое вешаем обработчик             $this->MODULE_ID,//Идентификатор модуля, берем текущий             "Learn\\Event\\Main",//PHP Класс с неймспейсом, в котором реализован метод обработчика             "RunEvent"//Название метода-обработчика         );         //Далее код других обработчиков         return true;     }      //Метод, удаляющий обработчики события при удалении модуля     public function UnInstallEvents()     {         $eventManager = \Bitrix\Main\EventManager::getInstance();         $eventManager->unRegisterEventHandler("crm",             "OnBeforeCrmDealAdd",//Событие, на которое вешаем обработчик             $this->MODULE_ID,//Идентификатор модуля, берем текущий             "Learn\\Event\\Main",//PHP Класс с неймспейсом, в котором реализован метод обработчика             "RunEvent"//Название метода-обработчика         );         //Далее код других обработчиков         return true;     }      //Метод, запускающийся при установке модуля     public function DoInstall()     {         $this->InstallEvents();//Запускаем установку обработчиков         ModuleManager::registerModule($this->MODULE_ID);//Регистрируем модуль в системе как установленный     }       //Метод, запускающийся при удалении модуля     public function DoUninstall()     {         $this->UnInstallEvents();//Запускаем удаление обработчиков         ModuleManager::unRegisterModule($this->MODULE_ID);//Снимаем регистрацию модуля в системе     }   }

Далее добавляем файл /local/modules/learnevent/install/unstep1.php. Он будет отвечать за страничку, которая появляется перед удалением модуля в панели администратора:

<? //Если пользователь не авторизован, прерываем метод if(!check_bitrix_sessid()) return; echo CAdminMessage::ShowNote('Управляемые обработчики'); ?> <form action="<?=$APPLICATION->GetCurPage(); ?>"> <?=bitrix_sessid_post(); ?> <input type="hidden" name="step" value="2"> <input type="hidden" name="id" value="learnevent"> <input type="hidden" name="uninstall" value="Y"> <input type="submit" name="nextstep" value="Далее"> <input type="submit" name="cancel" value="Отменить"> </form>

Часто на данную страничку добавляют сообщения для тех, кто собирается удалить модуль, например «Пожалуйста, не удаляйте! Мы еще можем быть полезны».:-)

Папка lib

В данной папке традиционно размещаются классы модуля, которые будут автоматически подключены при его установке. В нашем случае создаем файл /local/modules/learnevent/lib/main.php:

namespace Learn\Event;  use Bitrix\Main\Config\Option;  class Main {      /**      * @return array|false Массив направлений сделки      * @description Возвращает массим текущих направлений сделок, поднадобится в админке      */     public static function getDealFunnels()     {         //Проверяем активен ли модуль CRM. Без него никакие Сделки доступны не будут         if (\Bitrix\Main\Loader::includeModule('crm')) {             //Получаем ООП Фабрику работы со сделками             $factory = \Bitrix\Crm\Service\Container::getInstance()->getFactory(                 \CCrmOwnerType ::Deal             );             //Получаем массив всех объектов направлений и делаем перебор             $categories = $factory->getCategories();             $arCategories = [];             foreach ($categories as $category) {                 //Получаем данные каждого направления и записываем в массив                 $arCategories[] = $category->getData();             }             return $arCategories;         } else {             return false;         }     }       /**      * @return array|false Результат обработчика      * @description Обработчик, который мы подключаем через модуля      */     public static function RunEvent(&$arFields)     {         //Проверяем, установлен ли флажок "Активно" в админке         if (Option::get("learnevent", "ACTIVE") == "Y") {             global $USER;             //Получаем список пользователей             $userExeptions = unserialize(Option::get("learnevent", "USER_EXEPTIONS"));             $pipeline = Option::get("learnevent", "PIPELINE");             if ((is_array($userExeptions) && in_array($USER->GetID(), $userExeptions)) || $userExeptions == $USER->GetID()) {                                     if (isset($arFields['CATEGORY_ID']) && !empty($arFields['CATEGORY_ID']) && ($arFields['CATEGORY_ID'] == $pipeline)) {                         //Какие-то действия, если наше условие сработало. Например прерываем создание Сделки                         $arFields['RESULT_MESSAGE'] = "Извините, данному пользователю запрещено создавать Сделку в данной воронке!";                         return false;                     }                          }          }     } }

В данном файле можно разместить методы для других обработчиков. Также никто не запрещает повесить несколько разных методов на одно событие.

Корневая папка модуля

Теперь перейдем к одному из важнейших файлов, который реализует окно настроек модуля в панели администрирования Битрикс24. Этот файл по стандарту лежит в папке модуля и носит название options.php. В нашем случае создаем его по пути /local/modules/learnevent/options.php и добавляем туда код:

<?php //Подключаем нужные нам неймспейсы и скрипты use \Bitrix\Main\Loader,     \Bitrix\Main\Config\Option;  require_once $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_admin_before.php';  require_once $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_admin_after.php';  global $APPLICATION;  $moduleName = 'learnevent'; if (!Loader::IncludeModule($moduleName)) {     return; }  //Проверяем права доступа, если их нет - перекидываем на форму авторизации $POST_RIGHT = $APPLICATION->GetGroupRight($moduleName); if ($POST_RIGHT == "D")     $APPLICATION->AuthForm(GetMessage("ACCESS_DENIED"));  //Получаем данные POST Запроса если настройки изменены, проводим фильтрацию данных для безопасности $request = Bitrix\Main\Application::getInstance()->getContext()->getRequest(); $request->addFilter(new \Bitrix\Main\Web\PostDecodeFilter);  //Сохраняем настройки модуля в системные опции (таблица b_option в БД) if ($POST_RIGHT == "W" && check_bitrix_sessid() && $request->isPost()) {     COption::SetOptionString($moduleName, 'ACTIVE', $request->get('ACTIVE'));     COption::SetOptionString($moduleName, 'PIPELINE', $request->get('PIPELINE'));          //Так как у нас может быть множественное значение а база можно хранить только единицное - делаем сериализацию массива в строку     COption::SetOptionString($moduleName, 'USER_EXEPTIONS', serialize($request->get('USER_EXEPTIONS'))); }  //Инициализируем табы админки, у нас таб будет один $tabs = [     [         'DIV' => 'main',         'TAB' => 'Настройки',         'ICON' => '',     ] ]; $tabControl = new \CAdminTabControl('tabControl', $tabs); //Далее добавляем форму с полями настроек, которые будут выводиться в админке ?>      <form method="POST"           action="<? echo $APPLICATION->GetCurPage() ?>?mid=<?= urlencode($mid) ?>&lang=<? echo LANGUAGE_ID ?>"           ENCTYPE="multipart/form-data" name="post_form">         <?= bitrix_sessid_post() ?>         <?php         $tabControl->Begin();         $tabControl->BeginNextTab();         ?>         <?//Поле "Обработчик активен"?>         <tr>             <td>Обработчик активен</td>             <td><input type="checkbox" name="ACTIVE"                        value="Y" <?php if (Option::get($moduleName, 'ACTIVE') == "Y") echo 'checked'; ?>/></td>         </tr>         <?//Поле "Воронка Сделки". Далее получаем массив воронок и текущую настройку?>         <tr>             <?php $allCategories = \Learn\Event\Main::getDealFunnels(); ?>             <?php $currentCategory = Option::get($moduleName, 'PIPELINE'); ?>             <td>Воронка Сделки</td>             <td>                 <select name="PIPELINE">                     <?php foreach ($allCategories as $allCategory) { ?>                         <option value="<?= $allCategory['ID'] ?>"<?php if ($allCategory['ID'] == $currentCategory) echo ' selected'; ?>><?= $allCategory['NAME'] ?></option>                     <?php } ?>                 </select>             </td>         </tr>         <?//Поле "Для пользователей". Множественный выбор пользователей для которых будет срабатывать обработчик.?>         <tr>             <?php $userCurId = unserialize(Option::get($moduleName, 'USER_EXEPTIONS')); ?>             <?php $order = array('sort' => 'asc');             $tmp = 'sort'; // параметр проигнорируется методом, но обязан быть             $rsUsers = \CUser::GetList($order, $tmp);             $allUsers = [];             while ($arUser = $rsUsers->Fetch()) {                 $allUsers[$arUser["ID"]] = "[" . $arUser["ID"] . "] " . $arUser["NAME"] . " " . $arUser["LAST_NAME"];             } ?>             <td>Для пользователей</td>             <td>                 <select name="USER_EXEPTIONS[]" multiple>                     <?php foreach ($allUsers as $userID => $userName) { ?>                         <option value="<?= $userID ?>"<?php if ((is_array($userCurId) && in_array($userID, $userCurId)) || $userCurId == $userID) echo ' selected'; ?>><?= $userName ?></option>                     <?php } ?>                 </select>             </td>         </tr>         <? $tabControl->End(); ?>         <input type="submit" value="Сохранить">     </form> <?php require_once $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/epilog_admin.php'; ?>

Данный файл реализует стандартную страницу настроек нашего модуля в разделе панели администратора Битрикс (Настройки — Настройки продукта — Настройки модулей — Управляемые обработчики).

Вместо заключения

Выше мы разобрали минимально необходимый набор файлов, реализующих модуль для Битрикс24, устанавливающий обработчики события, и хранящий настройки для них. Модуль содержит минимальный набор системных методов для того, чтобы Битрикс воспринимал его именно как модуль, а не как набор скриптов непонятного назначения. Всем спасибо за внимание и жду нашей встречи в следующих статьях!


Если вы работаете с коробочной версией Битрикс24 и хотите глубже разобраться в механике событий — их типах, регистрации и возможностях для управления сущностями, обратите внимание на предстоящий открытый урок «События в Битрикс24: Путеводитель по изменениям».

Разберёмся в архитектуре событийной модели и обсудим, как эффективно внедрять собственные сценарии обработки изменений. Старт 21 мая в 20:00 — участие бесплатное, нужно только зарегистрироваться.

А в календаре мероприятий можно записаться на открытые уроки по другим ИТ-направлениям.


ссылка на оригинал статьи https://habr.com/ru/articles/909170/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *