Участники и роли
Объект Bitrix\HumanResources\Item\NodeMember связывает пользователя с подразделением или командой. Для каждого узла объект хранит отдельный набор ролей пользователя.
Сервис Bitrix\HumanResources\Public\Service\NodeMemberService находит связи пользователей с узлами и участников с заданной ролью. С его помощью можно дополнить ORM-запрос Bitrix\Main\UserTable и получить данные пользователей вместе со сведениями об их подразделениях или командах.
Выбрать метод
Выбирайте метод сервиса Bitrix\HumanResources\Public\Service\NodeMemberService по исходным данным и ожидаемому результату.
|
Задача |
Метод |
Результат |
|
Найти подразделения или команды известных пользователей |
|
Коллекция связей пользователей с узлами |
|
Получить участников узла с заданным числовым идентификатором роли |
|
Коллекция участников узла |
|
Найти узлы пользователя по стандартным ролям |
|
Одна связь, |
|
Получить подразделения, которыми управляет пользователь |
|
Коллекция связей с подразделениями |
|
Добавить сведения об узлах в запрос к |
|
Дополненный ORM-запрос пользователей |
|
Сначала расположить пользователей из тех же подразделений, а руководителей — выше сотрудников |
|
ORM-запрос с добавленной сортировкой |
Получить сервис участников
Сервис Bitrix\HumanResources\Public\Service\NodeMemberService работает со связями участников подразделений и команд. Перед вызовом подключите модуль humanresources. Получите сервис через контейнер Bitrix\HumanResources\Public\Service\Container.
use Bitrix\HumanResources\Public\Service\Container;
use Bitrix\Main\Loader;
if (!Loader::includeModule('humanresources'))
{
throw new \RuntimeException('Требуется модуль humanresources');
}
$memberService = Container::getNodeMemberService();
Все следующие примеры используют переменную $memberService из этого блока.
Для работы с руководителями и подчиненными получите сервис Bitrix\HumanResources\Public\Service\Node\UserService с помощью метода Bitrix\HumanResources\Public\Service\Container::getUserService(). Сценарии работы с этим сервисом смотрите в статье Пользователи и управленческая иерархия.
Данные участника узла
Пользователь и участник узла — разные объекты. Для каждого узла сервис возвращает отдельный объект Bitrix\HumanResources\Item\NodeMember.
Объект Bitrix\HumanResources\Item\NodeMember содержит свойства связи. Обращайтесь к ним через объект, например $member->nodeId. Это не параметры метода: сервис заполняет свойства в возвращенном объекте. Знак ? перед типом означает, что свойство может содержать null.
|
Свойство |
Тип |
Назначение |
|
|
|
Идентификатор связи или |
|
|
|
Тип объекта участника |
|
|
|
Идентификатор объекта, для пользователя это его ID |
|
|
|
Идентификатор узла |
|
|
|
Признак активности участника или |
|
|
|
Идентификаторы ролей в результатах чтения |
|
|
|
Идентификатор роли для создания или изменения связи либо |
|
|
|
Строковое значение значка, по умолчанию пустая строка |
|
|
|
Идентификатор пользователя, который добавил участника, или |
|
|
|
Дата создания связи или |
|
|
|
Дата изменения связи или |
|
|
|
Объект связанного узла или |
Свойство node использует отложенную загрузку. Сервис загружает объект узла при первом обращении к свойству. Если достаточно идентификатора узла, используйте nodeId: обращение к нему не загружает связанный объект.
Найти связи пользователей с узлами
Для поиска связей участников с узлами используйте методы сервиса findAllByEntityIds() и findAllByRoleIdAndNodeId(). Они возвращают коллекцию Bitrix\HumanResources\Item\Collection\NodeMemberCollection. Она позволяет перебрать найденные связи и получить идентификатор узла и роли участника для каждой связи. Элемент коллекции — это объект Bitrix\HumanResources\Item\NodeMember. Пустая коллекция означает, что подходящих связей нет.
Используйте метод findAllByEntityIds(), чтобы определить, в каких подразделениях или командах состоят известные пользователи. Передайте их идентификаторы в entityIds и укажите нужные типы узлов в nodeTypes. По умолчанию метод ищет пользователей только в активных подразделениях.
Пример. Получить связи пользователей с подразделениями и командами.
use Bitrix\HumanResources\Type\NodeEntityType;
$userIds = [25, 31, 42];
// Сервис участников получен в первом примере
$members = $memberService->findAllByEntityIds(
entityIds: $userIds, // ID пользователей, связи которых нужно найти
nodeTypes: [
NodeEntityType::DEPARTMENT, // подразделения
NodeEntityType::TEAM, // команды
],
);
foreach ($members as $member)
{
echo "Пользователь {$member->entityId}, узел {$member->nodeId}\n";
}
Метод возвращает все найденные связи. Один пользователь может встретиться в коллекции несколько раз, если состоит в нескольких узлах или имеет несколько ролей в одном узле. Каждой роли соответствует отдельный элемент коллекции.
Ограничить поиск узлами и структурой
Передайте идентификаторы известных узлов в параметр nodeIds, чтобы найти связи только в этих узлах. Параметр structureId ограничивает поиск одной структурой, а structureAction — узлами, для которых текущему пользователю доступно указанное действие. Значение Bitrix\HumanResources\Enum\NodeActiveFilter::ONLY_GLOBAL_ACTIVE используется для параметра nodeActiveFilter по умолчанию.
use Bitrix\HumanResources\Enum\NodeActiveFilter;
use Bitrix\HumanResources\Type\NodeEntityType;
use Bitrix\HumanResources\Type\StructureAction;
$userId = 25;
$structureId = 1;
// Сервис участников получен в первом примере
$members = $memberService->findAllByEntityIds(
entityIds: [$userId], // ID пользователя
nodeIds: [10, 20, 30], // узлы, в которых нужно искать связь
nodeTypes: [NodeEntityType::DEPARTMENT], // только подразделения
structureId: $structureId, // структура, которой принадлежат узлы
structureAction: StructureAction::ViewAction, // доступные для просмотра узлы
nodeActiveFilter: NodeActiveFilter::ONLY_GLOBAL_ACTIVE, // стандартный фильтр активности
);
Найти участников узла по роли
Используйте метод findAllByRoleIdAndNodeId(), чтобы получить участников одного узла с заданной ролью. Передайте параметры:
-
roleId— числовой идентификатор роли из массиваrolesобъектаBitrix\HumanResources\Item\NodeMember, -
nodeId— идентификатор узла, -
limit— максимальное количество участников в результате, -
offset— смещение от начала результата, -
ascendingSort— порядок сортировки по идентификатору связи:true— по возрастанию,false— по убыванию.
// Сервис участников получен в первом примере
$roleId = null;
$nodeId = null;
foreach ($memberService->findAllByEntityIds(entityIds: [25]) as $member)
{
$roleId = $member->roles[0] ?? null;
if ($roleId !== null)
{
$nodeId = $member->nodeId;
break;
}
}
if ($roleId === null || $nodeId === null)
{
throw new \RuntimeException('У пользователя нет связи с ролью');
}
$members = $memberService->findAllByRoleIdAndNodeId(
roleId: $roleId, // ID роли из массива roles объекта NodeMember
nodeId: $nodeId, // узел, в котором нужно найти участников
limit: 50, // максимум 50 участников
offset: 0, // начать с первого участника
ascendingSort: true, // сортировать по возрастанию
);
Метод возвращает коллекцию Bitrix\HumanResources\Item\Collection\NodeMemberCollection. Пустая коллекция означает, что совпадений нет. Пустую коллекцию метод также возвращает, если roleId или nodeId равен 0, узел не найден либо роль не связана с указанным узлом.
Выбрать стандартную роль
Чтобы найти узлы пользователя по стандартным ролям, выберите метод сервиса Bitrix\HumanResources\Public\Service\Node\UserService:
-
findByUserIdAndRoleXmlIds()— возвращает одну связь илиnull, -
findAllByUserIdAndRoleXmlIds()— возвращает все подходящие связи в коллекцииBitrix\HumanResources\Item\Collection\NodeMemberCollection.
Передайте идентификатор пользователя в userId, а внешние идентификаторы ролей — в roleXmlIds. Перечисление Bitrix\HumanResources\Type\NodeMemberRole содержит внешние идентификаторы стандартных ролей подразделений и команд.
Роли подразделений:
-
NodeMemberRole::Head— руководитель, внешний идентификаторMEMBER_HEAD, -
NodeMemberRole::DeputyHead— заместитель, внешний идентификаторMEMBER_DEPUTY_HEAD, -
NodeMemberRole::Employee— сотрудник, внешний идентификаторMEMBER_EMPLOYEE.
Роли команд:
-
NodeMemberRole::TeamHead— руководитель команды, внешний идентификаторMEMBER_TEAM_HEAD, -
NodeMemberRole::TeamDeputyHead— заместитель руководителя команды, внешний идентификаторMEMBER_TEAM_DEPUTY_HEAD, -
NodeMemberRole::TeamEmployee— участник команды, внешний идентификаторMEMBER_TEAM_EMPLOYEE.
Пример. Найти подразделения и команды, где пользователь назначен руководителем.
use Bitrix\HumanResources\Public\Service\Container;
use Bitrix\HumanResources\Type\NodeMemberRole;
$userId = 25;
$userService = Container::getUserService();
$managedNodes = $userService->findAllByUserIdAndRoleXmlIds(
userId: $userId,
roleXmlIds: [
NodeMemberRole::Head->value, // руководитель подразделения
NodeMemberRole::TeamHead->value, // руководитель команды
],
);
Коллекция $managedNodes содержит связи пользователя с подразделениями и командами, где он назначен руководителем. Чтобы получить только первую подходящую связь, вызовите findByUserIdAndRoleXmlIds() с теми же аргументами. Пустой массив или массив без допустимых внешних идентификаторов ролей дает null для одиночного поиска и пустую коллекцию для множественного.
Дополнительные сценарии смотрите в статье Пользователи и управленческая иерархия.
Получить управляемые подразделения
Используйте метод getManagedDepartmentNodes(), чтобы получить подразделения, где пользователь назначен руководителем или заместителем. Метод работает только с узлами типа Bitrix\HumanResources\Type\NodeEntityType::DEPARTMENT и возвращает коллекцию Bitrix\HumanResources\Item\Collection\NodeMemberCollection.
Передайте идентификатор пользователя в userId. Параметр structureId ограничивает поиск одной структурой. Если передать null, сервис использует структуру по умолчанию.
Пример. Получить управляемые подразделения одной структуры.
$structureId = 1;
// Сервис участников получен в первом примере
$managedDepartments = $memberService->getManagedDepartmentNodes(
userId: 25,
structureId: $structureId, // ID нужной структуры
);
По свойству nodeId определите подразделение, а по массиву roles — роль пользователя в нем.
Добавить данные узлов в запрос пользователей
Чтобы получить пользователей из определенных подразделений или команд одним ORM-запросом, используйте injectUserNodeSubquery(). Метод дополняет запрос Bitrix\Main\UserTable связями с узлами и возвращает измененный объект Bitrix\Main\ORM\Query\Query.
Настройте выборку с помощью параметров:
-
query— запрос кBitrix\Main\UserTable, который нужно дополнить. -
nodeTypes— типы узлов. По умолчанию метод выбирает подразделения, значениеnullвключает все типы узлов. -
active— состояние связей:true— активные,false— неактивные,null— все связи. По умолчанию метод выбирает активные связи. -
nodeIds— идентификаторы узлов. Значениеnullили пустой массив включает все узлы выбранных типов.
Пример. Получить пользователей из двух активных подразделений.
use Bitrix\HumanResources\Type\NodeEntityType;
use Bitrix\Main\UserTable;
$query = UserTable::query()
->setSelect(['ID', 'NAME', 'LAST_NAME'])
;
// Сервис участников получен в первом примере
$query = $memberService->injectUserNodeSubquery(
query: $query,
nodeTypes: [NodeEntityType::DEPARTMENT], // только подразделения
active: true, // только активные связи участников
nodeIds: [10, 20], // подразделения, из которых нужны пользователи
);
$users = $query->exec();
После вызова продолжите настройку запроса или выполните его через exec().
Отсортировать пользователей по узлам и ролям
Используйте метод injectUserNodeSort(), чтобы сначала расположить пользователей из тех же подразделений, что и выбранный пользователь, а затем остальных. В каждой части результата руководители располагаются выше сотрудников.
Сначала вызовите injectUserNodeSubquery(). Он регистрирует поле USER_NODE_MEMBER, которое использует сортировка. Затем передайте дополненный запрос в query, а идентификатор выбранного пользователя — в userId.
Связи с несколькими узлами или ролями могут создать несколько строк для одного пользователя. Метод setDistinct() формирует результат с уникальными строками. Вызывайте его до выполнения или подсчета запроса, если результат должен содержать по одной строке на пользователя.
use Bitrix\Main\UserTable;
$currentUserId = 25;
$query = UserTable::query()
->setSelect(['ID', 'NAME', 'LAST_NAME'])
;
// Сервис участников получен в первом примере
$query = $memberService->injectUserNodeSubquery($query); // добавить связи с узлами
$query = $memberService->injectUserNodeSort(
query: $query,
userId: $currentUserId, // пользователь, чьи подразделения должны быть первыми
);
$query->setDistinct(); // по одной строке на пользователя
$users = $query->exec();
Обработать пустой результат и ошибки
Если метод вернул пустой результат, проверьте условия поиска:
-
модуль
humanresourcesподключен, -
идентификаторы пользователей, узлов, структуры и роли существуют,
-
nodeTypesсодержитBitrix\HumanResources\Type\NodeEntityType::TEAMдля выборки участников команд, -
фильтр активности включает целевые узлы или связи,
-
параметры
nodeIdsиstructureIdвключают целевые узлы, аlimitиoffsetне исключают нужные связи, -
текущему пользователю доступно действие из
structureAction.
Пустая коллекция Bitrix\HumanResources\Item\Collection\NodeMemberCollection — корректный результат поиска. Проверяйте количество элементов перед обработкой. Для результата одиночного поиска отдельно проверяйте значение null.
При работе с сервисом учитывайте следующие исключения:
|
Исключение |
На каком этапе возможно |
|
|
Подготовка поискового запроса и его аргументов |
|
|
Подготовка и чтение данных ORM |
|
|
Подготовка или выполнение операции сервиса |
|
|
Обработка элемента структуры компании |
|
|
Выполнение ORM-запроса через |
Обрабатывайте исключения на уровне приложения, где доступен контекст запроса и можно выбрать дальнейшее действие.
При поиске с structureAction ошибка построения фильтра доступа преобразуется в пустую коллекцию Bitrix\HumanResources\Item\Collection\NodeMemberCollection. Поиск без совпадений возвращает такой же результат. Для диагностики сохраняйте исходные идентификаторы и выбранное действие. Права пользователя проверяйте отдельно от содержимого коллекции.
Выбрать сервис или билдер
Выбирайте сервис Bitrix\HumanResources\Public\Service\NodeMemberService для типового поиска связей, выборки по одной роли и расширения запросов Bitrix\Main\UserTable. Используйте Bitrix\HumanResources\Builder\Structure\NodeMemberDataBuilder, когда один запрос должен объединить несколько фильтров по узлам, пользователям, ролям, иерархии или доступу.
Методы поиска и getManagedDepartmentNodes() читают существующие связи. Методы injectUserNodeSubquery() и injectUserNodeSort() изменяют только настройки переданного объекта Bitrix\Main\ORM\Query\Query. Запрос загружает данные после вызова exec().
Сервис Bitrix\HumanResources\Public\Service\NodeMemberService не изменяет роли участников. Для поиска и обхода подразделений и команд используйте сервис узлов. Для получения руководителей и подчиненных, проверки управленческих отношений и назначения пользователей в подразделения используйте сервисы управленческой иерархии.