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

Пользовательские поля у своей сущности - регистрация, запись, чтение

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

Что нужно знать заранее

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

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

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

Шаги

  1. Выбрать код сущности и записать его в константу своего модуля один раз.
  2. Зарегистрировать нужные поля ровно один раз при установке своего модуля.
  3. Для полей-списков добавить варианты значений отдельным вызовом при установке.
  4. Писать и читать значения только через менеджер пользовательских полей платформы.
  5. Заранее решить, как искать записи: обычными полями таблицы, а не пользовательскими.

Решение

Регистрируем поле у своей сущности:

$type = new \CUserTypeEntity();
$fieldId = $type->Add([
'ENTITY_ID' => 'VENDOR_CONTRACT', // код сущности придумываем сами
'FIELD_NAME' => 'UF_MANAGER', // имя обязано начинаться с этого префикса
'USER_TYPE_ID' => 'employee', // тип поля: строка, число, список, сотрудник
'EDIT_FORM_LABEL' => ['ru' => 'Ответственный'],
]);

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

Добавляем варианты для поля-списка:

$enum = new \CUserFieldEnum();
$enum->SetEnumValues($fieldId, [
'n1' => ['VALUE' => 'Разовый', 'SORT' => 10, 'DEF' => 'Y'],
'n2' => ['VALUE' => 'Рамочный', 'SORT' => 20], // ключ новых значений начинается с n
]);

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

Пишем значение записи:

$manager = \Bitrix\Main\UserField\Internal\UserFieldHelper::getInstance()->getManager();
$manager->Update('VENDOR_CONTRACT', $contractId, ['UF_MANAGER' => $userId]);
// три аргумента: код сущности, идентификатор записи и массив значений
// менеджер берут через хелпер там, где глобального объекта ядра ещё нет

Читаем значения записи:

$value = $manager->GetUserFieldValue('VENDOR_CONTRACT', 'UF_MANAGER', $contractId);
$all = $manager->GetUserFields('VENDOR_CONTRACT', $contractId);
printf("ответственный=%s всего полей=%d\n", $value, count($all));

Чтение одного поля дешевле чтения всех. В списке записей поля читают пакетом по идентификаторам, иначе на странице из двадцати строк появляется двадцать лишних обращений к базе.

Выводим поля в своей форме:

$manager->EditFormAddFields('VENDOR_CONTRACT', ['ENTITY_ID' => $contractId]);
// метод рисует поля в административной форме своей сущности

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

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

В интерфейсе появилось два одинаковых поля.

Регистрация поля выполняется при каждом запуске, а не один раз при установке. Проверяют наличие поля перед созданием или регистрируют его в установщике модуля.

Значения списка не добавились и ошибок нет.

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

Не получается отфильтровать записи по такому полю.

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

Поле не появилось в форме своей страницы.

Вывод полей не подключён: платформа рисует их только по явному вызову. Форму дополняют штатным методом вывода полей своей сущности.

Значения потерялись после удаления записи.

Значения живут отдельно от записи и сами не удаляются вместе с ней. Их чистят своим кодом при удалении записи, иначе они копятся годами.

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

Когда брать такие поля, а когда своё поле таблицы?

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

Какие типы полей доступны?

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

Нужен ли свой модуль для регистрации полей?

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

Как показать поля на витрине?

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

Что будет при переносе на другой сайт?

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

Смежное

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