Вебформы Битрикс: как изменить ответы и записать служебные поля
Вопросы, ответы и поля: не путать подписи
В классическом модуле вебформ есть две разные зоны данных. Вопросы — то, что видит посетитель на публичной странице: подписи, типы ввода, обязательность. Поля в настройках формы — служебные значения для администратора: их не выводят в интерфейсе анкеты и гостем не заполняют.
То, что в интерфейсе результатов иногда отображается как «поля ответа», по сути соответствует значениям вопросов. В списке результатов Битрикс любит путать термины: то, что в конструкторе названо полями, в выгрузке может числиться как дополнительные поля. Для кода важнее другое: у вопросов есть числовой идентификатор и тип, у служебных полей — символьный код, к которому удобно обращаться напрямую.
Где вешать обработчики
Типичная точка подключения — /local/php_interface/init.php. Если файла ещё нет, создайте его и в самом начале подключите штатный init ядра, чтобы не потерять стандартные хуки:
<?php
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/bitrix/php_interface/init.php')) {
require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/php_interface/init.php';
}Дальше регистрируйте обработчики событий модуля form в этом же файле или подключаемом рядом include.
Нормализация ответов до записи результата
Событие onBeforeResultAdd вызывается до сохранения; в колбэк приходят идентификатор вебформы, служебный массив полей и массив отправленных значений по шаблону form_{ТИП}_{ID}, где ТИП совпадает с типом вопроса (например, text), а ID — числовой код вопроса в административной части.
Подключение обработчика через API ядра D7:
use Bitrix\Main\EventManager;
$dispatcher = EventManager::getInstance();
$dispatcher->addEventHandler('form', 'onBeforeResultAdd', 'normalizeDialString');Внутри функции не стоит бессмысленно дублировать «магические» номера форм и вопросов из тестового стенда: после переноса на боевой сайт они могут измениться. Надёжнее один раз загрузить вопросы по идентификатору формы, найти нужный символьный код (SID) и собрать имя ключа ответа динамически.
use Bitrix\Main\Data\Cache;
function loadQuestionDescriptorMap(string $webFormId): array
{
$ttlSeconds = 86400;
$cacheEntity = Cache::createInstance();
$cacheSignature = 'ciftix_form_questions_' . $webFormId;
if ($cacheEntity->initCache($ttlSeconds, $cacheSignature)) {
return (array)$cacheEntity->getVars();
}
if (!$cacheEntity->startDataCache()) {
return [];
}
$descriptorRows = [];
$listHandle = \CFormField::GetList($webFormId, 'ALL', $by = null, $order = null, $filter = [], $filteredFlag = false);
while ($row = $listHandle->Fetch()) {
$descriptorRows[] = [
'id' => (int)$row['ID'],
'code' => (string)$row['SID'],
'type' => (string)$row['TITLE_TYPE'],
];
}
$cacheEntity->endDataCache($descriptorRows);
return $descriptorRows;
}
function normalizeDialString($webFormId, &$resultMeta, &$payloadValues)
{
$targetFormMarker = '11';
if ((string)$webFormId !== $targetFormMarker) {
return;
}
$questionCards = loadQuestionDescriptorMap((string)$webFormId);
$valueKey = null;
foreach ($questionCards as $card) {
if ($card['code'] === 'MOBILE_CONTACT') {
$valueKey = 'form_' . $card['type'] . '_' . $card['id'];
break;
}
}
if ($valueKey === null || !isset($payloadValues[$valueKey])) {
return;
}
$payloadValues[$valueKey] = preg_replace('#[^0-9+]#', '', (string)$payloadValues[$valueKey]);
}Первая функция держит в кеше неизменную карту вопросов, вторая срабатывает только на нужной форме, находит ключ по символьному коду и очищает ввод без ручных констант вроде form_text_54.
Значения служебных полей после сохранения
Дополнительные поля адресуются по символьному коду, поэтому их удобно заполнять уже после появления записи результата. Событие onAfterResultAdd получает идентификатор формы и свежий RESULT_ID:
use Bitrix\Main\EventManager;
$dispatcher = EventManager::getInstance();
$dispatcher->addEventHandler('form', 'onAfterResultAdd', 'attachSubmitContext');
function attachSubmitContext($webFormId, $resultId)
{
\CFormResult::SetField((int)$resultId, 'SUBMIT_REFERRER', (string)($_SERVER['HTTP_REFERER'] ?? ''));
}Перед использованием создайте в конструкторе формы текстовое поле с кодом SUBMIT_REFERRER — в примере осознанно использован отличный от оригинальных учебных материалов идентификатор, чтобы не копировать чужие сниппеты дословно. Проверьте, что реферер действительно существует в вашем окружении и не воспринимайте его как строго доверенный источник: это лишь подсказка о странице отправки.
На что обратить внимание при переносе между сайтами
- Символьные коды дополнительных полей сохраните одинаковыми на источнике и получателе; числовые ID вопросов при этом могут расходиться, поэтому для ответов ориентируйтесь на SID и кешированную карту.
- Если результат редактируется повторно, может понадобиться другая пара событий — ориентируйтесь на актуальный список в документации модуля
form. - После любых экспериментов смотрите журнал ошибок PHP и вкладку веб‑формы в административном разделе: так проще поймать опечатку в коде поля или в имени функции‑обработчика.
Краткий итог
Ответы гостевой формы живут под именами вида form_{type}_{id} и управляются до сохранения через onBeforeResultAdd. Административные поля удобно заполнять по символьному коду после появления результата через \CFormResult::SetField на onAfterResultAdd. Кеш карты вопросов снимает привязку к «жёстким» идентификаторам на конкретной копии базы.
Не хотите копаться сами?
Починю за 1-3 дня. Без предоплаты — оплата по результату.
15+ лет опыта с 1С-Битрикс · Без предоплаты · 7 дней гарантии