33 private $xmlImport =
null;
35 private $fileHandler =
null;
36 private $fileParameters = [
38 'ABSOLUTE_PATH' =>
'',
39 'FILES_DIRECTORY' =>
'',
43 private $parameters = [];
48 self::STEP_INIT_IMPORT_TABLES,
50 self::STEP_INDEX_IMPORT_TABLES,
51 self::STEP_IMPORT_METADATA,
52 self::STEP_IMPORT_SECTIONS,
53 self::STEP_MISSING_SECTIONS,
54 self::STEP_RESORT_SECTIONS,
55 self::STEP_IMPORT_ELEMENTS,
56 self::STEP_IMPORT_PRODUCT_BUNDLES,
57 self::STEP_MISSING_ELEMENTS,
61 private $stepId =
null;
62 private $stepParameters =
null;
63 private $final =
false;
64 private $iblockId =
null;
66 private $message =
'';
68 private $progressCounter = [];
72 private $startTime =
null;
81 $this->closeXmlFile();
82 $this->destroyXmlImporter();
87 $this->startTime = time();
90 $this->setParameters($parameters);
93 $this->setConfig($config);
96 $this->initSessionStorage();
99 $this->internalInit();
102 private function initSessionStorage()
104 if (!isset($_SESSION[self::SESSION_STORAGE_ID]) || !is_array($_SESSION[self::SESSION_STORAGE_ID]))
105 $_SESSION[self::SESSION_STORAGE_ID] = [];
106 if (!isset($_SESSION[self::SESSION_STORAGE_ID][
'SECTIONS_MAP']))
107 $_SESSION[self::SESSION_STORAGE_ID][
'SECTIONS_MAP'] =
null;
108 if (!isset($_SESSION[self::SESSION_STORAGE_ID][
'PRICES_MAP']))
109 $_SESSION[self::SESSION_STORAGE_ID][
'PRICES_MAP'] =
null;
110 $this->initStepParameters();
113 private function initStepParameters()
116 !isset($_SESSION[self::SESSION_STORAGE_ID][
'STEP_ID'])
118 !isset($_SESSION[self::SESSION_STORAGE_ID][
'STEP_PARAMETERS'])
119 || !is_array($_SESSION[self::SESSION_STORAGE_ID][
'STEP_PARAMETERS'])
123 $_SESSION[self::SESSION_STORAGE_ID][
'STEP_ID'] = reset($this->stepList);
124 $_SESSION[self::SESSION_STORAGE_ID][
'STEP_PARAMETERS'] = [];
127 $_SESSION[self::SESSION_STORAGE_ID][
'STEP_ID'],
131 $this->addError(Loc::getMessage(
'IBLOCK_XML_IMPORT_ERR_BAD_STEP_ID'));
134 $this->stepId = &$_SESSION[self::SESSION_STORAGE_ID][
'STEP_ID'];
135 $this->stepParameters = &$_SESSION[self::SESSION_STORAGE_ID][
'STEP_PARAMETERS'];
141 private function internalInit(): void
143 $this->closeXmlFile();
144 $this->destroyXmlImporter();
145 $this->createXmlImporter();
159 public function run(): void
161 $this->setXmlImporterParameters();
162 $this->setMessage(
'');
163 $this->clearProgressCounter();
164 switch ($this->getCurrentStep())
166 case self::STEP_INIT_IMPORT_TABLES:
167 $this->initTemporaryTablesAction();
169 case self::STEP_READ_XML:
170 $this->readXmlAction();
172 case self::STEP_INDEX_IMPORT_TABLES:
173 $this->indexTemporaryTablesAction();
175 case self::STEP_IMPORT_METADATA:
176 $this->importMetadataAction();
178 case self::STEP_IMPORT_SECTIONS:
179 $this->importSectionsAction();
181 case self::STEP_MISSING_SECTIONS:
182 $this->processMissingSectionsAction();
184 case self::STEP_RESORT_SECTIONS:
185 $this->resortSectionsAction();
187 case self::STEP_IMPORT_ELEMENTS:
188 $this->importElementsAction();
190 case self::STEP_MISSING_ELEMENTS:
191 $this->processMissingElementsAction();
193 case self::STEP_IMPORT_PRODUCT_BUNDLES:
194 $this->importProductBundlesAction();
196 case self::STEP_FINAL:
197 $this->finalAction();
210 $result[
'TYPE'] = self::RESULT_TYPE_SUCCESS;
211 $result[
'MESSAGE'] = $this->getMessage();
216 $progress = $this->getProgressCounter();
217 if (!empty($progress))
218 $result[
'PROGRESS'] = $progress;
224 $result[
'TYPE'] = self::RESULT_TYPE_ERROR;
245 return empty($this->errors);
268 private function addError(
string $error): void
282 private function setParameters(
array $parameters): void
284 $this->prepareParameters($parameters);
287 $this->parameters = $parameters;
294 private function prepareParameters(
array &$parameters): void
296 $parameters = array_filter($parameters, [__CLASS__,
'clearNull']);
297 $parameters = array_merge($this->getDefaultParameters(), $parameters);
299 $parameters[
'FILE'] = trim($parameters[
'FILE']);
300 if ($parameters[
'FILE'] ===
'')
302 $this->addError(Loc::getMessage(
'IBLOCK_XML_IMPORT_ERR_PARAMETER_FILE_IS_EMPTY'));
306 $rawFilename = $parameters[
'FILE'];
308 file_exists($rawFilename)
309 && is_file($rawFilename)
311 mb_substr($rawFilename, -4) ===
".xml"
315 $this->fileParameters[
'PATH'] = mb_substr($rawFilename, mb_strlen(
$_SERVER[
'DOCUMENT_ROOT']));
316 $this->fileParameters[
'ABSOLUTE_PATH'] = $rawFilename;
320 $rawFilename = trim(str_replace(
"\\",
'/', $rawFilename),
'/');
324 $this->fileParameters[
'PATH'] =
$filename;
325 $this->fileParameters[
'ABSOLUTE_PATH'] =
$_SERVER[
'DOCUMENT_ROOT'].$filename;
329 $this->fileParameters[
'FILES_DIRECTORY'] = mb_substr(
330 $this->fileParameters[
'ABSOLUTE_PATH'],
332 mb_strrpos($this->fileParameters[
'ABSOLUTE_PATH'],
'/') + 1
336 $parameters[
'IBLOCK_TYPE'] = trim($parameters[
'IBLOCK_TYPE']);
338 if (!is_array($parameters[
'SITE_LIST']))
339 $parameters[
'SITE_LIST'] = [$parameters[
'SITE_LIST']];
347 private function getParameter(
string $name)
354 return ($this->parameters[
$name] ??
null);
360 private function getDefaultParameters():
array
366 'MISSING_SECTION_ACTION' => self::ACTION_NOTHING,
367 'MISSING_ELEMENT_ACTION' => self::ACTION_NOTHING,
376 private function setConfig(
array $config): void
378 $this->prepareConfig($config);
383 $this->config = $config;
390 private function prepareConfig(
array &$config): void
392 $config = array_filter($config, [__CLASS__,
'clearNull']);
393 $config = array_merge($this->getDefaultConfig(), $config);
399 private function getConfig():
array
408 private function getConfigFieldValue(
string $field)
415 return ($this->config[$field] ??
null);
421 private function getDefaultConfig():
array
425 'PREVIEW_PICTURE_SETTINGS' =>
false,
426 'DETAIL_PICTURE_SETTINGS' =>
false,
427 'USE_OFFERS' =>
false,
428 'FORCE_OFFERS' =>
false,
429 'USE_IBLOCK_TYPE_ID' =>
false,
430 'TRANSLITERATION' => [
435 'TRANS_SPACE' =>
'-',
436 'TRANS_OTHER' =>
'-',
440 'SKIP_ROOT_SECTION' =>
false,
441 'DISABLE_CHANGE_PRICE_NAME' =>
false,
442 'TABLE_NAME' =>
'b_xml_tree',
443 'READ_BLOCKSIZE' => 1024,
451 private function getCurrentStep()
453 return $this->stepId;
460 private function setCurrentStep($step): void
462 $this->stepId = $step;
468 private function nextStep(): void
470 $index = array_search($this->getCurrentStep(), $this->stepList);
471 if (isset($this->stepList[$index+1]))
473 $this->setCurrentStep($this->stepList[$index + 1]);
485 private function setMessage(
string $message): void
487 $this->message = $message;
493 private function getMessage(): string
501 private function clearProgressCounter(): void
503 $this->progressCounter = [];
511 private function setProgressCounter(
int $total,
int $current): void
513 $this->progressCounter = [
515 'CURRENT' => $current
522 private function getProgressCounter(): ?
array
524 return (!empty($this->progressCounter) ? $this->progressCounter :
null);
530 private function setXmlImporterParameters(): void
532 $this->xmlImport->InitEx($this->stepParameters, $this->getXmlImporterConfig());
538 private function getXmlImporterConfig():
array
540 $config = $this->getConfig();
543 'files_dir' => $this->fileParameters[
'FILES_DIRECTORY'],
544 'use_crc' => $config[
'USE_CRC'],
545 'preview' => $config[
'PREVIEW_PICTURE_SETTINGS'],
546 'detail' => $config[
'DETAIL_PICTURE_SETTINGS'],
547 'use_offers' => $config[
'USE_OFFERS'],
548 'force_offers' => $config[
'FORCE_OFFERS'],
549 'use_iblock_type_id' => $config[
'USE_IBLOCK_TYPE_ID'],
550 'skip_root_section' => $config[
'SKIP_ROOT_SECTION'],
551 'disable_change_price_name' => $config[
'DISABLE_CHANGE_PRICE_NAME'],
552 'table_name' => $config[
'TABLE_NAME'],
553 'iblock_cache_mode' => $config[
'IBLOCK_CACHE_MODE'],
555 + $this->getXmlImporterTransliterationSettings()
565 private function initTemporaryTablesAction(): void
567 $result = $this->xmlImport->initializeTemporaryTables();
571 $this->addError(Loc::getMessage(
'IBLOCK_XML_IMPORT_ERR_CANNOT_PREPARE_TEMPORARY_TABLES'));
579 private function readXmlAction(): void
581 $this->openXmlFile();
586 if ($this->xmlImport->ReadXMLToDatabase(
588 $this->stepParameters,
589 $this->getParameter(
'INTERVAL'),
590 $this->getConfigFieldValue(
'READ_BLOCKSIZE')
593 $this->setMessage(Loc::getMessage(
'IBLOCK_XML_IMPORT_MESS_XML_FILE_READ_COMPLETE'));
598 $this->setMessage(Loc::getMessage(
599 'IBLOCK_XML_IMPORT_MESS_XML_FILE_READ_PROGRESS',
600 [
'#PERCENT#' => $this->getXmlFileProgressPercent()]
603 $this->closeXmlFile();
609 private function indexTemporaryTablesAction(): void
611 if (!$this->xmlImport->IndexTemporaryTables())
613 $this->addError(Loc::getMessage(
'IBLOCK_XML_IMPORT_ERR_CANNOT_CREATE_TEMPORARY_TABLES_INDEX'));
616 $this->setMessage(Loc::getMessage(
'IBLOCK_XML_IMPORT_MESS_CREATE_TEMPORARY_TABLES_INDEX_COMPLETE'));
623 private function importMetadataAction(): void
625 $result = $this->xmlImport->ImportMetaData(
626 $this->xmlImport->GetRoot(),
627 $this->getParameter(
'IBLOCK_TYPE'),
628 $this->getParameter(
'SITE_LIST')
633 $this->setMessage(Loc::getMessage(
'IBLOCK_XML_IMPORT_MESS_METADATA_IMPORT_COMPLETE'));
641 $this->addError(Loc::getMessage(
642 'IBLOCK_XML_IMPORT_ERR_METADATA_IMPORT_FAILURE',
652 private function importSectionsAction(): void
654 $this->xmlImport->freezeIblockCache();
655 $result = $this->xmlImport->ImportSections();
656 $this->xmlImport->unFreezeIblockCache();
657 $this->xmlImport->clearIblockCacheOnHit();
661 $this->setMessage(Loc::getMessage(
'IBLOCK_XML_IMPORT_MESS_IBLOCK_SECTIONS_IMPORT_COMPLETE'));
665 $this->addError(Loc::getMessage(
666 'IBLOCK_XML_IMPORT_ERR_IBLOCK_SECTIONS_IMPORT_FAILURE',
675 private function processMissingSectionsAction(): void
677 $this->xmlImport->freezeIblockCache();
678 $this->xmlImport->DeactivateSections($this->getParameter(
'MISSING_SECTION_ACTION'));
679 $this->xmlImport->SectionsResort();
680 $this->xmlImport->unFreezeIblockCache();
681 $this->xmlImport->clearIblockCacheOnHit();
683 $this->setMessage(Loc::getMessage(
'IBLOCK_XML_IMPORT_MESS_PROCESS_MISSING_IBLOCK_SECTIONS_COMPLETE'));
689 private function resortSectionsAction(): void
691 $this->xmlImport->freezeIblockCache();
692 $this->xmlImport->SectionsResort();
693 $this->xmlImport->unFreezeIblockCache();
694 $this->xmlImport->clearIblockCacheOnHit();
696 $this->setMessage(Loc::getMessage(
'IBLOCK_XML_IMPORT_MESS_IBLOCK_SECTIONS_RESORT_COMPLETE'));
702 private function importElementsAction(): void
704 $this->xmlImport->freezeIblockCache();
705 $result = $this->xmlImport->GetTotalCountElementsForImport();
708 $this->addError(Loc::getMessage(
709 'IBLOCK_XML_IMPORT_ERR_ELEMENTS_IMPORT_FAILURE',
710 [
'#ERROR#' => $this->xmlImport->LAST_ERROR]
715 $this->xmlImport->ReadCatalogData(
716 $_SESSION[self::SESSION_STORAGE_ID][
'SECTIONS_MAP'],
717 $_SESSION[self::SESSION_STORAGE_ID][
'PRICES_MAP']
719 $result = $this->xmlImport->ImportElements(
721 $this->getParameter(
'INTERVAL')
724 $this->xmlImport->unFreezeIblockCache();
725 $this->xmlImport->clearIblockCacheOnHit();
729 $this->setMessage(Loc::getMessage(
'IBLOCK_XML_IMPORT_MESS_IBLOCK_ELEMENTS_IMPORT_COMPLETE'));
733 $this->setMessage(Loc::getMessage(
734 'IBLOCK_XML_IMPORT_MESS_IBLOCK_ELEMENTS_IMPORT_PROGRESS',
736 '#TOTAL#' => $this->stepParameters[
'DONE'][
'ALL'],
737 '#DONE#' => $this->stepParameters[
'DONE'][
'CRC']
740 $this->setProgressCounter(
741 $this->stepParameters[
'DONE'][
'ALL'],
742 $this->stepParameters[
'DONE'][
'CRC']
750 private function processMissingElementsAction(): void
752 $this->xmlImport->freezeIblockCache();
753 $result = $this->xmlImport->DeactivateElement(
754 $this->getParameter(
'MISSING_ELEMENT_ACTION'),
756 $this->getParameter(
'INTERVAL')
759 $this->xmlImport->unFreezeIblockCache();
760 $this->xmlImport->clearIblockCacheOnHit();
764 $this->setMessage(Loc::getMessage(
'IBLOCK_XML_IMPORT_MESS_PROCESS_MISSING_IBLOCK_ELEMENTS_COMPLETE'));
768 $this->setMessage(Loc::getMessage(
769 'IBLOCK_XML_IMPORT_MESS_IBLOCK_ELEMENTS_IMPORT_PROGRESS',
771 '#TOTAL#' => $this->stepParameters[
'DONE'][
'ALL'],
772 '#DONE#' => $this->stepParameters[
'DONE'][
'NON']
775 $this->setProgressCounter(
776 $this->stepParameters[
'DONE'][
'ALL'],
777 $this->stepParameters[
'DONE'][
'NON']
785 private function importProductBundlesAction(): void
787 $this->xmlImport->ImportProductSets();
789 $this->setMessage(Loc::getMessage(
'IBLOCK_XML_IMPORT_MESS_PRODUCT_BUNDLES_IMPORT_COMPLETE'));
795 private function finalAction(): void
797 $this->xmlImport->clearIblockCacheAfterFinal();
798 $this->iblockId = $this->stepParameters[
'IBLOCK_ID'];
800 $this->setMessage(Loc::getMessage(
'IBLOCK_XML_IMPORT_MESS_FINAL_SUCCESS'));
801 $this->destroyXmlImporter();
802 $this->destroySessionStorage();
808 private function openXmlFile(): void
810 $this->closeXmlFile();
812 if ($this->fileParameters[
'ABSOLUTE_PATH'] ==
'')
814 $this->addError(Loc::getMessage(
'IBLOCK_XML_IMPORT_ERR_OPEN_XML_FILE'));
818 $this->fileHandler = fopen($this->fileParameters[
'ABSOLUTE_PATH'],
'rb');
819 if (!is_resource($this->fileHandler))
821 $this->addError(Loc::getMessage(
'IBLOCK_XML_IMPORT_ERR_OPEN_XML_FILE'));
825 $this->fileParameters[
'SIZE'] = (int)filesize($this->fileParameters[
'ABSOLUTE_PATH']);
826 if ($this->fileParameters[
'SIZE'] <= 0)
828 $this->addError(Loc::getMessage(
'IBLOCK_XML_IMPORT_ERR_OPEN_XML_FILE'));
837 private function closeXmlFile(): void
839 if (!is_resource($this->fileHandler))
843 fclose($this->fileHandler);
844 $this->fileHandler =
null;
850 private function getXmlFileProgressPercent()
852 if (!is_resource($this->fileHandler))
856 if ($this->fileParameters[
'SIZE'] <= 0)
861 return round($this->xmlImport->GetFilePosition()*100/$this->fileParameters[
'SIZE'], 2);
867 private function createXmlImporter(): void
869 $this->xmlImport =
new CIBlockCMLImport();
875 private function destroyXmlImporter(): void
877 if (is_object($this->xmlImport))
879 $this->xmlImport =
null;
886 private function destroySessionStorage(): void
888 unset($this->stepId);
889 unset($this->stepParameters);
890 if (array_key_exists(self::SESSION_STORAGE_ID, $_SESSION))
892 unset($_SESSION[self::SESSION_STORAGE_ID]);
901 private function checkTranslitMode(
int $currentValue,
int $mode): bool
903 return ($currentValue & $mode) > 0;
909 private function getXmlImporterTransliterationSettings():
array
911 $config = $this->getConfigFieldValue(
'TRANSLITERATION');
913 'translit_on_add' => $this->checkTranslitMode(
915 self::TRANSLITERATION_ON_ADD
917 'translit_on_update' => $this->checkTranslitMode(
919 self::TRANSLITERATION_ON_UPDATE
921 'translit_params' => [
922 'max_len' => $config[
'SETTINGS'][
'TRANS_LEN'],
923 'change_case' => $config[
'SETTINGS'][
'TRANS_CASE'],
924 'replace_space' => $config[
'SETTINGS'][
'TRANS_SPACE'],
925 'replace_other' => $config[
'SETTINGS'][
'TRANS_OTHER'],
926 'delete_repeat_replace' => $config[
'SETTINGS'][
'TRANS_EAT'] ==
'Y',
937 private static function clearNull($value): bool