Как настроить отбор в иерархическом динамическом списке без использования RLS в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке интерфейсов на управляемых формах часто возникает задача ограничить видимость элементов и групп справочника для разных пользователей. Например, в справочнике Номенклатура необходимо показывать каждой группе пользователей только «свои» папки и позицию товара, исключив доступ к чужой иерархии. Если при этом заказчик просит обойтись без применения механизмов ограничения прав на уровне записей (RLS), разработчик сталкивается со специфическим поведением платформы «1С:Предприятие».

Разберем подробно, с какими сложностями мы сталкиваемся при такой постановке задачи и какими способами можно реализовать гибкий отбор в динамическом списке.

Выясним причину: почему обычный отбор не скрывает вышестоящие группы?

Проанализируем поведение системы при стандартной настройке отборов. Когда таблица формы отображает динамический список в режиме «Иерархический список» или «Дерево», платформа специально сохраняет в структуре вышестоящие родительские узлы. Даже если вышестоящая папка не соответствует условиям установленного отбора, система отобразит её, чтобы не нарушать целостность древовидного дерева.

Поле Родитель обрабатывается платформой особым образом для обеспечения навигации. Поэтому стандартные отборы системы компоновки данных (СКД), а также произвольные условия в запросе динамического списка по дополнительным реквизитам или флагам доступа не приводят к скрытию «пустых» узлов-предков. В результате пользователь видит развернутую цепочку пустых папок, внутри которых отображаются только разрешенные узлы.

Вариант 1. Упрощение структуры иерархии справочника

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

  1. Верхний уровень: исключительно группы (папки).
  2. Вложенный уровень: только элементы справочника.

В этом случае мы можем добавить в группу справочника реквизит ГруппаДоступаНоменклатуры со ссылкой на соответствующий справочник прав или перечисление. Установив обычный отбор по реквизиту Родитель.ГруппаДоступаНоменклатуры или ГруппаДоступаНоменклатуры, мы избавимся от проблемы глубоких пустых узлов, так как иерархия станет строго фиксированной.

Вариант 2. Переключение режима отображения динамического списка

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

Программно или через палитру свойств изменим режим отображения:

Элементы.Список.РежимОтображения = РежимОтображенияТаблицы.Список;

В плоском списке механизмы отбора СКД работают напрямую без учета древовидных связей. Все элементы и папки, не подпадающие под условия отбора, скрываются полностью, не оставляя никаких пустых узлов.

Вариант 3. Разделение интерфейса на две связанные таблицы

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

  1. Первая таблица (дерево/список групп): содержит только доступные пользователю группы номенклатуры. Отбор накладывается на список папок.
  2. Вторая таблица (список элементов): отображает элементы текущей группы, выбранной в первой таблице.

Связь реализуется через свойство ОтображениеРодителя или программно при активизации строки первой таблицы с помощью установки параметра отбора Родитель во втором динамическом списке:


&НаКлиенте
Процедура СписокГруппПриАктивизацииСтроки(Элемент)
    ТекущиеДанные = Элемент.ТекущиеДанные;
    Если ТекущиеДанные <> Неопределено Тогда
        ОтборРодитель = СписокЭлементов.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
        ОтборРодитель.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Родитель");
        ОтборРодитель.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
        ОтборРодитель.ПравоеЗначение = ТекущиеДанные.Ссылка;
        ОтборРодитель.Использование = Истина;
    КонецЕсли;
КонецПроцедуры

Вариант 4. Ограничение выборки через регистр сведений и соединение в запросе

Рассмотрим вариант, когда необходимо скрыть элементы ещё на уровне запроса динамического списка. Для этого создадим регистр сведений ПраваДоступаКНоменклатуре с измерениями Пользователь (или ГруппаПользователей) и Номенклатура.

При изменении прав или регламентным заданием регистр заполняется развернутым списком всех доступных объектов (включая все вложенные элементы и папки). В произвольном запросе динамического списка настраиваем соединение:


ВЫБРАТЬ
    СправочникНоменклатура.Ссылка КАК Ссылка,
    СправочникНоменклатура.Наименование КАК Наименование,
    СправочникНоменклатура.Код КАК Код
ИЗ
    Справочник.Номенклатура КАК СправочникНоменклатура
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ПраваДоступаКНоменклатуре КАК Права
        ПО Права.Номенклатура = СправочникНоменклатура.Ссылка
ГДЕ
    Права.Пользователь = &ТекущийПользователь

Данный подход гарантирует отсечение недоступных записей на уровне СУБД без использования RLS, однако требует поддержания актуальности данных в регистре сведений.

Вариант 5. Использование отбора по иерархии (ВидСравнения.ВИерархии)

Проанализируем программный отбор с использованием вида сравнения ВИерархии. Если пользователю разрешен доступ к определенным корневым группам, мы можем передать массив этих групп в элемент отбора СКД:


МассивРазрешенныхГрупп = ПолучитьДоступныеГруппыДляПользователя();

ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Ссылка");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВИерархии;
ЭлементОтбора.ПравоеЗначение = МассивРазрешенныхГрупп;
ЭлементОтбора.Использование = Истина;

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

Сравнение альтернативных методов с механизмом RLS

Подведем итоги и сравним рассмотренные методы с механизмом RLS (Record Level Security):

← На главную