Import.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\ImportExport\Model;
  7. use Magento\Framework\App\Filesystem\DirectoryList;
  8. use Magento\Framework\App\ObjectManager;
  9. use Magento\Framework\HTTP\Adapter\FileTransferFactory;
  10. use Magento\Framework\Stdlib\DateTime\DateTime;
  11. use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError;
  12. use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
  13. use Magento\Framework\Message\ManagerInterface;
  14. /**
  15. * Import model
  16. *
  17. * @api
  18. *
  19. * @method string getBehavior() getBehavior()
  20. * @method \Magento\ImportExport\Model\Import setEntity() setEntity(string $value)
  21. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  22. * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
  23. * @since 100.0.2
  24. */
  25. class Import extends \Magento\ImportExport\Model\AbstractModel
  26. {
  27. /**#@+
  28. * Import behaviors
  29. */
  30. const BEHAVIOR_APPEND = 'append';
  31. const BEHAVIOR_ADD_UPDATE = 'add_update';
  32. const BEHAVIOR_REPLACE = 'replace';
  33. const BEHAVIOR_DELETE = 'delete';
  34. const BEHAVIOR_CUSTOM = 'custom';
  35. /**#@-*/
  36. /**#@+
  37. * Form field names (and IDs)
  38. */
  39. /**
  40. * Import source file.
  41. */
  42. const FIELD_NAME_SOURCE_FILE = 'import_file';
  43. /**
  44. * Import image archive.
  45. */
  46. const FIELD_NAME_IMG_ARCHIVE_FILE = 'import_image_archive';
  47. /**
  48. * Import images file directory.
  49. */
  50. const FIELD_NAME_IMG_FILE_DIR = 'import_images_file_dir';
  51. /**
  52. * Allowed errors count field name
  53. */
  54. const FIELD_NAME_ALLOWED_ERROR_COUNT = 'allowed_error_count';
  55. /**
  56. * Validation startegt field name
  57. */
  58. const FIELD_NAME_VALIDATION_STRATEGY = 'validation_strategy';
  59. /**
  60. * Import field separator.
  61. */
  62. const FIELD_FIELD_SEPARATOR = '_import_field_separator';
  63. /**
  64. * Import multiple value separator.
  65. */
  66. const FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR = '_import_multiple_value_separator';
  67. /**
  68. * Import empty attribute value constant.
  69. */
  70. const FIELD_EMPTY_ATTRIBUTE_VALUE_CONSTANT = '_import_empty_attribute_value_constant';
  71. /**
  72. * Allow multiple values wrapping in double quotes for additional attributes.
  73. */
  74. const FIELDS_ENCLOSURE = 'fields_enclosure';
  75. /**#@-*/
  76. /**
  77. * default delimiter for several values in one cell as default for FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR
  78. */
  79. const DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR = ',';
  80. /**
  81. * default empty attribute value constant
  82. */
  83. const DEFAULT_EMPTY_ATTRIBUTE_VALUE_CONSTANT = '__EMPTY__VALUE__';
  84. /**#@+
  85. * Import constants
  86. */
  87. const DEFAULT_SIZE = 50;
  88. const MAX_IMPORT_CHUNKS = 4;
  89. const IMPORT_HISTORY_DIR = 'import_history/';
  90. const IMPORT_DIR = 'import/';
  91. /**#@-*/
  92. /**#@-*/
  93. protected $_entityAdapter;
  94. /**
  95. * Import export data
  96. *
  97. * @var \Magento\ImportExport\Helper\Data
  98. */
  99. protected $_importExportData = null;
  100. /**
  101. * @var \Magento\ImportExport\Model\Import\ConfigInterface
  102. */
  103. protected $_importConfig;
  104. /**
  105. * @var \Magento\ImportExport\Model\Import\Entity\Factory
  106. */
  107. protected $_entityFactory;
  108. /**
  109. * @var \Magento\ImportExport\Model\ResourceModel\Import\Data
  110. */
  111. protected $_importData;
  112. /**
  113. * @var \Magento\ImportExport\Model\Export\Adapter\CsvFactory
  114. */
  115. protected $_csvFactory;
  116. /**
  117. * @var \Magento\Framework\HTTP\Adapter\FileTransferFactory
  118. */
  119. protected $_httpFactory;
  120. /**
  121. * @var \Magento\MediaStorage\Model\File\UploaderFactory
  122. */
  123. protected $_uploaderFactory;
  124. /**
  125. * @var \Magento\Framework\Indexer\IndexerRegistry
  126. */
  127. protected $indexerRegistry;
  128. /**
  129. * @var \Magento\ImportExport\Model\Source\Import\Behavior\Factory
  130. */
  131. protected $_behaviorFactory;
  132. /**
  133. * @var \Magento\Framework\Filesystem
  134. */
  135. protected $_filesystem;
  136. /**
  137. * @var History
  138. */
  139. private $importHistoryModel;
  140. /**
  141. * @var DateTime
  142. */
  143. private $localeDate;
  144. /**
  145. * @var ManagerInterface
  146. */
  147. private $messageManager;
  148. /**
  149. * @param \Psr\Log\LoggerInterface $logger
  150. * @param \Magento\Framework\Filesystem $filesystem
  151. * @param \Magento\ImportExport\Helper\Data $importExportData
  152. * @param \Magento\Framework\App\Config\ScopeConfigInterface $coreConfig
  153. * @param Import\ConfigInterface $importConfig
  154. * @param Import\Entity\Factory $entityFactory
  155. * @param \Magento\ImportExport\Model\ResourceModel\Import\Data $importData
  156. * @param Export\Adapter\CsvFactory $csvFactory
  157. * @param FileTransferFactory $httpFactory
  158. * @param \Magento\MediaStorage\Model\File\UploaderFactory $uploaderFactory
  159. * @param Source\Import\Behavior\Factory $behaviorFactory
  160. * @param \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry
  161. * @param History $importHistoryModel
  162. * @param DateTime $localeDate
  163. * @param array $data
  164. * @param ManagerInterface|null $messageManager
  165. * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  166. */
  167. public function __construct(
  168. \Psr\Log\LoggerInterface $logger,
  169. \Magento\Framework\Filesystem $filesystem,
  170. \Magento\ImportExport\Helper\Data $importExportData,
  171. \Magento\Framework\App\Config\ScopeConfigInterface $coreConfig,
  172. \Magento\ImportExport\Model\Import\ConfigInterface $importConfig,
  173. \Magento\ImportExport\Model\Import\Entity\Factory $entityFactory,
  174. \Magento\ImportExport\Model\ResourceModel\Import\Data $importData,
  175. \Magento\ImportExport\Model\Export\Adapter\CsvFactory $csvFactory,
  176. \Magento\Framework\HTTP\Adapter\FileTransferFactory $httpFactory,
  177. \Magento\MediaStorage\Model\File\UploaderFactory $uploaderFactory,
  178. \Magento\ImportExport\Model\Source\Import\Behavior\Factory $behaviorFactory,
  179. \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry,
  180. \Magento\ImportExport\Model\History $importHistoryModel,
  181. DateTime $localeDate,
  182. array $data = [],
  183. ManagerInterface $messageManager = null
  184. ) {
  185. $this->_importExportData = $importExportData;
  186. $this->_coreConfig = $coreConfig;
  187. $this->_importConfig = $importConfig;
  188. $this->_entityFactory = $entityFactory;
  189. $this->_importData = $importData;
  190. $this->_csvFactory = $csvFactory;
  191. $this->_httpFactory = $httpFactory;
  192. $this->_uploaderFactory = $uploaderFactory;
  193. $this->indexerRegistry = $indexerRegistry;
  194. $this->_behaviorFactory = $behaviorFactory;
  195. $this->_filesystem = $filesystem;
  196. $this->importHistoryModel = $importHistoryModel;
  197. $this->localeDate = $localeDate;
  198. $this->messageManager = $messageManager ?: ObjectManager::getInstance()->get(ManagerInterface::class);
  199. parent::__construct($logger, $filesystem, $data);
  200. }
  201. /**
  202. * Create instance of entity adapter and return it
  203. *
  204. * @throws \Magento\Framework\Exception\LocalizedException
  205. * @return \Magento\ImportExport\Model\Import\Entity\AbstractEntity|\Magento\ImportExport\Model\Import\AbstractEntity
  206. */
  207. protected function _getEntityAdapter()
  208. {
  209. if (!$this->_entityAdapter) {
  210. $entities = $this->_importConfig->getEntities();
  211. if (isset($entities[$this->getEntity()])) {
  212. try {
  213. $this->_entityAdapter = $this->_entityFactory->create($entities[$this->getEntity()]['model']);
  214. } catch (\Exception $e) {
  215. $this->_logger->critical($e);
  216. throw new \Magento\Framework\Exception\LocalizedException(
  217. __('Please enter a correct entity model.')
  218. );
  219. }
  220. if (!$this->_entityAdapter instanceof \Magento\ImportExport\Model\Import\Entity\AbstractEntity &&
  221. !$this->_entityAdapter instanceof \Magento\ImportExport\Model\Import\AbstractEntity
  222. ) {
  223. throw new \Magento\Framework\Exception\LocalizedException(
  224. __(
  225. 'The entity adapter object must be an instance of %1 or %2.',
  226. \Magento\ImportExport\Model\Import\Entity\AbstractEntity::class,
  227. \Magento\ImportExport\Model\Import\AbstractEntity::class
  228. )
  229. );
  230. }
  231. // check for entity codes integrity
  232. if ($this->getEntity() != $this->_entityAdapter->getEntityTypeCode()) {
  233. throw new \Magento\Framework\Exception\LocalizedException(
  234. __('The input entity code is not equal to entity adapter code.')
  235. );
  236. }
  237. } else {
  238. throw new \Magento\Framework\Exception\LocalizedException(__('Please enter a correct entity.'));
  239. }
  240. $this->_entityAdapter->setParameters($this->getData());
  241. }
  242. return $this->_entityAdapter;
  243. }
  244. /**
  245. * Returns source adapter object.
  246. *
  247. * @param string $sourceFile Full path to source file
  248. * @return \Magento\ImportExport\Model\Import\AbstractSource
  249. * @throws \Magento\Framework\Exception\FileSystemException
  250. */
  251. protected function _getSourceAdapter($sourceFile)
  252. {
  253. return \Magento\ImportExport\Model\Import\Adapter::findAdapterFor(
  254. $sourceFile,
  255. $this->_filesystem->getDirectoryWrite(DirectoryList::ROOT),
  256. $this->getData(self::FIELD_FIELD_SEPARATOR)
  257. );
  258. }
  259. /**
  260. * Return operation result messages
  261. *
  262. * @param ProcessingErrorAggregatorInterface $validationResult
  263. * @return string[]
  264. * @throws \Magento\Framework\Exception\LocalizedException
  265. */
  266. public function getOperationResultMessages(ProcessingErrorAggregatorInterface $validationResult)
  267. {
  268. $messages = [];
  269. if ($this->getProcessedRowsCount()) {
  270. if ($validationResult->getErrorsCount()) {
  271. $messages[] = __('Data validation failed. Please fix the following errors and upload the file again.');
  272. // errors info
  273. foreach ($validationResult->getRowsGroupedByErrorCode() as $errorMessage => $rows) {
  274. $error = $errorMessage . ' ' . __('in row(s)') . ': ' . implode(', ', $rows);
  275. $messages[] = $error;
  276. }
  277. } else {
  278. if ($this->isImportAllowed()) {
  279. $messages[] = __('The validation is complete.');
  280. } else {
  281. $messages[] = __('The file is valid, but we can\'t import it for some reason.');
  282. }
  283. }
  284. $messages[] = __(
  285. 'Checked rows: %1, checked entities: %2, invalid rows: %3, total errors: %4',
  286. $this->getProcessedRowsCount(),
  287. $this->getProcessedEntitiesCount(),
  288. $validationResult->getInvalidRowsCount(),
  289. $validationResult->getErrorsCount(
  290. [
  291. ProcessingError::ERROR_LEVEL_CRITICAL,
  292. ProcessingError::ERROR_LEVEL_NOT_CRITICAL
  293. ]
  294. )
  295. );
  296. } else {
  297. $messages[] = __('This file does not contain any data.');
  298. }
  299. return $messages;
  300. }
  301. /**
  302. * Get attribute type for upcoming validation.
  303. *
  304. * @param \Magento\Eav\Model\Entity\Attribute\AbstractAttribute|\Magento\Eav\Model\Entity\Attribute $attribute
  305. * @return string
  306. */
  307. public static function getAttributeType(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute $attribute)
  308. {
  309. $frontendInput = $attribute->getFrontendInput();
  310. if ($attribute->usesSource() && in_array($frontendInput, ['select', 'multiselect', 'boolean'])) {
  311. return $frontendInput;
  312. } elseif ($attribute->isStatic()) {
  313. return $frontendInput == 'date' ? 'datetime' : 'varchar';
  314. } else {
  315. return $attribute->getBackendType();
  316. }
  317. }
  318. /**
  319. * DB data source model getter.
  320. *
  321. * @return \Magento\ImportExport\Model\ResourceModel\Import\Data
  322. */
  323. public function getDataSourceModel()
  324. {
  325. return $this->_importData;
  326. }
  327. /**
  328. * Default import behavior getter.
  329. *
  330. * @static
  331. * @return string
  332. */
  333. public static function getDefaultBehavior()
  334. {
  335. return self::BEHAVIOR_APPEND;
  336. }
  337. /**
  338. * Override standard entity getter.
  339. *
  340. * @throws \Magento\Framework\Exception\LocalizedException
  341. * @return string
  342. */
  343. public function getEntity()
  344. {
  345. if (empty($this->_data['entity'])) {
  346. throw new \Magento\Framework\Exception\LocalizedException(__('Entity is unknown'));
  347. }
  348. return $this->_data['entity'];
  349. }
  350. /**
  351. * Returns number of checked entities.
  352. *
  353. * @return int
  354. * @throws \Magento\Framework\Exception\LocalizedException
  355. */
  356. public function getProcessedEntitiesCount()
  357. {
  358. return $this->_getEntityAdapter()->getProcessedEntitiesCount();
  359. }
  360. /**
  361. * Returns number of checked rows.
  362. *
  363. * @return int
  364. * @throws \Magento\Framework\Exception\LocalizedException
  365. */
  366. public function getProcessedRowsCount()
  367. {
  368. return $this->_getEntityAdapter()->getProcessedRowsCount();
  369. }
  370. /**
  371. * Import/Export working directory (source files, result files, lock files etc.).
  372. *
  373. * @return string
  374. */
  375. public function getWorkingDir()
  376. {
  377. return $this->_varDirectory->getAbsolutePath('importexport/');
  378. }
  379. /**
  380. * Import source file structure to DB.
  381. *
  382. * @return bool
  383. * @throws \Magento\Framework\Exception\LocalizedException
  384. */
  385. public function importSource()
  386. {
  387. $this->setData('entity', $this->getDataSourceModel()->getEntityTypeCode());
  388. $this->setData('behavior', $this->getDataSourceModel()->getBehavior());
  389. $this->importHistoryModel->updateReport($this);
  390. $this->addLogComment(__('Begin import of "%1" with "%2" behavior', $this->getEntity(), $this->getBehavior()));
  391. $result = $this->processImport();
  392. if ($result) {
  393. $this->addLogComment(
  394. [
  395. __(
  396. 'Checked rows: %1, checked entities: %2, invalid rows: %3, total errors: %4',
  397. $this->getProcessedRowsCount(),
  398. $this->getProcessedEntitiesCount(),
  399. $this->getErrorAggregator()->getInvalidRowsCount(),
  400. $this->getErrorAggregator()->getErrorsCount()
  401. ),
  402. __('The import was successful.'),
  403. ]
  404. );
  405. $this->importHistoryModel->updateReport($this, true);
  406. } else {
  407. $this->importHistoryModel->invalidateReport($this);
  408. }
  409. return $result;
  410. }
  411. /**
  412. * Process import.
  413. *
  414. * @return bool
  415. * @throws \Magento\Framework\Exception\LocalizedException
  416. */
  417. protected function processImport()
  418. {
  419. return $this->_getEntityAdapter()->importData();
  420. }
  421. /**
  422. * Import possibility getter.
  423. *
  424. * @return bool
  425. * @throws \Magento\Framework\Exception\LocalizedException
  426. */
  427. public function isImportAllowed()
  428. {
  429. return $this->_getEntityAdapter()->isImportAllowed();
  430. }
  431. /**
  432. * Get error aggregator instance.
  433. *
  434. * @return ProcessingErrorAggregatorInterface
  435. * @throws \Magento\Framework\Exception\LocalizedException
  436. */
  437. public function getErrorAggregator()
  438. {
  439. return $this->_getEntityAdapter()->getErrorAggregator();
  440. }
  441. /**
  442. * Move uploaded file.
  443. *
  444. * @throws \Magento\Framework\Exception\LocalizedException
  445. * @return string Source file path
  446. */
  447. public function uploadSource()
  448. {
  449. /** @var $adapter \Zend_File_Transfer_Adapter_Http */
  450. $adapter = $this->_httpFactory->create();
  451. if (!$adapter->isValid(self::FIELD_NAME_SOURCE_FILE)) {
  452. $errors = $adapter->getErrors();
  453. if ($errors[0] == \Zend_Validate_File_Upload::INI_SIZE) {
  454. $errorMessage = $this->_importExportData->getMaxUploadSizeMessage();
  455. } else {
  456. $errorMessage = __('The file was not uploaded.');
  457. }
  458. throw new \Magento\Framework\Exception\LocalizedException($errorMessage);
  459. }
  460. $entity = $this->getEntity();
  461. /** @var $uploader \Magento\MediaStorage\Model\File\Uploader */
  462. $uploader = $this->_uploaderFactory->create(['fileId' => self::FIELD_NAME_SOURCE_FILE]);
  463. $uploader->skipDbProcessing(true);
  464. $result = $uploader->save($this->getWorkingDir());
  465. $extension = pathinfo($result['file'], PATHINFO_EXTENSION);
  466. $uploadedFile = $result['path'] . $result['file'];
  467. if (!$extension) {
  468. $this->_varDirectory->delete($uploadedFile);
  469. throw new \Magento\Framework\Exception\LocalizedException(__('The file you uploaded has no extension.'));
  470. }
  471. $sourceFile = $this->getWorkingDir() . $entity;
  472. $sourceFile .= '.' . $extension;
  473. $sourceFileRelative = $this->_varDirectory->getRelativePath($sourceFile);
  474. if (strtolower($uploadedFile) != strtolower($sourceFile)) {
  475. if ($this->_varDirectory->isExist($sourceFileRelative)) {
  476. $this->_varDirectory->delete($sourceFileRelative);
  477. }
  478. try {
  479. $this->_varDirectory->renameFile(
  480. $this->_varDirectory->getRelativePath($uploadedFile),
  481. $sourceFileRelative
  482. );
  483. } catch (\Magento\Framework\Exception\FileSystemException $e) {
  484. throw new \Magento\Framework\Exception\LocalizedException(__('The source file moving process failed.'));
  485. }
  486. }
  487. $this->_removeBom($sourceFile);
  488. $this->createHistoryReport($sourceFileRelative, $entity, $extension, $result);
  489. return $sourceFile;
  490. }
  491. /**
  492. * Move uploaded file and provide source instance.
  493. *
  494. * @return Import\AbstractSource
  495. * @throws \Magento\Framework\Exception\FileSystemException
  496. * @throws \Magento\Framework\Exception\LocalizedException
  497. * @since 100.2.7
  498. */
  499. public function uploadFileAndGetSource()
  500. {
  501. $sourceFile = $this->uploadSource();
  502. try {
  503. $source = $this->_getSourceAdapter($sourceFile);
  504. } catch (\Exception $e) {
  505. $this->_varDirectory->delete($this->_varDirectory->getRelativePath($sourceFile));
  506. throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage()));
  507. }
  508. return $source;
  509. }
  510. /**
  511. * Remove BOM from a file
  512. *
  513. * @param string $sourceFile
  514. * @return $this
  515. * @throws \Magento\Framework\Exception\FileSystemException
  516. */
  517. protected function _removeBom($sourceFile)
  518. {
  519. $string = $this->_varDirectory->readFile($this->_varDirectory->getRelativePath($sourceFile));
  520. if ($string !== false && substr($string, 0, 3) == pack("CCC", 0xef, 0xbb, 0xbf)) {
  521. $string = substr($string, 3);
  522. $this->_varDirectory->writeFile($this->_varDirectory->getRelativePath($sourceFile), $string);
  523. }
  524. return $this;
  525. }
  526. /**
  527. * Validates source file and returns validation result
  528. *
  529. * Before validate data the method requires to initialize error aggregator (ProcessingErrorAggregatorInterface)
  530. * with 'validation strategy' and 'allowed error count' values to allow using this parameters in validation process.
  531. *
  532. * @param \Magento\ImportExport\Model\Import\AbstractSource $source
  533. * @return bool
  534. * @throws \Magento\Framework\Exception\LocalizedException
  535. */
  536. public function validateSource(\Magento\ImportExport\Model\Import\AbstractSource $source)
  537. {
  538. $this->addLogComment(__('Begin data validation'));
  539. $errorAggregator = $this->getErrorAggregator();
  540. $errorAggregator->initValidationStrategy(
  541. $this->getData(self::FIELD_NAME_VALIDATION_STRATEGY),
  542. $this->getData(self::FIELD_NAME_ALLOWED_ERROR_COUNT)
  543. );
  544. try {
  545. $adapter = $this->_getEntityAdapter()->setSource($source);
  546. $adapter->validateData();
  547. } catch (\Exception $e) {
  548. $errorAggregator->addError(
  549. \Magento\ImportExport\Model\Import\Entity\AbstractEntity::ERROR_CODE_SYSTEM_EXCEPTION,
  550. ProcessingError::ERROR_LEVEL_CRITICAL,
  551. null,
  552. null,
  553. $e->getMessage()
  554. );
  555. }
  556. $messages = $this->getOperationResultMessages($errorAggregator);
  557. $this->addLogComment($messages);
  558. $errorsCount = $errorAggregator->getErrorsCount();
  559. $result = !$errorsCount;
  560. $validationStrategy = $this->getData(self::FIELD_NAME_VALIDATION_STRATEGY);
  561. if ($errorsCount
  562. && $validationStrategy === ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_SKIP_ERRORS
  563. ) {
  564. $this->messageManager->addWarningMessage(__('Skipped errors: %1', $errorsCount));
  565. $result = true;
  566. }
  567. if ($result) {
  568. $this->addLogComment(__('Import data validation is complete.'));
  569. }
  570. return $result;
  571. }
  572. /**
  573. * Invalidate indexes by process codes.
  574. *
  575. * @return $this
  576. * @throws \Magento\Framework\Exception\LocalizedException
  577. */
  578. public function invalidateIndex()
  579. {
  580. $relatedIndexers = $this->_importConfig->getRelatedIndexers($this->getEntity());
  581. if (empty($relatedIndexers)) {
  582. return $this;
  583. }
  584. foreach (array_keys($relatedIndexers) as $indexerId) {
  585. try {
  586. $indexer = $this->indexerRegistry->get($indexerId);
  587. if (!$indexer->isScheduled()) {
  588. $indexer->invalidate();
  589. }
  590. } catch (\InvalidArgumentException $e) {
  591. }
  592. }
  593. return $this;
  594. }
  595. /**
  596. * Gets array of entities and appropriate behaviours
  597. * array(
  598. * <entity_code> => array(
  599. * 'token' => <behavior_class_name>,
  600. * 'code' => <behavior_model_code>,
  601. * ),
  602. * ...
  603. * )
  604. *
  605. * @return array
  606. * @throws \Magento\Framework\Exception\LocalizedException
  607. */
  608. public function getEntityBehaviors()
  609. {
  610. $behaviourData = [];
  611. $entities = $this->_importConfig->getEntities();
  612. foreach ($entities as $entityCode => $entityData) {
  613. $behaviorClassName = isset($entityData['behaviorModel']) ? $entityData['behaviorModel'] : null;
  614. if ($behaviorClassName && class_exists($behaviorClassName)) {
  615. /** @var $behavior \Magento\ImportExport\Model\Source\Import\AbstractBehavior */
  616. $behavior = $this->_behaviorFactory->create($behaviorClassName);
  617. $behaviourData[$entityCode] = [
  618. 'token' => $behaviorClassName,
  619. 'code' => $behavior->getCode() . '_behavior',
  620. 'notes' => $behavior->getNotes($entityCode),
  621. ];
  622. } else {
  623. throw new \Magento\Framework\Exception\LocalizedException(
  624. __('The behavior token for %1 is invalid.', $entityCode)
  625. );
  626. }
  627. }
  628. return $behaviourData;
  629. }
  630. /**
  631. * Get array of unique entity behaviors
  632. * array(
  633. * <behavior_model_code> => <behavior_class_name>,
  634. * ...
  635. * )
  636. *
  637. * @return array
  638. * @throws \Magento\Framework\Exception\LocalizedException
  639. */
  640. public function getUniqueEntityBehaviors()
  641. {
  642. $uniqueBehaviors = [];
  643. $behaviourData = $this->getEntityBehaviors();
  644. foreach ($behaviourData as $behavior) {
  645. $behaviorCode = $behavior['code'];
  646. if (!isset($uniqueBehaviors[$behaviorCode])) {
  647. $uniqueBehaviors[$behaviorCode] = $behavior['token'];
  648. }
  649. }
  650. return $uniqueBehaviors;
  651. }
  652. /**
  653. * Retrieve processed reports entity types
  654. *
  655. * @param string|null $entity
  656. * @return bool
  657. * @throws \Magento\Framework\Exception\LocalizedException
  658. */
  659. public function isReportEntityType($entity = null)
  660. {
  661. $result = false;
  662. if (!$entity) {
  663. $entity = $this->getEntity();
  664. }
  665. if ($entity !== null && $this->_getEntityAdapter()->getEntityTypeCode() != $entity) {
  666. $entities = $this->_importConfig->getEntities();
  667. if (isset($entities[$entity])) {
  668. try {
  669. $result = $this->_getEntityAdapter()->isNeedToLogInHistory();
  670. } catch (\Exception $e) {
  671. throw new \Magento\Framework\Exception\LocalizedException(
  672. __('Please enter a correct entity model')
  673. );
  674. }
  675. } else {
  676. throw new \Magento\Framework\Exception\LocalizedException(__('Please enter a correct entity model'));
  677. }
  678. } else {
  679. $result = $this->_getEntityAdapter()->isNeedToLogInHistory();
  680. }
  681. return $result;
  682. }
  683. /**
  684. * Create history report
  685. *
  686. * @param string $sourceFileRelative
  687. * @param string $entity
  688. * @param string $extension
  689. * @param array $result
  690. * @return $this
  691. * @throws \Magento\Framework\Exception\LocalizedException
  692. */
  693. protected function createHistoryReport($sourceFileRelative, $entity, $extension = null, $result = null)
  694. {
  695. if ($this->isReportEntityType($entity)) {
  696. if (is_array($sourceFileRelative)) {
  697. $fileName = $sourceFileRelative['file_name'];
  698. $sourceFileRelative = $this->_varDirectory->getRelativePath(self::IMPORT_DIR . $fileName);
  699. } elseif (isset($result['name'])) {
  700. $fileName = $result['name'];
  701. } elseif ($extension !== null) {
  702. $fileName = $entity . $extension;
  703. } else {
  704. $fileName = basename($sourceFileRelative);
  705. }
  706. $copyName = $this->localeDate->gmtTimestamp() . '_' . $fileName;
  707. $copyFile = self::IMPORT_HISTORY_DIR . $copyName;
  708. try {
  709. if ($this->_varDirectory->isExist($sourceFileRelative)) {
  710. $this->_varDirectory->copyFile($sourceFileRelative, $copyFile);
  711. } else {
  712. $content = $this->_varDirectory->getDriver()->fileGetContents($sourceFileRelative);
  713. $this->_varDirectory->writeFile($copyFile, $content);
  714. }
  715. } catch (\Magento\Framework\Exception\FileSystemException $e) {
  716. throw new \Magento\Framework\Exception\LocalizedException(__('Source file coping failed'));
  717. }
  718. $this->importHistoryModel->addReport($copyName);
  719. }
  720. return $this;
  721. }
  722. /**
  723. * Get count of created items
  724. *
  725. * @return int
  726. * @throws \Magento\Framework\Exception\LocalizedException
  727. */
  728. public function getCreatedItemsCount()
  729. {
  730. return $this->_getEntityAdapter()->getCreatedItemsCount();
  731. }
  732. /**
  733. * Get count of updated items
  734. *
  735. * @return int
  736. * @throws \Magento\Framework\Exception\LocalizedException
  737. */
  738. public function getUpdatedItemsCount()
  739. {
  740. return $this->_getEntityAdapter()->getUpdatedItemsCount();
  741. }
  742. /**
  743. * Get count of deleted items
  744. *
  745. * @return int
  746. * @throws \Magento\Framework\Exception\LocalizedException
  747. */
  748. public function getDeletedItemsCount()
  749. {
  750. return $this->_getEntityAdapter()->getDeletedItemsCount();
  751. }
  752. }