20.09.2025
Получение элементов ИБ со всеми свойствами и создание Excel с помощью PhpSpreadsheet
В примере рассмотрим как сформировать Excel файл с помощью PhpSpreadsheet состоящий из двух страниц, на страницах записываем информацию о всех элементах ИБ с полями и всеми свойствами.
Для начала подключаем необходимые классы и получаем необходимые параметры
<?php
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style;
use Bitrix\Main\Loader;
use Bitrix\Iblock\PropertyTable;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
global $USER;
function getFormData($method)
{
// GET или POST: данные возвращаем как есть
if($method === 'GET')
return $_GET;
if($method === 'POST')
return $_POST;
// PUT, PATCH или DELETE
$data = [];
$exploded = explode('&', file_get_contents('php://input'));
foreach($exploded as $pair)
{
$item = explode('=', $pair);
if(count($item) == 2)
{
$data[urldecode($item[0])] = urldecode($item[1]);
}
}
return $data;
}
$formData = getFormData($_SERVER['REQUEST_METHOD']);
$action = $formData["action"];
if($action != "downloadExcel" && !$USER->IsAuthorized())
{
exit;
}
Loader::includeModule('iblock');
$host = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http').'://'.$_SERVER['HTTP_HOST'];
$spreadsheetOPEN = new Spreadsheet();
//шрифт файла
$spreadsheetOPEN->getDefaultStyle()->getFont()->setName('Aptos SemiBold')->setSize(12);
///////////// Платформы /////////////
$sheet1 = $spreadsheetOPEN->getActiveSheet();
$sheet1->setTitle('Платформы'); // название листа
$sheet1->getPageMargins()->setTop(0.50);
$sheet1->getPageMargins()->setRight(0.35);
$sheet1->getPageMargins()->setLeft(0.35);
$sheet1->getPageMargins()->setBottom(0.50);
$sheet1->setShowGridlines(false);
Получаем все свойства ИБ и записываем их для select в формате в зависимости от типа
$props = PropertyTable::getList([
'filter' => [
'=IBLOCK_ID' => CONFIGURATOR_SYSTEMS,
'=ACTIVE' => 'Y'
],
'order' => [
'SORT' => 'ASC',
'ID' => 'ASC'
],
'select' => [
'ID',
'CODE',
'NAME',
'PROPERTY_TYPE',
'USER_TYPE',
'MULTIPLE',
'SORT',
'LINK_IBLOCK_ID'
]
])->fetchAll();
$selectProps = [];
$arrProps = [];
foreach($props as $p)
{
if($p["PROPERTY_TYPE"] == "E")
{
$selectProps[] = $p["CODE"].".ELEMENT";
}
elseif($p["PROPERTY_TYPE"] == "S" || $p["PROPERTY_TYPE"] == "N")
{
$selectProps[] = $p["CODE"];
}
elseif($p["PROPERTY_TYPE"] == "L")
{
$selectProps[] = $p["CODE"].".ITEM";
}
elseif($p["PROPERTY_TYPE"] == "F")
{
$selectProps[] = $p["CODE"].".FILE";
}
$arrProps[$p["CODE"]] = $p;
}
$selectFields = [
'ID' => "ID",
'DETAIL_TEXT' => "Название",
'ACTIVE' => "Активность"
];
$row = 2;
$sheet1->getCell("A".$row)->setValue("Платформы");
$row += 2;
Заполняем шапку таблицы названиями полей и свойств и устанавливаем их ширину
$startCell = "A".$row;
$col = 1;
foreach($selectFields as $kF => $field)
{
$colLetter = Coordinate::stringFromColumnIndex($col); // A, B, C...
$cell = $colLetter.$row;
// Пишем значение
$sheet1->setCellValue($cell, $field);
$w = 30;
if(in_array($kF, ["DETAIL_TEXT"]))
{
$w = 50;
}
$sheet1->getColumnDimension($colLetter)->setWidth($w);
$col++;
}
foreach($arrProps as $prop)
{
$colLetter = Coordinate::stringFromColumnIndex($col); // A, B, C...
$cell = $colLetter.$row;
// Пишем значение
$sheet1->setCellValue($cell, $prop["NAME"]);
$w = 30;
if(in_array($prop["CODE"], ["CO_DESCRIPTION", "DESCRIPTION", "DOCUMENTATION", "COMPLECT"]))
{
$w = 80;
}
$sheet1->getColumnDimension($colLetter)->setWidth($w);
$col++;
}
$endColumnLetter = $colLetter;
$selectFields['NAME'] = "Название(старое)";
$select = array_merge(array_keys($selectFields), $selectProps);
Делаем запрос на ИБ с сформированным select, в котором нужные поля и все свойства.
// Важно!!! Значения свойств ИБ должны храниться "в отдельной таблице для данного информационного блока" чтобы не было ошибки лимита 61 таблица в одном JOIN (Too many tables; MariaDB can only use 61 tables in a join)
$entity = \Bitrix\Iblock\Iblock::wakeUp(CONFIGURATOR_SYSTEMS)->getEntityDataClass();
$rowsItems = $entity::getList([
'select' => $select,
'order' => [
'ID' => 'ASC',
],
])->fetchCollection();
Перебираем полученные элементы ИБ и заполняем таблицу значениями в соответствии с типом свойств
foreach($rowsItems as $element)
{
$col = 1;
$row++;
$cell = Coordinate::stringFromColumnIndex($col).$row;
$sheet1->setCellValue($cell, $element->get("ID"));
$col++;
$cell = Coordinate::stringFromColumnIndex($col).$row;
$sheet1->setCellValue($cell, $element->get("DETAIL_TEXT") ?: $element->get("NAME"));
$col++;
$cell = Coordinate::stringFromColumnIndex($col).$row;
$sheet1->setCellValue($cell, $element->get("ACTIVE") ? "Да" : "Нет");
foreach($arrProps as $key => $value)
{
$col++;
$valCell = "";
if($value["PROPERTY_TYPE"] == "E")
{
if($value["MULTIPLE"] == "Y")
{
$prOb = $element->get($value["CODE"])?->getAll() ?? [];
if($prOb)
{
foreach($prOb as $prVal)
{
$prObItem = $prVal->getElement();
$valCell .= ($prObItem->get("DETAIL_TEXT") ?: $prObItem->get("NAME"))."\n";
}
}
}
else
{
$prOb = $element->get($value["CODE"])?->getElement() ?? [];
if($prOb)
{
$valCell = $prOb->get("DETAIL_TEXT") ?: $prOb->get("NAME");
}
}
}
elseif($value["PROPERTY_TYPE"] == "N")
{
if($value["MULTIPLE"] == "Y")
{
$prOb = $element->get($value["CODE"])?->getAll() ?? [];
if($prOb)
{
foreach($prOb as $prVal)
{
$valCell .= $prVal->getValue()."\n";
}
}
}
else
{
$valCell = $element->get($value["CODE"])?->getValue();
}
}
elseif($value["PROPERTY_TYPE"] == "S")
{
if($value["MULTIPLE"] == "Y")
{
$prOb = $element->get($value["CODE"])?->getAll() ?? [];
if($prOb)
{
$kitArr = [];
foreach($prOb as $prVal)
{
if($value["USER_TYPE"] == "HTML")
{
$valCell .= unserialize($prVal->getValue())["TEXT"];
}
else
{
if($value["CODE"] == "COMPLECT")
{
$kitArr[$prVal->getValue()] = $prVal->getDescription();
}
else
{
$valCell .= $prVal->getValue()."\n";
}
}
}
if($value["CODE"] == "COMPLECT")
{
$kitOb = \Bitrix\Iblock\Elements\ElementConfiguratorComponentsTable::getList([
'filter' => [
"ID" => array_keys($kitArr),
],
"select" => [
"ID",
"NAME",
"DETAIL_TEXT"
],
]);
while($arrKit = $kitOb->fetch())
{
$valCell .= ($arrKit["DETAIL_TEXT"] ?: $arrKit["NAME"])." - ".$kitArr[$arrKit["ID"]]."шт\n";
}
}
}
}
else
{
if($value["USER_TYPE"] == "HTML")
{
$valCell = unserialize($element->get($value["CODE"])?->getValue())["TEXT"];
}
else
{
$valCell = $element->get($value["CODE"])?->getValue();
}
}
}
elseif($value["PROPERTY_TYPE"] == "L")
{
if($value["MULTIPLE"] == "Y")
{
$prOb = $element->get($value["CODE"])?->getAll() ?? [];
if($prOb)
{
foreach($prOb as $prVal)
{
$prObItem = $prVal->getItem();
$valCell .= $prObItem->getValue()."\n";
}
}
}
else
{
$prOb = $element->get($value["CODE"])?->getItem() ?? [];
if($prOb)
{
$valCell = $prOb->getValue();
}
}
}
elseif($value["PROPERTY_TYPE"] == "F")
{
if($value["MULTIPLE"] == "Y")
{
$prOb = $element->get($value["CODE"])?->getAll() ?? [];
if($prOb)
{
foreach($prOb as $prVal)
{
$fName = $prVal->getFile()->getFileName();
$valCell .= $host."/upload/".$prVal->getFile()->getSubdir()."/".$fName."\n";
}
}
}
else
{
$prVal = $element->get($value["CODE"]);
$fName = $prVal->getFile()->getFileName();
$valCell = $host."/upload/".$prVal->getFile()->getSubdir()."/".$fName."\n";
}
}
$cell = Coordinate::stringFromColumnIndex($col).$row;
// включаем перенос строк
// $sheet1->getStyle($cell)->getAlignment()->setWrapText(true);
// включаем авто-высоту для строки
$sheet1->getRowDimension($row)->setRowHeight(-1);
$sheet1->setCellValue($cell, $valCell);
}
}
$sheet1->getStyle($startCell.':'.$endColumnLetter.$row)->applyFromArray([
'borders' => [
'allBorders' => [ // рамки со всех сторон
'borderStyle' => Style\Border::BORDER_THIN,
'color' => ['argb' => 'FF000000'], // чёрный цвет
],
],
'alignment' => [
'horizontal' => Style\Alignment::HORIZONTAL_CENTER, // по горизонтали
'vertical' => Style\Alignment::VERTICAL_CENTER, // и по вертикали
// 'indent' => 20, // отступ в символах (только при горизонтальном выравнивании Left или Right)
'wrapText' => true, // перенос строк, если надо
],
]);
Для второй страницы делаем тоже самое
///////////// Компоненты /////////////
$sheet2 = new Worksheet($spreadsheetOPEN, 'Компоненты');
$sheet2->getPageMargins()->setTop(0.50);
$sheet2->getPageMargins()->setRight(0.35);
$sheet2->getPageMargins()->setLeft(0.35);
$sheet2->getPageMargins()->setBottom(0.50);
$sheet2->setShowGridlines(false);
$spreadsheetOPEN->addSheet($sheet2);
$props = PropertyTable::getList([
'filter' => [
'=IBLOCK_ID' => CONFIGURATOR_ITEMS,
'=ACTIVE' => 'Y'
],
'order' => [
'SORT' => 'ASC',
'ID' => 'ASC'
],
'select' => [
'ID',
'CODE',
'NAME',
'PROPERTY_TYPE',
'USER_TYPE',
'MULTIPLE',
'SORT',
'LINK_IBLOCK_ID'
]
])->fetchAll();
$selectProps = [];
$arrProps = [];
foreach($props as $p)
{
if($p["PROPERTY_TYPE"] == "E")
{
$selectProps[] = $p["CODE"].".ELEMENT";
}
elseif($p["PROPERTY_TYPE"] == "S" || $p["PROPERTY_TYPE"] == "N")
{
$selectProps[] = $p["CODE"];
}
elseif($p["PROPERTY_TYPE"] == "L")
{
$selectProps[] = $p["CODE"].".ITEM";
}
elseif($p["PROPERTY_TYPE"] == "F")
{
$selectProps[] = $p["CODE"].".FILE";
}
$arrProps[$p["CODE"]] = $p;
}
$selectFields = [
'ID' => "ID",
'DETAIL_TEXT' => "Название",
'ACTIVE' => "Активность"
];
$row = 2;
$sheet2->getCell("A".$row)->setValue("Компоненты");
$row += 2;
$startCell = "A".$row;
$col = 1;
foreach($selectFields as $kF => $field)
{
$colLetter = Coordinate::stringFromColumnIndex($col); // A, B, C...
$cell = $colLetter.$row;
// Пишем значение
$sheet2->setCellValue($cell, $field);
$w = 30;
if(in_array($kF, ["DETAIL_TEXT"]))
{
$w = 50;
}
$sheet2->getColumnDimension($colLetter)->setWidth($w);
$col++;
}
foreach($arrProps as $prop)
{
$colLetter = Coordinate::stringFromColumnIndex($col); // A, B, C...
$cell = $colLetter.$row;
// Пишем значение
$sheet2->setCellValue($cell, $prop["NAME"]);
$w = 30;
if(in_array($prop["CODE"], []))
{
$w = 80;
}
$sheet2->getColumnDimension($colLetter)->setWidth($w);
$col++;
}
$endColumnLetter = $colLetter;
$selectFields['NAME'] = "Название(старое)";
$select = array_merge(array_keys($selectFields), $selectProps);
$entity = \Bitrix\Iblock\Iblock::wakeUp(CONFIGURATOR_ITEMS)->getEntityDataClass();
$rowsItems = $entity::getList([
'select' => $select,
'order' => [
'ID' => 'ASC',
],
])->fetchCollection();
foreach($rowsItems as $element)
{
$col = 1;
$row++;
$cell = Coordinate::stringFromColumnIndex($col).$row;
$sheet2->setCellValue($cell, $element->get("ID"));
$col++;
$cell = Coordinate::stringFromColumnIndex($col).$row;
$sheet2->setCellValue($cell, $element->get("DETAIL_TEXT") ?: $element->get("NAME"));
$col++;
$cell = Coordinate::stringFromColumnIndex($col).$row;
$sheet2->setCellValue($cell, $element->get("ACTIVE") ? "Да" : "Нет");
foreach($arrProps as $key => $value)
{
$col++;
$valCell = "";
if($value["PROPERTY_TYPE"] == "E")
{
if($value["MULTIPLE"] == "Y")
{
$prOb = $element->get($value["CODE"])?->getAll() ?? [];
if($prOb)
{
foreach($prOb as $prVal)
{
$prObItem = $prVal->getElement();
$valCell .= ($prObItem->get("DETAIL_TEXT") ?: $prObItem->get("NAME"))."\n";
}
}
}
else
{
$prOb = $element->get($value["CODE"])?->getElement() ?? [];
if($prOb)
{
$valCell = $prOb->get("DETAIL_TEXT") ?: $prOb->get("NAME");
}
}
}
elseif($value["PROPERTY_TYPE"] == "N")
{
if($value["MULTIPLE"] == "Y")
{
$prOb = $element->get($value["CODE"])?->getAll() ?? [];
if($prOb)
{
foreach($prOb as $prVal)
{
$valCell .= $prVal->getValue()."\n";
}
}
}
else
{
$valCell = $element->get($value["CODE"])?->getValue();
}
}
elseif($value["PROPERTY_TYPE"] == "S")
{
if($value["MULTIPLE"] == "Y")
{
$prOb = $element->get($value["CODE"])?->getAll() ?? [];
if($prOb)
{
$kitArr = [];
foreach($prOb as $prVal)
{
if($value["USER_TYPE"] == "HTML")
{
$valCell .= unserialize($prVal->getValue())["TEXT"];
}
else
{
if($value["CODE"] == "COMPLECT")
{
$kitArr[$prVal->getValue()] = $prVal->getDescription();
}
else
{
$valCell .= $prVal->getValue()."\n";
}
}
}
if($value["CODE"] == "COMPLECT")
{
$kitOb = \Bitrix\Iblock\Elements\ElementConfiguratorComponentsTable::getList([
'filter' => [
"ID" => array_keys($kitArr),
],
"select" => [
"ID",
"NAME",
"DETAIL_TEXT"
],
]);
while($arrKit = $kitOb->fetch())
{
$valCell .= ($arrKit["DETAIL_TEXT"] ?: $arrKit["NAME"])." - ".$kitArr[$arrKit["ID"]]."шт\n";
}
}
}
}
else
{
if($value["USER_TYPE"] == "HTML")
{
$valCell = unserialize($element->get($value["CODE"])?->getValue())["TEXT"];
}
else
{
$valCell = $element->get($value["CODE"])?->getValue();
}
}
}
elseif($value["PROPERTY_TYPE"] == "L")
{
if($value["MULTIPLE"] == "Y")
{
$prOb = $element->get($value["CODE"])?->getAll() ?? [];
if($prOb)
{
foreach($prOb as $prVal)
{
$prObItem = $prVal->getItem();
$valCell .= $prObItem->getValue()."\n";
}
}
}
else
{
$prOb = $element->get($value["CODE"])?->getItem() ?? [];
if($prOb)
{
$valCell = $prOb->getValue();
}
}
}
elseif($value["PROPERTY_TYPE"] == "F")
{
if($value["MULTIPLE"] == "Y")
{
$prOb = $element->get($value["CODE"])?->getAll() ?? [];
if($prOb)
{
foreach($prOb as $prVal)
{
$fName = $prVal->getFile()->getFileName();
$valCell .= $host."/upload/".$prVal->getFile()->getSubdir()."/".$fName."\n";
}
}
}
else
{
$prVal = $element->get($value["CODE"]);
$fName = $prVal->getFile()->getFileName();
$valCell = $host."/upload/".$prVal->getFile()->getSubdir()."/".$fName."\n";
}
}
$cell = Coordinate::stringFromColumnIndex($col).$row;
// включаем авто-высоту для строки
$sheet2->getRowDimension($row)->setRowHeight(-1);
$sheet2->setCellValue($cell, $valCell);
}
}
$sheet2->getStyle($startCell.':'.$endColumnLetter.$row)->applyFromArray([
'borders' => [
'allBorders' => [ // рамки со всех сторон
'borderStyle' => Style\Border::BORDER_THIN,
'color' => ['argb' => 'FF000000'], // чёрный цвет
],
],
'alignment' => [
'horizontal' => Style\Alignment::HORIZONTAL_CENTER, // по горизонтали
'vertical' => Style\Alignment::VERTICAL_CENTER, // и по вертикали
// 'indent' => 20, // отступ в символах (только при горизонтальном выравнивании Left или Right)
'wrapText' => true, // перенос строк, если надо
],
]);
Устанавливаем активность первой странице и сохраняем файл
$spreadsheetOPEN->setActiveSheetIndex(0);
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheetOPEN, "Xlsx");
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename="'.urlencode("all-catalogs.xlsx").'"');
ob_end_clean();
$writer->save('php://output');
$spreadsheetOPEN->disconnectWorksheets();
unset($spreadsheetOPEN);
?>