Yandex Metrika
sanches.free 17 просмотров

Вебформы Битрикс: как изменить ответы и записать служебные поля

Вопросы, ответы и поля: не путать подписи

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

То, что в интерфейсе результатов иногда отображается как «поля ответа», по сути соответствует значениям вопросов. В списке результатов Битрикс любит путать термины: то, что в конструкторе названо полями, в выгрузке может числиться как дополнительные поля. Для кода важнее другое: у вопросов есть числовой идентификатор и тип, у служебных полей — символьный код, к которому удобно обращаться напрямую.

Где вешать обработчики

Типичная точка подключения — /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 дней гарантии