Перенос Highload-блока с полем типа файл

Перенос Highload-блока с полем типа файл

Возникла задача перенести инфоблоки и хайлоад блоки с одного сайта на другой. Если для экспорта / импорта обычных инфоблоков Битрикс предлагает решения из коробки, то Highload-блоки пришлось осуществлять самостоятельно.

Highloadblock (далее сокращенно HL) в Битрикс основывается на таблице в БД, поэтому экспортируем её (таблицу) либо через командную строку:
mysqldump --user=NAME --password=PASSWORD
  db_name table_name >name_file_export.sql

либо с помощью веб-интерфейса, который предлагает PhpMyAdmin или аналог.

После чего создаем Highload-блоки на целевом сайте

Полученный на первом шаге файл с таблицей импортируем в БД целевого сайта, опять же, через консольную команду, либо через любимый многими PhpMyAdmin. Если среди полей Highload-блока не было имеющих тип "Файл", то на этом процесс переноса можно считать завершенным. Если поля highload блока не появились автоматически, то воспользуемся "хаком": попробуем создать поля, соответствующие по коду полям импортированной нами таблицы. Разумеется, Битрикс не даст этого сделать и выдаст ошибку о том, что поле с таким кодом уже существует, но при этом, оно появится в составе нашего хайлоад блока.

Поля типа "файл" при этом будут заполнены числовыми значениями(ID соответствующих файлов на прежнем сайте) в соответствующей таблице БД, но выводится как пустые в самом HL, т.к. данные числа теперь не соответствуют файлам в таблице b_file.

Есть такой алгоритм решения проблемы:

  • Переносим раздел, содержащий изображения из папки /upload/ старого сайта в /upload/ нового;
  • На сайте, с которого необходимо произвести перенос получаем прикрепленные в полях элементов хайлоад блоков файлы;
  • Формируем массив вида :

[ 0 => [ 'ID'=> '1', 'URL'=>'/uf/namefile.jpg', ], 1 => [ 'ID'=> '2', 'URL'=>'/uf/namefile2.jpg',  ],  ...  n => [ ... ]]
  • Полученный массив файлов регистрируем (CFile::SaveFile) на новом сайте (на который осуществляем перенос);
  • Метод CFile::SaveFile после сохранения и регистрации возвращает ID файла. На основе этих данных получаем соответствие старых ID и новых ID файлов;
  • Заменяем в значениях поля типа файл элементов созданного нами HL  старые ID файлов на новые ID.
  • Радуемся результату.

Исходный код методов реализации вышеописанного функционала:
/**
 * @param $highloadBlockId
 *
 * @throws \Bitrix\Main\ArgumentException
 * @throws \Bitrix\Main\SystemException
 *
 * @return json
 *
 * Метод возвращает массив в формате JSON,
 * сеодержащий список файлов элементов
 * хайлоад блока.
 * Каждый элемент списка содержит
 * ID(в таблице b_file Битрикса) и URL (путь) к файлу.
 *
 * @Todo : при рефакторинге этот метод вынести в класс экспорта
 */
function getFilesListJsonFromItemsHighloadBlockById($highloadBlockId) {

    $items  = [];
    $params = [
        'select'      => ['*',],
        'filter'      => ['ID' => (int)$highloadBlockId,],
        'order'       => ['ID' => 'ASC'],
        'count_total' => true,
        'limit'       => 10000,
        'offset'      => 0,
        'runtime'     => [],
    ];

    $hlBlocksCollection = HighloadBlockTable::getList($params)->fetch();

    $entity = \Bitrix\Highloadblock\HighloadBlockTable::compileEntity($hlBlocksCollection);

    $entityCode = $entity->getDataClass();

    $itemsCollection = $entityCode::getList([
        'select' => ['*'],
        'order'  => ['ID' => 'ASC'],
        'filter' => [],
    ]);

    while ($item = $itemsCollection->fetch()) {
        $items[$item['UF_FILE']]['ID']  = $item['UF_FILE'];
        $items[$item['UF_FILE']]['URL'] = CFile::GetPath($item['UF_FILE']);
    }

    return json_encode($items);

}

