Как создать свою ORM-таблицу в 1С-Битрикс через DataManager и getMap?

Как создать свою ORM-таблицу в 1С-Битрикс через DataManager и getMap?

Модуль стоит, а логи заказов все ещё пишутся сырым SQL или тащатся в инфоблок. MyModule\LogTable::getList() падает с "Class ...Table not found", в phpMyAdmin таблицы нет - хотя install.php прошёл чисто. Обычно виноваты: класс без суффикса Table, createDbTable без isTableExists или забытый Loader::includeModule. Ниже - полный цикл своей ORM-таблицы в 1С-Битрикс: Управление сайтом через DataManager, getMap и createDbTable.

Своя *Table в lib/ модуля - это когда данные служебные: логи, очередь, счётчики. Класс наследует DataManager, имя заканчивается на Table, getMap описывает поля, createDbTable() вызывается в InstallDB с проверкой isTableExists. Перед CRUD - Loader::includeModule. Результат: таблица в БД, add/getList работают без сырого SQL, uninstall удаляет таблицу через dropTable.

Речь про коробочную CMS, не про облачный Bitrix24. ORM (Object-Relational Mapping) - слой D7, который связывает PHP-класс с таблицей MySQL: поля в getMap(), чтение и запись через getList, add, update, delete. Каркас модуля ещё не собран - начните с гайда по созданию модуля, здесь шаг после include.php.

Выберите, когда нужна своя ORM-таблица, а когда хватит инфоблока или Highload

Таблица сравнения: когда ORM-таблица, а когда инфоблок или Highload в Битрикс

DataManager в lib/ - не замена всему подряд. Это узкий инструмент для служебных данных модуля, которые не должны жить в админке как контент.

Задача Инфоблок D7 (B60) Highload (B26) Своя *Table в модуле
Новости, каталог, SEO-страницы Да - ElementTable, админка Нет Нет - лишний вес
Справочник 50 000 SKU Медленно Да - отдельная таблица HL Редко - HL проще
Лог API-запросов модуля Избыточно Избыточно Да - LogTable в lib/
Очередь фоновых задач Нет Иногда Да - полный контроль схемы

Выборка инфоблока - в сравнении GetList и D7 ORM, справочники - в гайде по Highload. Своя таблица - когда данные только вашего модуля, без редактора в админке.

Делайте: храните служебные записи в *Table. Не делайте: не создавайте инфоблок ради десятка строк лога - админка и кеш усложнят поддержку.

Создайте класс LogTable в lib/ с getTableName и getMap

Схема шагов: создание LogTable с getTableName и getMap в lib/ модуля

Наследник DataManager живёт в lib/. Имя класса заканчивается на Table - правило ядра. getTableName() - имя таблицы в MySQL, getMap() - поля (IntegerField, StringField и др.).

  1. Создайте файл /local/modules/mycompany.custommodule/lib/LogTable.php.
  2. Задайте namespace Mycompany\Custommodule и extends \Bitrix\Main\Entity\DataManager.
  3. Реализуйте getTableName() - например, return 'mycompany_custommodule_log';
  4. Опишите getMap(): ID (IntegerField, primary, autoincrement), TIMESTAMP_X (DatetimeField), LEVEL (StringField), MESSAGE (TextField).
  5. Зарегистрируйте класс в include.php через Loader::registerAutoLoadClasses с полным именем Mycompany\Custommodule\LogTable.
  6. Проверьте, что имя класса в автозагрузке совпадает с файлом - не Log вместо LogTable.
<?php
namespace Mycompany\Custommodule;

use Bitrix\Main\Entity\DataManager;
use Bitrix\Main\Entity\IntegerField;
use Bitrix\Main\Entity\StringField;
use Bitrix\Main\Entity\TextField;
use Bitrix\Main\Entity\DatetimeField;

class LogTable extends DataManager
{
    public static function getTableName()
    {
        return 'mycompany_custommodule_log';
    }

    public static function getMap()
    {
        return [
            new IntegerField('ID', [
                'primary' => true,
                'autocomplete' => true,
            ]),
            new DatetimeField('TIMESTAMP_X', [
                'default_value' => function () {
                    return new \Bitrix\Main\Type\DateTime();
                },
            ]),
            new StringField('LEVEL', ['required' => true]),
            new TextField('MESSAGE'),
        ];
    }
}

