Разработка модуля экспорта данных 1С-Битрикс
Экспорт из Битрикс — задача на первый взгляд простая: SELECT из нужных таблиц и сформировать файл. На практике всё сложнее: данные распределены по десяткам таблиц, нужны JOIN с учётом прав доступа, файл должен генерироваться асинхронно без блокировки интерфейса, а форматы могут быть разные в зависимости от получателя.
Типичные сценарии
- Выгрузка каталога для маркетплейсов (Ozon, Wildberries) в специфическом XML или JSON
- Экспорт заказов в 1С:Бухгалтерию через XML или CSV
- Регулярная выгрузка лидов CRM в Google Sheets или BI-систему
- Передача пользовательских данных в ESP (UniSender, SendGrid)
- Резервный экспорт данных для переноса на другую платформу
Для каждого сценария — свой маппинг полей и свой формат. Единый модуль позволяет настроить все выгрузки в одном месте.
Структура модуля
Модуль vendor.exporter с тремя слоями:
- Collector — собирает данные из источника (ORM-запросы к таблицам Битрикс)
- Transformer — преобразует сырые данные в нужную структуру
- Formatter — формирует конечный файл нужного формата
Таблицы модуля:
-
b_vendor_exporter_profile— профили экспорта: name, source_config (JSON), format, schedule, last_run, last_file -
b_vendor_exporter_job— задания на экспорт: profile_id, status, started_at, finished_at, file_path, rows_count, error -
b_vendor_exporter_field— маппинг полей для профиля: profile_id, source_field, target_field, transform_rule
Коллекторы данных
class CatalogProductCollector implements CollectorInterface
{
public function collect(array $filter, array $select): \Generator
{
$query = \Bitrix\Iblock\Elements\ElementTable::query()
->setFilter($filter)
->setSelect($select);
foreach ($query->fetchAll() as $row) {
// JOIN с ценами
$prices = \Bitrix\Catalog\PriceTable::getList([
'filter' => ['=PRODUCT_ID' => $row['ID']],
'select' => ['PRICE', 'CURRENCY', 'CATALOG_GROUP_NAME'],
])->fetchAll();
$row['PRICES'] = $prices;
yield $row;
}
}
}
Использование Generator вместо массива критично при выгрузке 100 000+ записей — данные не накапливаются в памяти.
Форматтеры
CSV-форматтер с поддержкой разделителей и кодировок:
class CsvFormatter implements FormatterInterface
{
public function format(\Generator $data, array $columns, string $outputPath): void
{
$handle = fopen($outputPath, 'w');
fputs($handle, "\xEF\xBB\xBF"); // UTF-8 BOM для Excel
fputcsv($handle, array_column($columns, 'label'), $this->delimiter);
foreach ($data as $row) {
fputcsv($handle, $this->extractValues($row, $columns), $this->delimiter);
}
fclose($handle);
}
}
XML-форматтер для произвольных схем — конфигурируется шаблоном XSD или XSLT. XLSX-форматтер через PhpSpreadsheet с поддержкой форматирования ячеек. JSON-форматтер с выбором структуры: плоский массив или вложенные объекты.
Асинхронная генерация
Файл не генерируется синхронно при HTTP-запросе. Администратор нажимает «Запустить экспорт», создаётся задание в b_vendor_exporter_job со статусом queued. Агент ExportAgent::run() запускается раз в минуту:
public static function run(): string
{
$job = ExportJobTable::getList([
'filter' => ['=STATUS' => 'queued'],
'order' => ['CREATED_AT' => 'ASC'],
'limit' => 1,
])->fetch();
if (!$job) return __CLASS__ . '::run();';
ExportJobTable::update($job['ID'], ['STATUS' => 'running', 'STARTED_AT' => new DateTime()]);
try {
$profile = ExportProfileTable::getById($job['PROFILE_ID'])->fetch();
$service = new ExportService($profile);
$filePath = $service->execute();
ExportJobTable::update($job['ID'], [
'STATUS' => 'done',
'FILE_PATH' => $filePath,
'FINISHED_AT' => new DateTime(),
]);
} catch (\Throwable $e) {
ExportJobTable::update($job['ID'], ['STATUS' => 'failed', 'ERROR' => $e->getMessage()]);
}
return __CLASS__ . '::run();';
}
Расписание и автодоставка
Профили поддерживают cron-расписание. После генерации файл можно:
- скачать вручную из административного интерфейса
- отправить на email (через
\Bitrix\Main\Mail\Event::send()) - передать по FTP/SFTP (
\Bitrix\Main\IO+ PHP ftp-функции) - опубликовать по URL (файл кладётся в
/upload/vendor_exporter/, ссылка фиксируется в профиле) - отправить POST-запросом к внешнему API (вебхук с файлом в multipart/form-data)
Фильтрация и частичный экспорт
В профиле настраивается базовый фильтр. При ручном запуске администратор может дополнить фильтр через форму: диапазон дат, статусы, конкретные ID. Фильтр передаётся в коллектор через filter_override:
$collector->collect(
array_merge($profile->getBaseFilter(), $job->getFilterOverride()),
$profile->getSelect()
);
Безопасность и права
Экспорт персональных данных (пользователи, заказы) доступен только группам с явно выданными правами в настройках модуля. Логируется: кто запустил экспорт, когда, сколько записей, путь к файлу. Лог хранится в b_vendor_exporter_audit.
Сроки разработки
| Этап | Срок |
|---|---|
| Архитектура, интерфейсы, таблицы | 1 день |
| Коллекторы для нужных сущностей Битрикс | 2 дня |
| Форматтеры (CSV, XML, XLSX, JSON) | 2 дня |
| Асинхронная генерация, агент | 1 день |
| Расписание, автодоставка (email, FTP) | 2 дня |
| Административный интерфейс | 2 дня |
| Фильтрация, права, аудит-лог | 1 день |
| Тестирование на больших объёмах | 1 день |
Итого: 12 рабочих дней для стандартного набора форматов и источников. Специфические форматы маркетплейсов (особенно с обязательными полями сертификации) — +1-2 дня каждый.







