Перейти к содержимому

Свой тип пользовательского поля - регистрация, формы, значение

Заводим собственный тип пользовательского поля: когда штатных типов не хватает и значение надо хранить, показывать и проверять по своим правилам.

Решение

Регистрируем тип обработчиком события:

/local/php_interface/init.php
use Bitrix\Main\EventManager;
EventManager::getInstance()->addEventHandler('main', 'OnUserTypeBuildList',
['\\Vendor\\ColorType', 'getUserTypeDescription']);
// без подключения обработчика тип исчезает из списка, а значения перестают выводиться

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

Описываем класс типа:

namespace Vendor;
class ColorType {
public static function getUserTypeDescription(): array {
return [
'USER_TYPE_ID' => 'vendor_color', // уникальное имя типа
'CLASS_NAME' => self::class,
'DESCRIPTION' => 'Цвет',
'BASE_TYPE' => 'string', // тип хранения менять потом нельзя
];
}
}

Описание отдаёт имя типа, его класс и тип хранения значений. Имя должно быть уникальным среди всех решений на проекте, а тип хранения выбирается один раз: сменить его у заполненного поля означает потерять значения.

Рисуем поле в форме редактирования:

public static function getEditFormHTML(array $userField, array $htmlControl): string {
return sprintf('<input type="color" name="%s" value="%s">',
$htmlControl['NAME'], htmlspecialcharsbx($userField['VALUE'] ?? '#000000'));
}

Разметка формы ввода остаётся полностью на вашей стороне. Платформа передаёт имя поля и текущее значение, а как выглядит ввод - решает класс, и это же объясняет, почему свой тип стоит заводить только ради особенного ввода.

Проверяем значение и выводим его:

public static function checkFields(array $userField, $value): array {
return preg_match('/^#[0-9a-f]{6}$/i', (string)$value)
? [] : [['id' => $userField['FIELD_NAME'], 'text' => 'Ожидается цвет в формате #rrggbb']];
}
public static function getPublicViewHTML(array $userField, $value): string {
return '<span style="background:' . htmlspecialcharsbx($value) . '"></span>';
}

Проверка значения живёт в самом типе, а не в форме ввода. Значение приходит и из формы, и из кода, и из обмена, поэтому единственное надёжное место для правил - класс типа.

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

Бизнес-процессы видят добавленный свой тип поля далеко не сразу и не везде. Им нужно отдельное описание соответствия, иначе поле в списке свойств документа не появится, а значение из процесса не запишется.

Свой тип стоит заводить только ради особенного ввода или собственной проверки. Ради подписи и списка значений хватает штатных типов, а каждый свой тип - это код, который сопровождается годами.

Типичные проблемы

Тип пропал из списка после переноса сайта.

Файл с подключением обработчика не переехал вместе с остальным кодом. Без этого обработчика платформа о существовании типа не знает.

Значения полей стали пустыми.

Обработчик типа отключён, а поля этого типа в сущностях остались. Платформа не умеет показывать значение неизвестного ей типа.

После смены типа хранения значения исчезли.

Тип хранения задаётся при создании и меняться потом не должен. Перенос значений делают отдельным скриптом заранее, ещё до смены типа поля.

Свой тип не виден в бизнес-процессе.

Для бизнес-процессов свой тип описывается отдельно. Без описания поле в списке свойств документа не появляется.

В поле сохраняется что угодно.

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

Частые вопросы

Когда свой тип оправдан?

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

Где хранится значение своего типа?

В той же таблице значений, что и у штатных типов. Отличается только вид хранимых данных, заданный в описании.

Можно ли использовать свой тип у любой сущности?

Да, типы общие для платформы: поле такого типа заводится и у раздела, и у пользователя, и у заказа.

Что будет с данными, если удалить решение?

Значения останутся в базе, но показывать их будет нечем. Перед удалением тип меняют на штатный с переносом значений.

Смежное

Первоисточник