Перейти к содержимому

Универсальный список изнутри - инфоблок, поля и права

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

Механика

Список - это инфоблок внутри отдельного типа, выделенного под списки проекта. Модуль хранит имя этого типа своей настройкой и показывает в разделе только его инфоблоки.

Тип инфоблока задают один раз, ещё до создания первого списка проекта. Инфоблок, заведённый в другом типе, в разделе списков не появится, хотя данные его целы и доступны кодом.

У нового списка ровно одно поле, и это его название. Остальные поля заводит человек, подбирая тип под характер данных из двенадцати доступных вариантов.

Поле списка - это свойство инфоблока вместе с надстройкой над ним. Интерфейс списка добавляет к свойству свои настройки: обязательность, множественность, показ, сортировку и режим только для чтения.

Код поля остаётся единственной стабильной опорой для всего кода проекта. Числовой идентификатор свойства выдаёт база, и на соседнем стенде у того же поля он будет другим.

Значения полей лежат в таблицах свойств того самого инфоблока, в котором живёт список. Вторая версия хранения держит их в отдельных таблицах инфоблока, но способ обращения к значениям от версии не зависит.

Сортировку полей интерфейс описывает правилом «чем выше число, тем ниже поле». На деле это обычная сортировка по возрастанию, просто названная от обратного, и путает она почти каждого.

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

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

Записи хранит инфоблок, поэтому доступ к ним считается его средствами. В расширенном режиме прав он считается по элементам и разделам, и устаревшая проверка прав инфоблока отвечает там неверно.

Шаги

  1. Посмотреть в настройках модуля списков, какой тип инфоблока отведён спискам проекта.
  2. Найти нужный список среди инфоблоков этого типа и запомнить его числовой идентификатор.
  3. Прочитать поля списка как свойства инфоблока и сверить их коды с ожиданиями кода проекта.
  4. Проверить уровни доступа групп на инфоблок списка и режим управления его правами.
  5. Убедиться, что флаг бизнес-процессов у списка отвечает тому, ради чего список заводили.

Код

Смотрим, какой тип инфоблока отдан спискам:

\Bitrix\Main\Loader::includeModule('lists');
print_r(\Bitrix\Main\Config\Option::getForModule('lists'));
// среди настроек модуля лежит тип инфоблока, отведённый спискам проекта
// пустое значение означает, что раздел списков не к чему привязать

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

Находим сам список среди инфоблоков этого типа:

$rows = \Bitrix\Iblock\IblockTable::getList([
'filter' => ['=IBLOCK_TYPE_ID' => 'lists'],
'select' => ['ID', 'CODE', 'NAME', 'VERSION'],
])->fetchAll();
foreach ($rows as $row) {
printf("%-5d %-16s %s версия=%d\n", $row['ID'], $row['CODE'], $row['NAME'], $row['VERSION']);
}
// VERSION показывает, как хранятся значения полей этого списка
// CODE одинаков на стендах, а числовой идентификатор у каждого стенда свой

Версия хранения свойств определяет таблицы значений, а не способ обращения к ним. Вторая версия держит значения в отдельных таблицах инфоблока и выбирает их одним запросом без лишних соединений.

Читаем поля списка как свойства инфоблока:

$res = CIBlockProperty::GetList(['SORT' => 'ASC'], ['IBLOCK_ID' => $listIblockId]);
while ($prop = $res->Fetch()) {
printf("%-4d %-14s %s/%s сорт=%d\n", $prop['ID'], $prop['CODE'],
$prop['PROPERTY_TYPE'], $prop['USER_TYPE'], $prop['SORT']);
}
// PROPERTY_TYPE: S строка, N число, L список, F файл, E элемент, G раздел
// USER_TYPE уточняет базовый тип: HTML, Date, DateTime и другие

Тип поля из интерфейса списка раскладывается на пару из базового и пользовательского типа свойства. Именно эта пара определяет форму ввода значения и способ фильтрации записей списка.

Заводим поле списка кодом:

$prop = new CIBlockProperty();
$id = $prop->Add([
'IBLOCK_ID' => $listIblockId, 'NAME' => 'Статус', 'CODE' => 'STATUS',
'PROPERTY_TYPE' => 'L', 'SORT' => 100, // меньше число - выше поле в форме
'VALUES' => [['VALUE' => 'новая'], ['VALUE' => 'в работе']],
]);

Код свойства обязателен при создании, и придумывают его один раз на всю жизнь списка. Без кода обращаться к полю придётся по числовому идентификатору, который перенос на другой стенд не переживает.

