По сути HL-блок - это обычная таблица в базе данных с набором колонок, которую создает и обслуживает Битрикс. У каждой записи есть ID и набор пользовательских полей, которые вы сами определяете.
Подключаем модуль highloadblock
Перед работой нужно убедиться, что модуль highloadblock подключен:
Bitrix\Main\Loader::includeModule('highloadblock');
use Bitrix\Highloadblock\HighloadBlockTable;
Создаем Highload-блок
Для создания используется метод HighloadBlockTable::add(). Ему нужно передать всего два параметра: NAME (имя класса, латиницей) и TABLE_NAME (имя таблицы в базе).
$result = HighloadBlockTable::add([
'NAME' => 'Brands',
'TABLE_NAME' => 'hl_brands',
]);
if ($result->isSuccess())
{
$hlblockId = $result->getId();
echo "HL-блок создан, ID = " . $hlblockId;
}
else
{
print_r($result->getErrors());
}
NAME будет использоваться как имя класса для ORM (например, BrandsTable). TABLE_NAME - это физическое имя таблицы в MySQL. Его можно указать любое, но принято использовать префикс hl_.
Добавляем поля через API
Сам по себе HL-блок бесполезен - у него есть только ID. Нужно добавить пользовательские поля. Для этого используется класс CUserTypeEntity.
Строка (string)
Допустим, наш HL-блок для брендов. Добавим строковое поле "Название":
$userField = new CUserTypeEntity();
$fieldId = $userField->Add([
'ENTITY_ID' => 'HLBLOCK_' . $hlblockId,
'FIELD_NAME' => 'UF_NAME',
'USER_TYPE_ID' => 'string',
'MANDATORY' => 'Y',
'EDIT_FORM_LABEL' => ['ru' => 'Название бренда', 'en' => 'Brand name'],
'LIST_COLUMN_LABEL' => ['ru' => 'Название', 'en' => 'Name'],
'LIST_FILTER_LABEL' => ['ru' => 'Название', 'en' => 'Name'],
'SETTINGS' => [
'SIZE' => 50,
'MIN_LENGTH' => 1,
'MAX_LENGTH' => 255,
'DEFAULT_VALUE' => '',
],
]);
if ($fieldId)
{
echo "Поле UF_NAME добавлено, ID = " . $fieldId;
}
ENTITY_ID собирается из префикса "HLBLOCK_" и ID вашего HL-блока. Это обязательное условие, иначе Битрикс не поймет, к какому HL-блоку относится поле.
Целое число (integer)
Добавим числовое поле "Сортировка":
$userField->Add([
'ENTITY_ID' => 'HLBLOCK_' . $hlblockId,
'FIELD_NAME' => 'UF_SORT',
'USER_TYPE_ID' => 'integer',
'EDIT_FORM_LABEL' => ['ru' => 'Сортировка'],
'SETTINGS' => [
'DEFAULT_VALUE' => 500,
'MIN_VALUE' => 0,
'MAX_VALUE' => 10000,
],
]);
Дробное число (double)
Если нужно число с плавающей точкой, например, курс валюты:
$userField->Add([
'ENTITY_ID' => 'HLBLOCK_' . $hlblockId,
'FIELD_NAME' => 'UF_RATE',
'USER_TYPE_ID' => 'double',
'EDIT_FORM_LABEL' => ['ru' => 'Курс'],
'SETTINGS' => [
'PRECISION' => 4, // количество знаков после запятой
'DEFAULT_VALUE' => 0,
],
]);
Да/Нет (boolean)
Поле-флажок. Например, "Активность":
$userField->Add([
'ENTITY_ID' => 'HLBLOCK_' . $hlblockId,
'FIELD_NAME' => 'UF_ACTIVE',
'USER_TYPE_ID' => 'boolean',
'EDIT_FORM_LABEL' => ['ru' => 'Активность'],
'SETTINGS' => [
'DEFAULT_VALUE' => 1,
'DISPLAY' => 'CHECKBOX',
],
]);
Дата (date) и Дата со временем (datetime)
Например, дата создания или дата проведения мероприятия:
// Только дата
$userField->Add([
'ENTITY_ID' => 'HLBLOCK_' . $hlblockId,
'FIELD_NAME' => 'UF_DATE',
'USER_TYPE_ID' => 'date',
'EDIT_FORM_LABEL' => ['ru' => 'Дата проведения'],
]);
// Дата и время
$userField->Add([
'ENTITY_ID' => 'HLBLOCK_' . $hlblockId,
'FIELD_NAME' => 'UF_DATETIME',
'USER_TYPE_ID' => 'datetime',
'EDIT_FORM_LABEL' => ['ru' => 'Дата и время создания'],
]);
Список (enumeration)
Поле с выпадающим списком. Например, "Статус" со значениями "Активен", "Неактивен", "В архиве".
// Сначала добавляем само поле
$fieldId = $userField->Add([
'ENTITY_ID' => 'HLBLOCK_' . $hlblockId,
'FIELD_NAME' => 'UF_STATUS',
'USER_TYPE_ID' => 'enumeration',
'EDIT_FORM_LABEL' => ['ru' => 'Статус'],
'SETTINGS' => [
'DISPLAY' => 'LIST', // LIST, CHECKBOX, UI_BOOLEAN
'LIST_HEIGHT' => 1,
],
]);
// Теперь добавляем варианты списка
$enums = new CUserFieldEnum();
$enums->SetEnumValues($fieldId, [
['VALUE' => 'Активен', 'SORT' => 10, 'XML_ID' => 'active', 'DEF' => 'Y'],
['VALUE' => 'Неактивен', 'SORT' => 20, 'XML_ID' => 'inactive', 'DEF' => 'N'],
['VALUE' => 'В архиве', 'SORT' => 30, 'XML_ID' => 'archived', 'DEF' => 'N'],
]);
Файл (file)
Поле для загрузки файла. Например, логотип бренда:
$userField->Add([
'ENTITY_ID' => 'HLBLOCK_' . $hlblockId,
'FIELD_NAME' => 'UF_LOGO',
'USER_TYPE_ID' => 'file',
'EDIT_FORM_LABEL' => ['ru' => 'Логотип'],
'SETTINGS' => [
'SIZE' => 20, // размер поля ввода
'LIST_WIDTH' => 100,
'LIST_HEIGHT' => 100,
'MAX_SHOW_SIZE' => 0,
'MAX_ALLOWED_SIZE' => 5242880, // 5 MB
],
]);
Привязка к другому Highload-блоку (hlblock)
Допустим, у нас есть HL-блок "Бренды" (Brands) и HL-блок "Товары" (Products). В товарах нужно указать бренд.
// Сначала узнаем ID HL-блока Products
$hlProducts = HighloadBlockTable::query()
->addSelect('ID')
->where('NAME', 'Products')
->exec()
->fetch();
if ($hlProducts)
{
$userField->Add([
'ENTITY_ID' => 'HLBLOCK_' . $hlProducts['ID'],
'FIELD_NAME' => 'UF_BRAND',
'USER_TYPE_ID' => 'hlblock',
'EDIT_FORM_LABEL' => ['ru' => 'Бренд'],
'SETTINGS' => [
'HLBLOCK_ID' => $hlblockId, // ID HL-блока Brands
'DISPLAY' => 'LIST',
'LIST_HEIGHT' => 1,
],
]);
}
Добавляем свои типы полей через UF
На самом деле типов полей для HL-блоков гораздо больше. Вот полный список USER_TYPE_ID, которые вы можете использовать:
- string - строка
- integer - целое число
- double - дробное число
- boolean - да/нет
- date - дата
- datetime - дата со временем
- file - файл
- enumeration - список
- hlblock - привязка к элементам highload-блоков
- iblock_element - привязка к элементам инфоблоков
- iblock_section - привязка к разделам инфоблоков
- employee - привязка к сотруднику
- crm - привязка к элементам CRM
- money - деньги
- url - ссылка
- address - адрес
- video - видео
Работа с данными: добавление записи
После того как HL-блок создан и поля добавлены, нужно скомпилировать ORM-класс и работать с ним.
$hlblock = HighloadBlockTable::getById($hlblockId)->fetch();
$entity = HighloadBlockTable::compileEntity($hlblock);
$entityDataClass = $entity->getDataClass();
// Добавляем новую запись
$result = $entityDataClass::add([
'UF_NAME' => 'Sony',
'UF_SORT' => 100,
'UF_ACTIVE' => 1,
'UF_DATE' => new Bitrix\Main\Type\Date(),
'UF_STATUS' => 'active',
]);
if ($result->isSuccess())
{
$newId = $result->getId();
echo "Добавлена запись с ID = " . $newId;
}
Выборка записей
Работает так же, как и с обычными ORM-сущностями. Можно фильтровать, сортировать, ограничивать выборку.
$hlblock = HighloadBlockTable::getById($hlblockId)->fetch();
$entity = HighloadBlockTable::compileEntity($hlblock);
$entityDataClass = $entity->getDataClass();
// Выбрать все активные записи, отсортированные по сортировке
$records = $entityDataClass::getList([
'select' => ['*'],
'filter' => ['UF_ACTIVE' => 1],
'order' => ['UF_SORT' => 'ASC'],
'limit' => 10,
]);
while ($record = $records->fetch())
{
echo $record['UF_NAME'] . ' - ' . $record['UF_SORT'] . '
';
}
Обновление и удаление записей
// Обновление
$entityDataClass::update($id, [
'UF_NAME' => 'Sony Updated',
'UF_SORT' => 200,
]);
// Удаление
$entityDataClass::delete($id);
Реальный пример целиком
Допустим, нам нужно создать HL-блок "Валюты" с полями: код, название, курс, активность, логотип флага. Вот как это выглядит целиком:
Bitrix\Main\Loader::includeModule('highloadblock');
Bitrix\Main\Loader::includeModule('main');
use Bitrix\Highloadblock\HighloadBlockTable;
// 1. Создаем HL-блок
$result = HighloadBlockTable::add([
'NAME' => 'Currencies',
'TABLE_NAME' => 'hl_currencies',
]);
if (!$result->isSuccess())
{
die('Ошибка создания HL-блока');
}
$hlblockId = $result->getId();
// 2. Добавляем поля
$userField = new CUserTypeEntity();
// Код валюты (строка, обязательное)
$userField->Add([
'ENTITY_ID' => 'HLBLOCK_' . $hlblockId,
'FIELD_NAME' => 'UF_CODE',
'USER_TYPE_ID' => 'string',
'MANDATORY' => 'Y',
'EDIT_FORM_LABEL' => ['ru' => 'Код валюты'],
'SETTINGS' => ['SIZE' => 10, 'MAX_LENGTH' => 3],
]);
// Название (строка)
$userField->Add([
'ENTITY_ID' => 'HLBLOCK_' . $hlblockId,
'FIELD_NAME' => 'UF_TITLE',
'USER_TYPE_ID' => 'string',
'EDIT_FORM_LABEL' => ['ru' => 'Название'],
'SETTINGS' => ['SIZE' => 50, 'MAX_LENGTH' => 255],
]);
// Курс (дробное число)
$userField->Add([
'ENTITY_ID' => 'HLBLOCK_' . $hlblockId,
'FIELD_NAME' => 'UF_RATE',
'USER_TYPE_ID' => 'double',
'EDIT_FORM_LABEL' => ['ru' => 'Курс к рублю'],
'SETTINGS' => ['PRECISION' => 4, 'DEFAULT_VALUE' => 0],
]);
// Активность (да/нет)
$userField->Add([
'ENTITY_ID' => 'HLBLOCK_' . $hlblockId,
'FIELD_NAME' => 'UF_ACTIVE',
'USER_TYPE_ID' => 'boolean',
'EDIT_FORM_LABEL' => ['ru' => 'Активна'],
'SETTINGS' => ['DEFAULT_VALUE' => 1, 'DISPLAY' => 'CHECKBOX'],
]);
// Флаг (файл)
$userField->Add([
'ENTITY_ID' => 'HLBLOCK_' . $hlblockId,
'FIELD_NAME' => 'UF_FLAG',
'USER_TYPE_ID' => 'file',
'EDIT_FORM_LABEL' => ['ru' => 'Флаг'],
]);
// Дата обновления курса (дата со временем)
$userField->Add([
'ENTITY_ID' => 'HLBLOCK_' . $hlblockId,
'FIELD_NAME' => 'UF_UPDATED_AT',
'USER_TYPE_ID' => 'datetime',
'EDIT_FORM_LABEL' => ['ru' => 'Дата обновления курса'],
]);
// 3. Добавляем данные
$entity = HighloadBlockTable::compileEntity($hlblockId);
$entityDataClass = $entity->getDataClass();
// Добавляем доллар
$entityDataClass::add([
'UF_CODE' => 'USD',
'UF_TITLE' => 'Доллар США',
'UF_RATE' => 75.5,
'UF_ACTIVE' => 1,
]);
// Добавляем евро
$entityDataClass::add([
'UF_CODE' => 'EUR',
'UF_TITLE' => 'Евро',
'UF_RATE' => 85.2,
'UF_ACTIVE' => 1,
]);
// 4. Выбираем только активные валюты
$currencies = $entityDataClass::getList([
'select' => ['UF_CODE', 'UF_TITLE', 'UF_RATE'],
'filter' => ['UF_ACTIVE' => 1],
'order' => ['UF_SORT' => 'ASC'],
]);
echo '';
echo 'Код Название Курс ';
while ($currency = $currencies->fetch())
{
echo '';
echo '' . $currency['UF_CODE'] . ' ';
echo '' . $currency['UF_TITLE'] . ' ';
echo '' . $currency['UF_RATE'] . ' ';
echo ' ';
}
echo '
';
Шпаргалка: что использовать для каких данных
Коротко по типам полей, чтобы не лазить каждый раз в документацию:
- Справочник (список значений) - string (если простой список городов/брендов) или enumeration (если нужны варианты)
- Цены, курсы, рейтинги - double
- Количество, ID, сортировка - integer
- Флаги, переключатели - boolean
- События, даты рождения - date
- Точное время создания - datetime
- Картинки, документы - file
- Связь с другим HL-блоком - hlblock
- Связь с инфоблоком - iblock_element / iblock_section
Пишите свои примеры в комментариях - лучшие добавим в заметку. Особенно интересны кейсы со связями между разными HL-блоками и нестандартным использованием.