Схема: lib/LogTable.php → getTableName + getMap → registerAutoLoadClasses в include.php → класс доступен после includeModule.

Делайте: держите поля в getMap, а не в ручном CREATE TABLE. Не делайте: не называйте класс Log без суффикса Table - ядро не распознает сущность.

Настройте createDbTable в InstallDB с проверкой isTableExists

Чеклист: createDbTable в InstallDB с проверкой isTableExists перед prod

createDbTable() создаёт таблицу по getMap() при установке. Не меняет схему существующей таблицы и не добавляет индексы. Без isTableExists при повторной установке - "table already exists".

public function InstallDB()
{
    if (!\Bitrix\Main\Loader::includeModule('mycompany.custommodule')) {
        return false;
    }
    $connection = \Bitrix\Main\Application::getConnection();
    $tableName = \Mycompany\Custommodule\LogTable::getTableName();
    if (!$connection->isTableExists($tableName)) {
        \Mycompany\Custommodule\LogTable::getEntity()->createDbTable();
    }
    return true;
}

public function UnInstallDB()
{
    $connection = \Bitrix\Main\Application::getConnection();
    $tableName = \Mycompany\Custommodule\LogTable::getTableName();
    if ($connection->isTableExists($tableName)) {
        $connection->dropTable($tableName);
    }
    return true;
}

Движок берётся из default-storage-engine MySQL - часто MyISAM. Нужен InnoDB - ALTER после создания или настройка сервера по рекомендациям 1С-Битрикс. Изменили getMap - колонки через Sprint Migration или ALTER, не createDbTable.

Делайте: вызывайте createDbTable только при !isTableExists. Не делайте: не ждите, что правка getMap автоматически обновит БД.

Выполните CRUD: add, getList, update и delete после includeModule

На практике любой вызов LogTable::getList() из компонента или агента требует предварительного Loader::includeModule('mycompany.custommodule'). Без этого - "Class Mycompany\Custommodule\LogTable not found", даже если таблица в БД уже есть.

\Bitrix\Main\Loader::includeModule('mycompany.custommodule');

$result = \Mycompany\Custommodule\LogTable::add([
    'LEVEL' => 'error',
    'MESSAGE' => 'Payment callback timeout',
]);
if (!$result->isSuccess()) {
    // $result->getErrorMessages()
}

$rows = \Mycompany\Custommodule\LogTable::getList([
    'filter' => ['=LEVEL' => 'error'],
    'order' => ['TIMESTAMP_X' => 'DESC'],
    'limit' => 50,
    'select' => ['ID', 'TIMESTAMP_X', 'LEVEL', 'MESSAGE'],
])->fetchAll();

Workflow: includeModule → add с isSuccess() → getList с filter/order/limit → update/delete по ID. Отладка SQL - getLastQuery(), см. справочник DataManager.

Делайте: проверяйте isSuccess() после add и update. Не делайте: не вызывайте *Table до includeModule - типичная ловушка после успешной установки.

Проверьте чек-лист и типичные ошибки перед выкладкой на prod

После установки модуля на staging пройдите короткий smoke-test - он сэкономит часы на проде.

  1. Установите модуль в админке - таблица появилась в phpMyAdmin с полями из getMap.
  2. Добавьте тестовую запись через LogTable::add() - ID вернулся, isSuccess() true.
  3. Выберите строки через getList с фильтром - данные совпадают с add.
  4. Удалите модуль - таблица исчезла, в b_module записи нет.
  5. Переустановите модуль - нет ошибки "table exists", CRUD снова работает.
  6. Откройте getLastQuery() после getList - SQL совпадает с ожидаемым filter/order.

Типичная ошибка на практике — Log вместо LogTable в автозагрузке; вторая ловушка: авто-миграция getMap не сработает; третья — MyISAM вместо InnoDB. Генератор perfmon (?orm=y) ускоряет старт - урок по автогенерации ORM.

Делайте: фиксируйте схему в git и прогоняйте uninstall на копии БД. Не делайте: не правьте таблицу только в phpMyAdmin на проде без миграции.

Что дальше

Дальше: ReferenceField, сервис в lib/Service/, агент очистки логов, миграции схемы между окружениями. Помощь с архитектурой модуля - обсудим задачу, кейсы - в портфолио.

Автор: Максим Мольков, Senior-разработчик 1С-Битрикс.
Источники: концепция ORM Bitrix Framework, справочник DataManager D7, Base::createDbTable.

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

