Посмотрим, как свойства "работают" для объектов "Пользователи".
Коротко процесс выглядит так:
1)выведем закладку со свойствами в форме редактирования пользователя;
2)изменим класс CUser, чтобы сохранять введенные значения;
3)изменим класс CUser, чтобы возвращать значения свойств;
4)выведем значения свойств в списке пользователей.
[spoiler]
1. Форма редактирования пользователя. Файл /bitrix/modules/main/admin/user_edit.php.
Зададим где-то сверху уникальный для проекта идентификатор объектов, используемый для связывания свойств и конкретных сущностей:
$PROPERTY_ID = "USER"; |
Затем в коде, который инициализирует массив закладок для формы редактирования, добавим свою закладку:
$aTabs[] = $USER_FIELD_MANAGER->EditFormTab($PROPERTY_ID); |
Глобальная переменная $USER_FIELD_MANAGER - это объект специального класса CUserTypeManager - менеджера набираемых свойств. Это по сути единственный класс, с которым нам придется иметь дело.
После последней закладки на форме мы выводим свою:
$tabControl->BeginNextTab(); $USER_FIELD_MANAGER->EditFormShowTab($PROPERTY_ID, ((strLen($strError) > 0) ? true : false), $ID); |
В методе EditFormShowTab() второй параметр содержит признак ошибки ввода данных, третий равен идентификатору редактируемого объекта. Метод сам выводит на закладке все добавленные поля для данного типа объектов (в нашем случае - для всех пользователей).
Теперь нам нужно передать введенные на закладке данные в функции API для сохранения в БД.
В блоке сохранения данных if($REQUEST_METHOD=="POST" ...) после инициализации массива значений $arFields добавим вызов:
$USER_FIELD_MANAGER->EditFormAddFields($PROPERTY_ID, $arFields); |
Данный метод дополняет массив $arFields значениями свойств из формы редактирования. После этого массив можно передавать в API-функции Add() и Update(), как обычно.
2. Сохранение значений свойств. Файл /bitrix/modules/main/classes/general/user.php.
Сначала необходимо проверить введенные значения, т.к. в настройках свойств могут быть заданы ограничивающие параметры. Для этого в методе CAllUser:CheckFields() мы после всех проверок добавим свою:
if(is_object($APPLICATION)) $APPLICATION->ResetException(); if (!$GLOBALS["USER_FIELD_MANAGER"]->CheckFields("USER", $ID, $arFields)) { if(is_object($APPLICATION) && $APPLICATION->GetException()) { $e = $APPLICATION->GetException(); $this->LAST_ERROR .= $e->GetString(); } else { $this->LAST_ERROR .= "Unknown error. "; } } |
Вызывается метод менеджера свойств CheckFields, который в случае ошибки выбрасывает исключение.
Затем поправим метод Update(). После основного запроса, сохраняющего данные, вставим вызов:
$GLOBALS["USER_FIELD_MANAGER"]->Update("USER", $ID, $arFields); |
Ничего неожиданного, передаем менеджеру идентификатор типа объектов, идентификатор конкретной записи, значения всех полей объекта пользователя. Менеджер сам разберется, какие из полей являются набираемыми свойствами по префиксу имени поля "UF_".
Аналогичный вызов нужно вставить в методе Add() после добавления основных значений.
Для удаления значений свойств при удалении записи мы в методе Delete() вызываем:
$GLOBALS["USER_FIELD_MANAGER"]->Delete("USER", $ID); |
Все, значения свойств добавляются, обновляются, удаляются вместе с основными полями.
Как же нам выбрать свойства для показа?
3. Выборка набираемых свойств. Файл /bitrix/modules/main/classes/mysql/user.php.
Основным методом для выборки данных пользователей является CUser::GetList. Давайте изменим его, чтобы метод возвращал также набираемые свойства. Примечательно, что свойства могут не только выбираться, но и участвовать в фильтре и сортировке записей.
Добавим в параметры метода GetList еще один:
function GetList(&$by, &$order, $arFilter=Array(), $arParams = Array()) |
Этот параметр будет содержать список свойств, которые нужно выбрать. Далее мы должны передать данные в "конструктор" запроса SQL, чтобы он составил правильный запрос с участием набираемых свойств (не забудем объявить экземпляр класса-менеджера глобальным):
global $DB, $USER, $USER_FIELD_MANAGER; $obUserFieldsSql = new CUserTypeSQL; $obUserFieldsSql->SetEntity("USER", "U.ID"); $obUserFieldsSql->SetSelect($arParams["SELECT"]); $obUserFieldsSql->SetFilter($arFilter); $obUserFieldsSql->SetOrder(array($by=>$order)); |
Конструктор запроса реализован в классе CUserTypeSQL. Соотвествующими методами мы устанавливаем название колонки таблицы, содержащий ID записи, список выбираемых полей, фильтр и сортировку.
Учтем порядок сортировки с помощью $obUserFieldsSql->GetOrder($by):
if(in_array(strtoupper($by),$arFields_all)) $strSqlOrder = " ORDER BY U.".strtoupper($by); elseif($s = $obUserFieldsSql->GetOrder($by)) $strSqlOrder = " ORDER BY ".strtoupper($s); else { $strSqlOrder = " ORDER BY U.TIMESTAMP_X "; $by = "timestamp_x"; } |
После набора в фильтр основных полей, добавим набираемые свойства:
$arSqlSearch[] = $obUserFieldsSql->GetFilter(); |
В строку основного запроса добавим список выбираемых полей $obUserFieldsSql->GetSelect() и список дополнительных таблиц $obUserFieldsSql->GetJoin("U.ID"):
$strSql = " SELECT $distinct U.*, ".$DB->DateToCharFunction("U.TIMESTAMP_X")." TIMESTAMP_X, ".$DB->DateToCharFunction("U.DATE_REGISTER")." DATE_REGISTER, ".$DB->DateToCharFunction("U.LAST_LOGIN")." LAST_LOGIN, ".$DB->DateToCharFunction("U.PERSONAL_BIRTHDAY", "SHORT")." PERSONAL_BIRTHDAY ".$obUserFieldsSql->GetSelect()." FROM b_user U $from1".$from1." ".$obUserFieldsSql->GetJoin("U.ID")." WHERE $strSqlSearch $strSqlOrder "; |
Теперь нам осталось только внедрить полученные запросом данные в результат (после вызова $DB->Query()):
$res->SetUserFields($USER_FIELD_MANAGER->GetUserFields("USER")); |
В результате поля будут представлены с именами, заданными при настройке свойств ("UF_...").
Нам осталось попробовать GetList() на практике - показать значения свойств в списке пользователей в панели управления.
4. Список пользователей. Файл /bitrix/modules/main/admin/user_admin.php.
Для удобства добавим сверху файла:
$entity_id = "USER"; |
Поскольку свойства могут участвовать в фильтре, нам нужно добавить их в массив полей фильтра перед инициализацией фильтра:
$USER_FIELD_MANAGER->AdminListAddFilterFields($entity_id, $arFilterFields); $lAdmin->InitFilter($arFilterFields); |
Не забываем и про значения полей фильтра:
if(CheckFilter($arFilterFields)) { $arFilter = Array( ... ); $USER_FIELD_MANAGER->AdminListAddFilter($entity_id, $arFilter); } |
Фильтр выводится внизу страницы. Перейдем туда и добавим свойства в выпадающее меню фильтра:
$arFindFields = array( ... ); $USER_FIELD_MANAGER->AddFindFields($entity_id, $arFindFields); $oFilter = new CAdminFilter( $sTableID."_filter", $arFindFields ); |
Наконец, выведем свойства в HTML фильтра перед показом кнопок $oFilter->Buttons():
$USER_FIELD_MANAGER->AdminListShowFilter($entity_id); |
Вернемся выше, туда, где строится список. Добавим свойства в массив колонок таблицы списка пользователей:
$arHeaders = array( ... ); $USER_FIELD_MANAGER->AdminListAddHeaders($entity_id, $arHeaders); $lAdmin->AddHeaders($arHeaders); |
Изменим вызов GetList(), передав туда список свойств для выборки (помните, мы добавляли параметр?):
$rsData = CUser::GetList($by, $order, $arFilter, array("SELECT" => $lAdmin->GetVisibleHeaderColumns())); |
Для вывода колонок, в цикле по строкам таблицы, после создания объекта строки $row, вставим код:
$USER_FIELD_MANAGER->AddUserFields($entity_id, $arRes, $row); |
Данные модификации позволили видеть свойства в фильтре, выводить в колонках списка, сортировать записи по значениям свойств.
Такие же шаги можно повторить в любом модуле для любых типов объектов. В частности, скоро выйдут изменения для секций инфоблоков, причем свойства можно будет набирать для секций каждого инфоблока отдельно.
"Ремонт вообще невозможно закончить, его можно только прекратить" (ц)