Читаем значения записи по кодам её полей:

$res = CIBlockElement::GetList([], ['IBLOCK_ID' => $listIblockId, 'ID' => $elementId],
false, false, ['ID', 'NAME', 'PROPERTY_STATUS']);
$row = $res->GetNext();
printf("%s: %s\n", $row['NAME'], $row['PROPERTY_STATUS_VALUE']);
// у списочного свойства приходит текст варианта, а номер лежит в PROPERTY_STATUS_ENUM_ID

Смотрим уровни доступа групп к записям:

print_r(CIBlock::GetGroupPermissions($listIblockId)); // уровни доступа по группам
// D доступа нет, R чтение, W изменение, X полный доступ вместе с правами
// пустой ответ означает, что уровни на вкладке доступа списка не выданы

Проверяем право на конкретную запись:

$can = CIBlockElementRights::UserHasRightTo($listIblockId, $elementId, 'element_read');
var_dump($can); // проверка работает и в простом, и в расширенном режиме прав
// устаревший CIBlock::GetPermission при расширенных правах отвечает неверно

Смотрим процессы над записью списка:

if (\Bitrix\Main\Loader::includeModule('bizproc')) {
print_r(CBPStateService::GetDocumentStates(['lists', 'BizprocDocument', $elementId]));
}
// запись списка приходит процессам документом из модуля, класса и номера записи

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

Ограничения

Модуля нет в младших редакциях: Старт, Стандарт и Малый бизнес. Закладывать списки в решение для этих редакций нельзя, и задачу там решают обычными инфоблоками.

Интерфейс списка выносит наружу не все настройки свойства инфоблока. Часть параметров правится только в карточке самого инфоблока, и это стоит учитывать при проектировании структуры.

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

Набор параметров поля зависит от выбранного типа и при смене типа перезагружается. Единого набора опций для всех двенадцати типов полей не существует, и проверять его приходится глазами.

Между стендами переносится структура списка, а не числовые идентификаторы его частей. Тип инфоблока, настройка модуля, поля с кодами и права групп задаются на боевом сайте заново.

Типичные проблемы

Готовый инфоблок подключили к списку, а его свойства в списке не видны.

Список ведёт своё описание полей поверх свойств инфоблока, и у чужого инфоблока его нет. Поля заводят через интерфейс списка, тогда описание появляется вместе со свойством.

Свой тип инфоблока не выбирается в источнике данных компонента списков.

В настройках модуля списков этому типу не выдан доступ, и компонент его не предлагает. Прямое указание типа в параметрах даёт ошибку прав вместо содержимого списка.

В таблице списка не видно колонок начиная со второй.

Настройка колонок ломается стилями главного грида на старом ядре платформы. Лечится обновлением ядра, а до обновления - правкой стиля окна настройки колонок.

Полю задали большое число сортировки, а оно ушло вниз формы.

Сортировка полей идёт по возрастанию, и большее число опускает поле ниже соседних. Формулировка интерфейса описывает то же правило от обратного и сбивает почти каждого.

Значение по умолчанию у поля не задаётся.

Оно доступно только полям с включённым флагом обязательности заполнения. Необязательному полю платформа задать значение по умолчанию не даёт вовсе.

Менеджер видит пустой список, а администратор видит все записи.

Права выданы на инфоблок, а сам инфоблок переведён в расширенный режим прав. В нём доступ считают по элементам и разделам, и проверяют его правами элемента.

Частые вопросы

Можно ли создать универсальный список на готовом инфоблоке?

Привязать инфоблок к списку получится, но своих полей у него не появится. Список ведёт описание полей поверх свойств, и заводят его через интерфейс списка.

Где хранятся данные элементов списка?

В таблицах свойств того самого инфоблока, в котором живёт список. Версия хранения решает, лежат значения в общей таблице или в отдельных таблицах инфоблока.

Чем поле списка отличается от свойства инфоблока?

Свойство хранит значения, а поле списка добавляет к нему настройки показа. Обязательность, множественность, сортировка и режим только для чтения задаются на стороне списка.

Как связать универсальный список с полем в бизнес-процессе?

Полем типа привязки к элементам, указав ему инфоблок нужного списка. Пустой выбор в таком поле означает, что записей в списке ещё нет.

Что из списка переносится между стендами?

Структура: тип инфоблока, сам список, поля с их кодами и права групп. Числовые идентификаторы и настройка модуля на новом стенде задаются заново.

Смежное

Первоисточник