Пользовательские поля у своей сущности - регистрация, запись, чтение
Вешаем пользовательские поля на свой объект: код сущности, регистрация поля, запись и чтение значений и честные границы такого механизма.
Что нужно знать заранее
Пользовательские поля не привязаны к инфоблокам и пользователям. Код сущности - это произвольная строка, и повесить набор полей можно на любой свой объект, включая записи своей таблицы.
Значения таких полей хранятся отдельно от самой записи вашей сущности. Их пишут и читают через менеджер полей по коду сущности и идентификатору записи, а не полем в своей таблице.
Такие поля не участвуют в выборках и фильтрах по вашей сущности. Отфильтровать записи по значению поля одним запросом не получится: у объекта нет таблицы, к которой платформа могла бы присоединить значения.
Шаги
- Выбрать код сущности и записать его в константу своего модуля один раз.
- Зарегистрировать нужные поля ровно один раз при установке своего модуля.
- Для полей-списков добавить варианты значений отдельным вызовом при установке.
- Писать и читать значения только через менеджер пользовательских полей платформы.
- Заранее решить, как искать записи: обычными полями таблицы, а не пользовательскими.
Решение
Регистрируем поле у своей сущности:
$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]);// метод рисует поля в административной форме своей сущностиШтатный вывод избавляет от ручной вёрстки каждого типа поля. Свой список, дата, файл и привязка к сотруднику отрисуются так же, как в карточке элемента инфоблока, без единой строки разметки.
Типичные проблемы
В интерфейсе появилось два одинаковых поля.
Регистрация поля выполняется при каждом запуске, а не один раз при установке. Проверяют наличие поля перед созданием или регистрируют его в установщике модуля.
Значения списка не добавились и ошибок нет.
Ключ нового значения списка не начинается с нужной буквы. Требование здесь жёсткое: без правильного ключа вызов проходит совершенно вхолостую.
Не получается отфильтровать записи по такому полю.
У своей сущности нет таблицы, к которой платформа присоединила бы значения. Для отбора и сортировки заводят обычное поле своей таблицы.
Поле не появилось в форме своей страницы.
Вывод полей не подключён: платформа рисует их только по явному вызову. Форму дополняют штатным методом вывода полей своей сущности.
Значения потерялись после удаления записи.
Значения живут отдельно от записи и сами не удаляются вместе с ней. Их чистят своим кодом при удалении записи, иначе они копятся годами.
Частые вопросы
Когда брать такие поля, а когда своё поле таблицы?
Пользовательские поля хороши там, где набор полей меняет администратор без разработчика. Всё, по чему нужен отбор и сортировка, делают обычными полями своей таблицы.
Какие типы полей доступны?
Те же, что у инфоблоков и пользователей: строка, число, дата, список, файл, привязка к сотруднику. Свой тип добавляется отдельно, как и для остальных сущностей.
Нужен ли свой модуль для регистрации полей?
Не обязательно, но крайне желательно: установщик модуля - естественное место для такой регистрации. Иначе поля появляются из случайного скрипта и теряются при переносе.
Как показать поля на витрине?
Прочитать значения менеджером и вывести своим шаблоном. Штатный вывод рассчитан на административные формы, а не на публичную часть.
Что будет при переносе на другой сайт?
Поля переносят отдельно: это не часть вашей таблицы. Их регистрируют миграцией вместе со структурой, а значения переносят своим скриптом.
Смежное
- Пользовательские поля - оглавление подтемы
- Пользовательское поле: заведение, вывод значения, типы - те же поля у штатных сущностей
- Свой тип пользовательского поля: регистрация, формы, значение - когда штатных типов мало
- Поля разделов и пользователей: выборка, множественные значения, файлы - чтение значений у штатных объектов
- Своя сущность от таблицы до админки: слои, права, интерфейс - куда встраивают такие поля
- Свой модуль: структура, установка, автозагрузка - где живёт регистрация полей
- Пользовательские поля - устройство механизма целиком
- Пользовательское поле изнутри: описание, значение, вывод - что связывает код сущности со значениями