Разработка конструктора форм на 1С-Битрикс
Конструктор форм — инструмент, позволяющий менеджеру или маркетологу самостоятельно создавать произвольные формы без разработчика. Добавить поле, изменить порядок, задать валидацию, настроить куда отправлять данные — всё через веб-интерфейс. 1С-Битрикс имеет встроенный модуль form (Веб-формы), но у него есть серьёзные ограничения: устаревший интерфейс, отсутствие адаптивного UI, сложность интеграции с внешними системами. Кастомный конструктор решает эти ограничения.
Что хранить
Форма — это метаданные (набор полей и правила) плюс результаты (заполненные данные). Хранение через HL-блоки:
Таблица форм (b_hl_form_builder):
class FormBuilderTable extends \Bitrix\Main\ORM\Data\DataManager
{
public static function getTableName(): string { return 'b_hl_form_builder'; }
public static function getMap(): array
{
return [
new IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
new StringField('TITLE'),
new StringField('SLUG'), // URL-идентификатор
new TextField('FIELDS_JSON'), // Описание полей
new TextField('SETTINGS_JSON'), // Настройки формы
new BooleanField('IS_ACTIVE', ['values' => [false, true]]),
new IntegerField('SUBMISSIONS_COUNT'),
new DatetimeField('CREATED_AT'),
];
}
}
FIELDS_JSON — массив полей с полной конфигурацией:
[
{
"id": "field_name",
"type": "text",
"label": "Ваше имя",
"placeholder": "Иван Иванов",
"required": true,
"width": "half"
},
{
"id": "field_phone",
"type": "tel",
"label": "Телефон",
"required": true,
"mask": "+7 (000) 000-00-00",
"width": "half"
},
{
"id": "field_service",
"type": "select",
"label": "Услуга",
"options": ["Разработка", "Аудит", "Поддержка"],
"required": true
},
{
"id": "field_message",
"type": "textarea",
"label": "Сообщение",
"rows": 4,
"required": false
}
]
SETTINGS_JSON — поведение формы:
{
"submit_text": "Отправить заявку",
"success_message": "Спасибо! Мы свяжемся с вами.",
"redirect_url": null,
"send_email": "[email protected]",
"crm_integration": {
"enabled": true,
"entity_type": "LEAD",
"source_id": "WEB",
"responsible_id": 5
},
"notification_template": "FORM_SUBMIT"
}
Таблица результатов (b_hl_form_submissions):
class FormSubmissionTable extends \Bitrix\Main\ORM\Data\DataManager
{
public static function getTableName(): string { return 'b_hl_form_submissions'; }
public static function getMap(): array
{
return [
new IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
new IntegerField('FORM_ID'),
new TextField('DATA_JSON'), // Заполненные данные
new StringField('USER_IP'),
new StringField('USER_AGENT'),
new IntegerField('USER_ID'), // NULL если анонимный
new IntegerField('CRM_ENTITY_ID'),// ID созданного лида/сделки
new DatetimeField('CREATED_AT'),
];
}
}
Интерфейс конструктора (административная часть)
Интерфейс — drag-and-drop редактор полей. Реализуется в /local/admin/form_builder.php или как отдельная React/Vue-страница в /local/assets/form-builder/.
Упрощённая версия — без drag-and-drop, просто добавление полей через кнопку и сортировка стрелками. Это быстрее в разработке и достаточно для большинства задач.
// Простой конструктор полей без drag-and-drop
class FormBuilder {
constructor(containerId) {
this.container = document.getElementById(containerId);
this.fields = [];
this.bindEvents();
}
addField(type) {
const id = 'field_' + Date.now();
const field = {id, type, label: '', required: false, options: []};
this.fields.push(field);
this.renderFields();
return field;
}
removeField(fieldId) {
this.fields = this.fields.filter(f => f.id !== fieldId);
this.renderFields();
}
moveField(fieldId, direction) {
const idx = this.fields.findIndex(f => f.id === fieldId);
if (direction === 'up' && idx > 0) {
[this.fields[idx-1], this.fields[idx]] = [this.fields[idx], this.fields[idx-1]];
} else if (direction === 'down' && idx < this.fields.length - 1) {
[this.fields[idx], this.fields[idx+1]] = [this.fields[idx+1], this.fields[idx]];
}
this.renderFields();
}
getFieldsJson() {
// Собрать актуальные значения из DOM
this.fields = this.fields.map(field => {
const row = this.container.querySelector(`[data-field-id="${field.id}"]`);
if (!row) return field;
return {
...field,
label: row.querySelector('.field-label').value,
required: row.querySelector('.field-required').checked,
placeholder: row.querySelector('.field-placeholder')?.value || '',
};
});
return JSON.stringify(this.fields, null, 2);
}
}
Рендер формы на фронтенде
Компонент-рендерер читает JSON конфигурацию и строит HTML формы:
// /local/components/local/form.builder.render/class.php
class FormBuilderRenderComponent extends \CBitrixComponent
{
public function executeComponent(): void
{
$formSlug = $this->arParams['FORM_SLUG'] ?? '';
$form = FormBuilderTable::getList([
'filter' => ['SLUG' => $formSlug, 'IS_ACTIVE' => true],
])->fetch();
if (!$form) {
$this->arResult['NOT_FOUND'] = true;
$this->includeComponentTemplate();
return;
}
$form['FIELDS'] = json_decode($form['FIELDS_JSON'], true) ?? [];
$form['SETTINGS'] = json_decode($form['SETTINGS_JSON'], true) ?? [];
$this->arResult = [
'FORM' => $form,
'SESSID' => bitrix_sessid(),
];
$this->includeComponentTemplate();
}
}
В template.php — итерация по $arResult['FORM']['FIELDS'] с switch по типу поля.
Обработчик сабмита
Универсальный обработчик работает с любой формой через FORM_ID:
// /local/ajax/form_builder_submit.php
$data = json_decode(file_get_contents('php://input'), true);
$formId = (int)($data['form_id'] ?? 0);
$form = FormBuilderTable::getByPrimary($formId)->fetch();
if (!$form || !$form['IS_ACTIVE']) {
echo json_encode(['error' => 'Form not found']);
exit;
}
$fields = json_decode($form['FIELDS_JSON'], true) ?? [];
$settings = json_decode($form['SETTINGS_JSON'], true) ?? [];
// Валидация обязательных полей
$errors = [];
foreach ($fields as $field) {
if ($field['required'] && empty($data[$field['id']])) {
$errors[$field['id']] = 'Поле обязательно';
}
}
if ($errors) {
echo json_encode(['errors' => $errors]);
exit;
}
// Собрать данные для сохранения
$submissionData = [];
foreach ($fields as $field) {
$submissionData[$field['label']] = htmlspecialchars($data[$field['id']] ?? '');
}
// Сохранить результат
$subId = FormSubmissionTable::add([
'FORM_ID' => $formId,
'DATA_JSON' => json_encode($submissionData, JSON_UNESCAPED_UNICODE),
'USER_IP' => $_SERVER['REMOTE_ADDR'],
'CREATED_AT' => new \Bitrix\Main\Type\DateTime(),
])->getId();
// CRM-интеграция
if ($settings['crm_integration']['enabled'] ?? false) {
// Найти поля name/phone/email по типу
$nameField = $this->findFieldByType($fields, 'text');
$phoneField = $this->findFieldByType($fields, 'tel');
$emailField = $this->findFieldByType($fields, 'email');
\Bitrix\Main\Loader::includeModule('crm');
$lead = new \CCrmLead(false);
$lead->Add([
'TITLE' => $form['TITLE'] . ': ' . ($data[$nameField['id']] ?? 'Новый лид'),
'NAME' => $data[$nameField['id']] ?? '',
'PHONE' => [['VALUE' => $data[$phoneField['id']] ?? '', 'VALUE_TYPE' => 'WORK']],
'EMAIL' => [['VALUE' => $data[$emailField['id']] ?? '', 'VALUE_TYPE' => 'WORK']],
'SOURCE_ID' => 'WEB',
'COMMENTS' => json_encode($submissionData, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT),
]);
}
echo json_encode(['success' => true]);
Сроки разработки
| Вариант | Состав | Срок |
|---|---|---|
| Базовый конструктор | Управление полями, сохранение, рендер | 8–12 дней |
| С CRM-интеграцией | + Лиды, маппинг полей, уведомления | 12–18 дней |
| Drag-and-drop + аналитика | + Визуальный редактор, статистика форм | 18–28 дней |







