Отрисовка пользовательских полей в главном модуле
Главный модуль выводит пользовательские поля в публичной части, административных формах, списках и фильтрах. Механизм нужен, когда код уже получил описание пользовательского поля и должен показать его значение как HTML. За вывод отвечают методы менеджера CUserTypeManager и класс Bitrix\Main\UserField\Renderer.
Как создать поле, хранить значения и какие типы доступны, читайте в статье Пользовательские поля. Как создать свой тип поля или компонент main.field.*, читайте в статье Типы и компоненты пользовательских полей в главном модуле.
Подготовить поле для вывода
Получите описание поля через $USER_FIELD_MANAGER->GetUserFields(). Методы вывода берут значение из ключа VALUE в описании, если оно не передано отдельно параметром VALUE.
global $USER_FIELD_MANAGER;
$userId = 1;
$userFields = $USER_FIELD_MANAGER->GetUserFields('USER', $userId, LANGUAGE_ID);
$userField = $userFields['UF_PHONE'] ?? null;
Во всех примерах ниже переменная $userField содержит описание поля из первого блока.
Формат значения зависит от типа поля. Передавайте:
-
в строковое поле — строку,
-
в множественное поле — массив значений,
-
в поле сложного типа — формат, который определяет сам тип.
Компоненты main.field.* приводят переданное значение к массиву перед выводом и добавляют к имени контрола множественного поля суффикс [].
Вывести поле в публичной части
Публичная часть сайта показывает значение поля как готовый текст, разметку или контрол формы. Отдельно можно получить значение без разметки. Выберите способ вывода:
-
GetPublicView()— готовое значение, -
GetPublicEdit()— контрол для формы редактирования, -
Renderer— значение в режиме, который задан явно, -
getPublicText()— значение без разметки.
Первые три способа принимают дополнительные параметры вторым аргументом, все ключи в нем необязательные. Метод getPublicText() дополнительных параметров не принимает.
Показать значение поля
Метод GetPublicView() возвращает HTML для просмотра значения. Передайте в него описание поля.
if ($userField)
{
echo $USER_FIELD_MANAGER->GetPublicView($userField);
}
Имя HTML-контрола менеджер берет из ключа FIELD_NAME в описании поля. Параметр NAME задает другое имя, а параметр VALUE — значение, которого нет в описании.
if ($userField)
{
echo $USER_FIELD_MANAGER->GetPublicView(
$userField,
[
'NAME' => 'user_phone',
'VALUE' => '+7 900 000-00-00',
]
);
}
Показать контрол редактирования
Метод GetPublicEdit() возвращает HTML-контрол для изменения значения в публичной форме.
if ($userField)
{
echo $USER_FIELD_MANAGER->GetPublicEdit($userField);
}
Метод принимает те же дополнительные параметры, что и GetPublicView(). Если форму уже отправили и контрол нужно заполнить отправленными данными, добавьте bVarsFromForm со значением true.
if ($userField)
{
echo $USER_FIELD_MANAGER->GetPublicEdit(
$userField,
[
'bVarsFromForm' => true,
]
);
}
По умолчанию параметр равен false, и компонент main.field.* берет значение из описания поля.
Задать режим вывода через Renderer
Класс Bitrix\Main\UserField\Renderer выводит поле в режиме, который задан явно. Передайте в конструктор описание поля и режим, а затем вызовите render().
use Bitrix\Main\UserField\Renderer;
use Bitrix\Main\UserField\Types\BaseType;
if ($userField)
{
$renderer = new Renderer(
$userField,
[
'mode' => BaseType::MODE_VIEW,
]
);
echo $renderer->render();
}
Режим задают константы класса BaseType:
-
BaseType::MODE_VIEW— публичный просмотр, -
BaseType::MODE_EDIT— публичное редактирование.
Остальные шесть режимов главный модуль подставляет сам: административная форма объекта, форма настроек поля, фильтр и ячейки административного списка, значение без разметки. Их константы закрыты, но имена режимов совпадают с именами папок шаблонов компонента. Полный список смотрите в статье Типы и компоненты пользовательских полей в главном модуле.
Класс Renderer не загружает поле сам. Передайте в него готовый массив описания поля со значением.
После создания объект Renderer можно перенастроить. Каждый метод меняет свою часть:
-
setAdditionalParameter()— значение одного дополнительного параметра, в том числе режимаmode, -
setAdditionalParameters()— весь набор дополнительных параметров, -
setUserField()— описание поля.
Каждый метод возвращает сам объект, поэтому вызовы можно выстроить в цепочку.
use Bitrix\Main\UserField\Renderer;
use Bitrix\Main\UserField\Types\BaseType;
if ($userField)
{
echo (new Renderer($userField))
->setAdditionalParameter('mode', BaseType::MODE_EDIT)
->setAdditionalParameter('NAME', 'user_phone')
->render()
;
}
Режим передавайте только ключом mode в дополнительных параметрах. У класса есть метод setMode(), но на результат render() он не влияет: метод пишет значение в свойство объекта, а render() передает компоненту лишь дополнительные параметры. Без ключа mode компонент возьмет шаблон .default.
Метод render() возвращает null, если у класса типа нет метода renderField(). Такие типы выводите методами менеджера.
Получить значение без разметки
Метод getPublicText() возвращает текстовое представление значения. Менеджер передает работу одноименному методу класса типа. Если класс типа такой метод не объявляет, менеджер объединяет значения через запятую.
if ($userField)
{
echo $USER_FIELD_MANAGER->getPublicText($userField);
}
Типы на базе BaseType возвращают значение уже экранированным: его готовит шаблон режима main.public_text. Повторно применять htmlspecialcharsbx() не нужно, иначе спецсимволы экранируются дважды.
Используйте текстовое представление в уведомлениях, журналах и других местах, где HTML-разметка не нужна.
Вывести поле в административной форме
Административная форма получает готовую строку таблицы с подписью поля, подсказкой и HTML-контролом. Выводить можно одно поле или все поля объекта сразу.
Показать строку одного поля
Метод GetEditFormHTML() формирует строку для одного поля. Вставьте результат в таблицу формы.
if ($userField)
{
echo $USER_FIELD_MANAGER->GetEditFormHTML(
false,
$userField['VALUE'],
$userField
);
}
Метод принимает три позиционных аргумента:
-
$bVarsFromForm— брать ли значение из отправленной формы,trueилиfalse. Методы публичной части принимают тот же признак ключомbVarsFromFormв дополнительных параметрах. -
$form_value— текущее значение поля. -
$arUserField— описание пользовательского поля.
Показать все поля объекта
Методы EditFormTab() и EditFormShowTab() выводят в форму все поля объекта сразу, без ручного обхода. Первый возвращает описание отдельной вкладки, второй заполняет ее строками полей.
global $USER_FIELD_MANAGER;
$entityId = 'MY_ENTITY';
$itemId = 12;
$tabs = [
['DIV' => 'edit1', 'TAB' => 'Элемент', 'TITLE' => 'Параметры элемента'],
$USER_FIELD_MANAGER->EditFormTab($entityId),
];
$tabControl = new CAdminTabControl('tabControl', $tabs);
В теле формы перейдите на вкладку и выведите поля.
$tabControl->BeginNextTab();
$USER_FIELD_MANAGER->EditFormShowTab($entityId, false, $itemId);
Метод EditFormShowTab() сам вызывает GetEditFormHTML() для каждого поля объекта. Если у текущего пользователя есть право на запись, метод дополнительно выводит ссылку на страницу настройки пользовательских полей.
Значения из отправленной формы соберите методом EditFormAddFields() и передайте в Update().
$fields = [];
$USER_FIELD_MANAGER->EditFormAddFields($entityId, $fields);
$USER_FIELD_MANAGER->Update($entityId, $itemId, $fields);
Метод EditFormAddFields() собирает значения из $_POST и $_FILES только для полей, у которых EDIT_IN_LIST имеет значение Y.
Какие настройки поля попадают в строку формы
Подпись и оформление строки метод GetEditFormHTML() берет из настроек самого поля:
-
EDIT_FORM_LABEL— подпись поля, а без нее метод подставляетFIELD_NAME, -
HELP_MESSAGE— подсказка рядом с подписью, ее видят пользователи с правом на запись, -
MANDATORY— со значениемYдобавляет отметку обязательного поля.
Настройку EDIT_IN_LIST обрабатывает не сам метод, а шаблон типа. Со значением N шаблоны выводят контрол заблокированным, а поля date и datetime показывают значение вместо контрола.
Где настройки задают в интерфейсе, читайте в статье Пользовательские поля.
Вывести поле в административном списке
В списке поле появляется в трех местах: как колонка, как значение в ячейке и как строка фильтра. За каждое место отвечает свой метод менеджера.
Добавить колонки
Метод AdminListAddHeaders() дописывает колонки пользовательских полей в массив заголовков списка.
global $USER_FIELD_MANAGER;
$entityId = 'MY_ENTITY';
$adminList = new CAdminList('my_entity_list');
$headers = [
['id' => 'ID', 'content' => 'ID', 'sort' => 'ID'],
];
$USER_FIELD_MANAGER->AdminListAddHeaders($entityId, $headers);
$adminList->AddHeaders($headers);
Метод учитывает настройки поля:
-
SHOW_IN_LIST— со значениемYдобавляет колонку в список, -
LIST_COLUMN_LABEL— заголовок колонки, а без него метод подставляетFIELD_NAME, -
MULTIPLE— со значениемNразрешает сортировку по колонке.
Метод AddUserFields() добавляет значения в ячейки. Он обходит поля объекта и для каждого поля с настройкой SHOW_IN_LIST равной Y вызывает AddUserField(). Тот формирует HTML значения и кладет его в строку списка. Поля, которых нет в массиве строки, метод пропускает.
В примере переменная $result — результат выборки объектов, которые попадают в список.
while ($item = $result->Fetch())
{
$row = $adminList->AddRow($item['ID'], $item);
$USER_FIELD_MANAGER->AddUserFields($entityId, $item, $row);
}
Метод getListView() возвращает готовый HTML значения без привязки к строке списка.
$html = $USER_FIELD_MANAGER->getListView($userField, $userField['VALUE']);
Добавить фильтр
Фильтр списка собирают три метода.
-
AdminListAddFilterFields()добавляет имена контролов фильтра видаfind_UF_PHONE. Для полей с базовым типомdatetimeметод добавляет еще две границы диапазона —_fromи_to. -
AdminListShowFilter()выводит строки фильтра для всех подходящих полей. -
AdminListAddFilter()собирает условия выборки из значений, которые ввел пользователь.
Имена контролов и условия выборки готовьте до вывода списка.
global $USER_FIELD_MANAGER;
$entityId = 'MY_ENTITY';
$filterFields = ['find_id'];
$USER_FIELD_MANAGER->AdminListAddFilterFields($entityId, $filterFields);
$filter = [];
$USER_FIELD_MANAGER->AdminListAddFilter($entityId, $filter);
В форме фильтра выведите строки полей.
$USER_FIELD_MANAGER->AdminListShowFilter($entityId);
Все три метода пропускают поле, если SHOW_FILTER имеет значение N или базовый тип поля — file.
Метод AdminListAddFilter() строит условие выборки по значению SHOW_FILTER:
-
I— точное совпадение, условие=, -
S— поиск по подстроке, условие%, -
другое значение — поиск по маске, условие без префикса.
Для полей с базовым типом datetime метод строит условия >= и <= по границам диапазона.
Метод AddFindFields() отдает список полей, доступных для поиска. Подпись он берет из LIST_FILTER_LABEL, а без нее подставляет FIELD_NAME.
Разрешить правку значений в списке
Метод AdminListPrepareFields() убирает из массива значения полей, у которых EDIT_IN_LIST отличается от Y. Вызывайте его перед сохранением списка.
$USER_FIELD_MANAGER->AdminListPrepareFields($entityId, $fields);
Подключить скрипт полей
Метод ShowScript() добавляет в head-область скрипт /bitrix/js/main/usertype.js. Он нужен, потому что контролы части типов работают на JavaScript.
$USER_FIELD_MANAGER->ShowScript();
Метод AddUserField() вызывает ShowScript() сам, поэтому для административного списка отдельный вызов не нужен. В своих формах вызывайте метод один раз до вывода контролов.
Заменить стандартную отрисовку
Прежде чем подключить компонент типа, менеджер проверяет несколько точек расширения. Порядок для GetPublicView() и GetPublicEdit() такой:
-
Событие
onBeforeGetPublicViewилиonBeforeGetPublicEdit— обработчик получает описание поля и дополнительные параметры по ссылке и может их изменить. -
Событие
onGetPublicViewилиonGetPublicEdit— обработчик может вернуть готовый HTML, и тогда менеджер дальше не идет. -
Ключ
VIEW_CALLBACKилиEDIT_CALLBACK— сначала в описании поля, затем в описании типа. У типов на базеBaseTypeэтот ключ заполнен всегда: базовый класс подставляет в описание типа свои методыrenderView()иrenderEdit(), а те подключают компонент изRENDER_COMPONENT. -
Ключ
VIEW_COMPONENT_NAMEилиEDIT_COMPONENT_NAME— в том же порядке. Собственному типу на базеBaseTypeэти ключи не нужны: до них цепочка не доходит. -
Компонент
bitrix:system.field.viewилиbitrix:system.field.editс шаблоном по коду типа. -
Событие
onAfterGetPublicViewилиonAfterGetPublicEdit— обработчик получает готовый HTML по ссылке и может его изменить.
Описание типа — это массив, который возвращает обработчик события OnUserTypeBuildList. Ключ в описании поля перекрывает такой же ключ в описании типа, поэтому одно поле можно вывести иначе, чем остальные поля того же типа.
Событие onGetPublicView подменяет вывод для выбранных полей и не трогает остальные. Обработчик получает объект события, а готовый HTML возвращает объектом EventResult со статусом SUCCESS.
use Bitrix\Main\Event;
use Bitrix\Main\EventManager;
use Bitrix\Main\EventResult;
EventManager::getInstance()->addEventHandler(
'main',
'onGetPublicView',
static function (Event $event) {
$userField = $event->getParameter(0);
if (
($userField['FIELD_NAME'] ?? '') !== 'UF_PHONE'
|| ($userField['MULTIPLE'] ?? 'N') === 'Y'
)
{
return null;
}
$value = (string)($userField['VALUE'] ?? '');
if ($value === '')
{
return null;
}
$href = 'tel:' . preg_replace('/[^\d+]/', '', $value);
$html = '<a href="' . htmlspecialcharsbx($href) . '">'
. htmlspecialcharsbx($value)
. '</a>';
return new EventResult(EventResult::SUCCESS, $html);
}
);
Разместите регистрацию обработчика в файле local/php_interface/init.php, чтобы она выполнялась на каждой странице.
Обработчик читает параметры по числовым ключам:
-
$event->getParameter(0)— описание пользовательского поля, -
$event->getParameter(1)— дополнительные параметры вывода.
У событий onAfterGetPublicView и onAfterGetPublicEdit есть третий параметр с готовым HTML.
Пример рассчитан на одиночное поле. У множественного поля значение приходит массивом, поэтому обработчик такие поля пропускает — для них соберите разметку обходом всех значений.
Если обработчик возвращает null или другое пустое значение, менеджер идет по цепочке дальше и подключает стандартную отрисовку.
Обработчик VIEW_CALLBACK принимает описание поля и дополнительные параметры и возвращает готовый HTML.
$userField['VIEW_CALLBACK'] = static function (array $userField, array $additionalParameters) {
return '<b>' . htmlspecialcharsbx((string)$userField['VALUE']) . '</b>';
};
echo $USER_FIELD_MANAGER->GetPublicView($userField);
Обработчик в описании поля действует только на этот массив, а событие — на все вызовы отрисовки в проекте. Если разметку нужно изменить для типа поля целиком, создайте свой тип и компонент main.field.*.
Метод renderField() передает отрисовку классу типа напрямую. Если класс типа метод renderField() не объявляет, менеджер возвращает null.
$html = $USER_FIELD_MANAGER->renderField($userField);
Отрисовать форму настроек поля
Метод GetSettingsHTML() возвращает HTML дополнительных настроек типа поля. Он нужен, когда форму создания или изменения пользовательского поля строит свой код.
echo $USER_FIELD_MANAGER->GetSettingsHTML($userField);
Метод принимает два позиционных аргумента:
-
$arUserField— описание существующего поля или код типа, если поле еще не создано. -
$bVarsFromForm— со значениемtrueзаполняет настройки данными отправленной формы.
Метод возвращает null, если тип не зарегистрирован или у его класса нет метода getSettingsHtml(). У типов на базе BaseType метод есть всегда, поэтому вернется строка — при пустых настройках пустая.
Свой тип поля и компонент main.field.* описаны в статье Типы и компоненты пользовательских полей в главном модуле.
Методы менеджера и класс Renderer покрывают вывод готового поля во всех формах продукта. Когда стандартной разметки не хватает, начните с точек расширения из раздела Заменить стандартную отрисовку.