Чем своя ORM-таблица отличается от инфоблока и Highload?

Инфоблок - для контента с админкой и SEO. Highload - для больших справочников через UI. Своя *Table в lib/ - для служебных данных модуля: логи, очереди, счётчики. Выбор: контент - инфоблок, миллионы строк справочника - HL, внутренние данные модуля - DataManager.

Где положить класс Table в структуре модуля?

В /local/modules/vendor.module/lib/, например lib/LogTable.php. Namespace совпадает с вендором модуля. Зарегистрируйте путь в include.php через Loader::registerAutoLoadClasses - полное имя класса с суффиксом Table.

Как создать таблицу при установке модуля без ручного SQL?

В InstallDB вызовите Loader::includeModule, проверьте isTableExists по getTableName(), затем LogTable::getEntity()->createDbTable(). В UnInstallDB - connection->dropTable с той же проверкой.

Зачем getMap, если можно писать SQL напрямую?

getMap даёт типизацию полей, единый CRUD через add/getList и защиту от расхождения PHP и БД. Сырой SQL быстрее на бумаге, но без карты полей легко ошибиться в именах колонок и типах при рефакторинге.

Почему createDbTable создаёт MyISAM, а не InnoDB?

ORM берёт default-storage-engine MySQL сервера. Проверьте SHOW VARIABLES LIKE 'default_storage_engine'. После createDbTable выполните ALTER TABLE ... ENGINE=InnoDB или настройте сервер до установки модуля.

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

createDbTable не ALTER-ит существующую таблицу. Добавьте колонку через Connection::queryExecute с ALTER или оформите миграцию в Sprint Migration - так схема доедет на staging и prod без ручных правок.

Class LogTable not found - что проверить первым?

Три пункта: Loader::includeModule('vendor.module') перед вызовом; в registerAutoLoadClasses полное имя с Table; файл лежит в lib/ и namespace совпадает. Таблица в БД есть, а класс не найден - почти всегда автозагрузка, не install.

Читайте также

Интеграции с 1С и API
1074 6 мин.

Как настроить регистрацию и личный кабинет покупателя на 1С-Битрикс?

Пошаговая настройка регистрации на сайте битрикс: Главный модуль, main.register, system.auth.form и sale.personal.section с историей заказов и 152-ФЗ.
Интеграции с 1С и API
941 6 мин.

Как настроить скидки и промокоды на 1С-Битрикс: правила корзины и купоны

Пошаговый гайд по скидкам в CMS-магазине: скидка на товар, правило корзины от суммы, купоны с лимитом, приоритеты без конфликтов и тестовый заказ. Не Bitrix24.
Интеграции с 1С и API
759 15 мин.

Что такое компонент в Битриксе и как он работает

Каждый разработчик, впервые столкнувшийся с Битриксом, проходит через своеобразный обряд посвящения. Вначале кажется, что это просто CMS, где можно поправить HTML в визуальном редакторе или дописать пару строк CSS. Но однажды наступает момент, когда нужно изменить логику вывода новостей, отфильтровать товары по хитрому свойству или добавить на страницу нечто совершенно новое. И тут он впервые слышит это слово — «компонент». Для многих этот момент становится стеной. Система, казавшаяся понятной, вдруг превращается в черный ящик, полный непонятных файлов и странных переменных. Но стоит лишь раз заглянуть под капот, как эта стена рассыпается, превращаясь в набор удивительно логичных и мощных строительных блоков. Понимание компонентов — это тот самый щелчок, после которого разработка на Битрикс из мучения превращается в творчество.

Эта статья — ваш проводник в мир компонентов «1С-Битрикс». Мы не будем сыпать сухими терминами из документации. Вместо этого мы совершим путешествие: от философии, заложенной в эту архитектуру, до мельчайших деталей её работы. Мы разберем компонент на атомы — его файлы, логику, шаблон, параметры — и соберем обратно, чтобы вы не просто знали, что это, но и глубоко понимали, почему это работает именно так. Это знание — ключ к эффективной и профессиональной разработке на Битрикс.

Интеграции с 1С и API
718 2 мин.

Установка Composer в 1С-Битрикс

Установка Composer в проекте на 1С-Битрикс требует учета особенностей платформы, чтобы обеспечить корректную работу и интеграцию с системой.