Полученный массив ( для удобства в формате json)  передаем в метод, регистрирующий и сохраняющий
файлы в системе Битрикс нового сайта:
/**
 * @param $filesList
 *
 * @return array
 *
 * Метод сохраняет и регистрирует в битрикс
 * входящий список файлов. Возвращает массив
 * элементов, содержащих новый и старый ID файла
 *
 */
function saveListFileByArray(array $filesList) {

    $documentRoot = substr($_SERVER['DOCUMENT_ROOT'], 0, -1);

    foreach ($filesList as $image) {

        $file            = \CFile::MakeFileArray($documentRoot . $image['URL']);
        $fileImage['MODULE_ID'] = 'iblock';
        $file['del']       = '';

        $newFileId                              = \CFile::SaveFile($file);
        $listFileNew[$newFileId]['ID']     = $newFileId;
        $listFileNew[$newFileId]['OLD_ID'] = $image['ID'];

    }

    return $listFileNew;

}

Метод получения всех элементов HL - блока:
/**
 * @param int $highloadBlockId
 *
 * @throws \Bitrix\Main\ArgumentException
 * @throws \Bitrix\Main\SystemException
 *
 * @return array
 */
function getItemsFromHighloadBlockById($highloadBlockId) {

    $highloadBlockId = (int)$highloadBlockId;

    $items  = [];
    $params = [
        'select'      => ['*',],
        'filter'      => ['ID' => $highloadBlockId,],
        'order'       => ['ID' => 'ASC'],
        'count_total' => true,
        'limit'       => 10000,
        'offset'      => 0,
        'runtime'     => [],
    ];
    $hlBlocksCollection = HighloadBlockTable::getList($params)->fetch();

    $entity = \Bitrix\Highloadblock\HighloadBlockTable::compileEntity($hlBlocksCollection);

    $entityCode = $entity->getDataClass();

    $itemsCollection = $entityCode::getList([
        'select' => ['*'],
        'order'  => ['ID' => 'ASC'],
        'filter' => [],
    ]);

    while ($item = $itemsCollection->fetch()) {
        $items[$item['ID']] = $item;
    }

    return $items;

}

Метод заменяющий в значениях поля типа файл элементов созданного нами HL  старые ID файлов на новые ID.
/**
 * @param array $items
 * @param array $listFileNew
 *
 * @return void
 */
function replaceFileIdOldToNew(array $items, array $listFileNew) {

    foreach ($items as $item) {

        if ((int)$item['UF_FILE'] > 0) {
            $item['UF_FILE'] = getNewIdFileByOldId($item['UF_FILE'], $listFileNew);
            $hlBlockId       = HIGHLOAD_BLOCK_ID;
            updateHLElement($hlBlockId, $item);
        }

    }
}

Два вспомогательных метода:

метод получения нового ID файла
/**
 * @param int   $id
 * @param array $list
 *
 * @return int
 */
function getNewIdFileByOldId($id, array $listItems) {

    foreach ($listItems as $item) {
        if ($item['OLD_ID'] == $id) {
            return $item['ID'];
        }
    }
    
}

и непосредственно по обновлению элемента HL-блока:
/**
 * @param       $hlBlockId
 * @param array $data
 *
 * @throws \Bitrix\Main\SystemException
 *
 * @return void
 */
function updateHLElement($hlBlockId, array $data) {
    $hlBlock         = HighloadBlockTable::getById($hlBlockId)->fetch();
    $entityTable     = HighloadBlockTable::compileEntity($hlBlock);
    $entityDataClass = $entityTable->getDataClass();
    $entity          = new $entityDataClass();
    $result          = $entity->update($data['ID'], $data);
}

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

Возврат к списку

Раздел Bitrix
(Codeblog)