diff --git a/.all-contributorsrc b/.all-contributorsrc index 0507fc3..b216c86 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -117,6 +117,15 @@ "contributions": [ "doc" ] + }, + { + "login": "sprankhub", + "name": "Simon Sprankel", + "avatar_url": "https://avatars.githubusercontent.com/u/930199?v=4", + "profile": "https://github.com/sprankhub", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7 diff --git a/Exception/ImportException.php b/Exception/ImportException.php new file mode 100644 index 0000000..aced256 --- /dev/null +++ b/Exception/ImportException.php @@ -0,0 +1,14 @@ +scopeConfig->getValue(self::XML_PATH_CATEGORY_PATH_SEPERATOR, ScopeInterface::SCOPE_STORE); - } - - /** - * @return string - */ - public function getIgnoreDuplicates() - { - return $this->scopeConfig->getValue(self::XML_PATH_IGNORE_DUPLICATES, ScopeInterface::SCOPE_STORE); - } - - /** - * @return string - */ - public function getBehavior() - { - return $this->scopeConfig->getValue(self::XML_PATH_BEHAVIOR, ScopeInterface::SCOPE_STORE); - } - - /** - * @return string - */ - public function getEntity() - { - return $this->scopeConfig->getValue(self::XML_PATH_ENTITY, ScopeInterface::SCOPE_STORE); - } - - /** - * @return string - */ - public function getValidationStrategy() - { - return $this->scopeConfig->getValue(self::XML_PATH_VALIDATION_STRATEGY, ScopeInterface::SCOPE_STORE); - } - - /** - * @return string - */ - public function getAllowedErrorCount() - { - return $this->scopeConfig->getValue(self::XML_PATH_ALLOWED_ERROR_COUNT, ScopeInterface::SCOPE_STORE); - } - - /** - * @return string - */ - public function getImportFileDir() - { - return $this->scopeConfig->getValue(self::XML_PATH_IMPORT_IMAGES_FILE_FIR, ScopeInterface::SCOPE_STORE); - } -} diff --git a/Helper/ImportError.php b/Helper/ImportError.php deleted file mode 100644 index 8bd5248..0000000 --- a/Helper/ImportError.php +++ /dev/null @@ -1,167 +0,0 @@ -reportProcessor = $reportProcessor; - $this->historyModel = $historyModel; - $this->reportHelper = $reportHelper; - $this->_helper = $helper; - - parent::__construct($context); - } - - /** - * TODO: Refactor Code - * @param \Magento\Framework\View\Element\AbstractBlock $resultBlock - * @param ProcessingErrorAggregatorInterface $errorAggregator - * @return $this - */ - public function getImportErrorMessages( - ProcessingErrorAggregatorInterface $errorAggregator - ) { - $resultText = ''; - if ($errorAggregator->getErrorsCount()) { - $message = ''; - $counter = 0; - foreach ($this->getErrorMessages($errorAggregator) as $error) { - $message .= ++$counter . '. ' . $error . '
'; - if ($counter >= self::LIMIT_ERRORS_MESSAGE) { - break; - } - } - if ($errorAggregator->hasFatalExceptions()) { - foreach ($this->getSystemExceptions($errorAggregator) as $error) { - $message .= $error->getErrorMessage() - . __('Additional data') . ': ' - . $error->getErrorDescription() . ''; - } - } - try { - $resultText.= - '' . __('Following Error(s) has been occurred during importing process:') . '
' - . '
' . __('Only first 100 errors are displayed here. ') - . '' . __('Download full report') . '
' - . '
' . $message . '
' - ; - } catch (\Exception $e) { - foreach ($this->getErrorMessages($errorAggregator) as $errorMessage) { - $resultText.= $errorMessage; - } - } - } - - return $resultText; - } - - /** - * @param \Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface $errorAggregator - * @return array - */ - protected function getErrorMessages(ProcessingErrorAggregatorInterface $errorAggregator) - { - $messages = []; - $rowMessages = $errorAggregator->getRowsGroupedByErrorCode([], [AbstractEntity::ERROR_CODE_SYSTEM_EXCEPTION]); - foreach ($rowMessages as $errorCode => $rows) { - $messages[] = $errorCode . ' ' . __('in rows:') . ' ' . implode(', ', $rows); - } - return $messages; - } - - /** - * @param ProcessingErrorAggregatorInterface $errorAggregator - * @return \Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError[] - */ - protected function getSystemExceptions(ProcessingErrorAggregatorInterface $errorAggregator) - { - return $errorAggregator->getErrorsByCode([AbstractEntity::ERROR_CODE_SYSTEM_EXCEPTION]); - } - - /** - * @param ProcessingErrorAggregatorInterface $errorAggregator - * @return string - */ - protected function createErrorReport(ProcessingErrorAggregatorInterface $errorAggregator) - { - $this->historyModel->loadLastInsertItem(); - $sourceFile = $this->reportHelper->getReportAbsolutePath($this->historyModel->getImportedFile()); - $writeOnlyErrorItems = true; - if ($this->historyModel->getData('execution_time') == ModelHistory::IMPORT_VALIDATION) { - $writeOnlyErrorItems = false; - } - $fileName = $this->reportProcessor->createReport($sourceFile, $errorAggregator, $writeOnlyErrorItems); - $this->historyModel->addErrorReportFile($fileName); - return $fileName; - } - - /** - * @param string $fileName - * @return string - */ - protected function createDownloadUrlImportHistoryFile($fileName) - { - return $this->getUrl(self::IMPORT_HISTORY_FILE_DOWNLOAD_ROUTE, ['filename' => $fileName]); - } - - /** - * Generate url by route and parameters - * - * @param string $route - * @param array $params - * @return string - */ - public function getUrl($route = '', $params = []) - { - return $this->_helper->getUrl($route, $params); - } -} diff --git a/Model/Adapters/ArrayAdapter.php b/Model/Adapters/ArrayAdapter.php index 6522886..e29f4fb 100644 --- a/Model/Adapters/ArrayAdapter.php +++ b/Model/Adapters/ArrayAdapter.php @@ -1,108 +1,89 @@ array = $data; + $colnames = array_keys($this->current()); + parent::__construct($colnames); + } /** * Go to given position and check if it is valid * - * @throws \OutOfBoundsException * @param int $position * @return void + * @throws \OutOfBoundsException */ public function seek($position) { - $this->_position = $position; + $this->position = $position; if (!$this->valid()) { - throw new \OutOfBoundsException("invalid seek position ($position)"); + throw new \OutOfBoundsException("Invalid seek position ($position)"); } } - /** - * ArrayAdapter constructor. - * @param array $data - */ - public function __construct($data) - { - $this->_array = $data; - $this->_position = 0; - $colnames = array_keys($this->current() ); - parent::__construct($colnames); - } - /** * Rewind to starting position - * - * @return void */ - public function rewind() + public function rewind(): void { - $this->_position = 0; + $this->position = 0; } /** * Get data at current position - * - * @return mixed */ - public function current() + public function current(): array { - return $this->_array[$this->_position]; + return $this->array[$this->position]; } /** * Get current position - * - * @return int */ - public function key() + public function key(): int { - return $this->_position; + return $this->position; } /** * Set pointer to next position - * - * @return void */ - public function next() + public function next(): void { - ++$this->_position; + ++$this->position; } /** * Is current position valid? - * - * @return bool */ - public function valid() + public function valid(): bool { - return isset($this->_array[$this->_position]); + return isset($this->array[$this->position]); } /** - * Column names getter. - * - * @return array + * @return array|string[] */ - public function getColNames() + public function getColNames(): array { - $colNames = array(); - foreach ($this->_array as $row) { + $colNames = []; + foreach ($this->array as $row) { foreach (array_keys($row) as $key) { if (!is_numeric($key) && !isset($colNames[$key])) { $colNames[$key] = $key; @@ -112,24 +93,31 @@ public function getColNames() return $colNames; } - public function setValue($key, $value) + public function setValue(string $key, $value): void { if (!$this->valid()) { return; } - $this->_array[$this->_position][$key] = $value; + $this->array[$this->position][$key] = $value; } - public function unsetValue($key) + public function unsetValue(string $key): void { if (!$this->valid()) { return; } - unset($this->_array[$this->_position][$key]); + unset($this->array[$this->position][$key]); } + /** + * Render next row + * + * Return array or false on error + * + * @return array|false + */ protected function _getNextRow() { $this->next(); diff --git a/Model/Adapters/ArrayAdapterFactory.php b/Model/Adapters/ArrayAdapterFactory.php index cb31657..f11ef36 100644 --- a/Model/Adapters/ArrayAdapterFactory.php +++ b/Model/Adapters/ArrayAdapterFactory.php @@ -1,30 +1,28 @@ _objectManager = $objectManager; - $this->_instanceName = $instanceName; + ObjectManagerInterface $objectManager, + $instanceName = ArrayAdapter::class + ) { + $this->objectManager = $objectManager; + $this->instanceName = $instanceName; } - /** - * @param array $data - * @return \FireGento\FastSimpleImport\Model\Adapters\ArrayAdapter - */ - public function create(array $data = []) + public function create(array $data = []): ArrayAdapter { - return $this->_objectManager->create($this->_instanceName, $data); + return $this->objectManager->create($this->instanceName, $data); } -} \ No newline at end of file +} diff --git a/Model/Adapters/ImportAdapterFactoryInterface.php b/Model/Adapters/ImportAdapterFactoryInterface.php index 5be00a5..886c5e8 100644 --- a/Model/Adapters/ImportAdapterFactoryInterface.php +++ b/Model/Adapters/ImportAdapterFactoryInterface.php @@ -1,13 +1,14 @@ multipleValueSeparator = $multipleValueSeparator; parent::__construct($data); - foreach ($this->_array as &$row) { - foreach ($row as $colName => &$value) + + foreach ($this->array as &$row) { + foreach ($row as &$value) { if (is_array($value)) { $this->convertToArray($value); } + } } - //print_r($this->_array); - } /** - * Transform nested array to string - * - * @param array $line - * @return void + * Transform nested array to flat array of strings */ - protected function convertToArray(&$line) + private function convertToArray(array &$line): void { $implodeStr = $this->multipleValueSeparator; - $arr = array_map( + $array = array_map( function ($value, $key) use (&$implodeStr) { if (is_array($value) && is_numeric($key)) { $this->convertToArray($value); @@ -53,8 +44,6 @@ function ($value, $key) use (&$implodeStr) { array_keys($line) ); - $line = implode( - $implodeStr, $arr - ); + $line = implode($implodeStr, $array); } } diff --git a/Model/Adapters/NestedArrayAdapterFactory.php b/Model/Adapters/NestedArrayAdapterFactory.php index 94acf6f..66fa7a7 100644 --- a/Model/Adapters/NestedArrayAdapterFactory.php +++ b/Model/Adapters/NestedArrayAdapterFactory.php @@ -1,30 +1,28 @@ _objectManager = $objectManager; - $this->_instanceName = $instanceName; + ObjectManagerInterface $objectManager, + $instanceName = NestedArrayAdapter::class + ) { + $this->objectManager = $objectManager; + $this->instanceName = $instanceName; } - /** - * @param array $data - * @return \FireGento\FastSimpleImport\Model\Adapters\NestedArrayAdapter - */ - public function create(array $data = []) + public function create(array $data = []): NestedArrayAdapter { - return $this->_objectManager->create($this->_instanceName, $data); + return $this->objectManager->create($this->instanceName, $data); } -} \ No newline at end of file +} diff --git a/Model/Config.php b/Model/Config.php new file mode 100644 index 0000000..857ab48 --- /dev/null +++ b/Model/Config.php @@ -0,0 +1,58 @@ +scopeConfig->isSetFlag(self::XML_PATH_IGNORE_DUPLICATES); + } + + public function getBehavior(): string + { + return $this->scopeConfig->getValue(self::XML_PATH_BEHAVIOR); + } + + public function getEntity(): string + { + return $this->scopeConfig->getValue(self::XML_PATH_ENTITY); + } + + public function getValidationStrategy(): string + { + return $this->scopeConfig->getValue(self::XML_PATH_VALIDATION_STRATEGY); + } + + public function getAllowedErrorCount(): int + { + return (int) $this->scopeConfig->getValue(self::XML_PATH_ALLOWED_ERROR_COUNT); + } + + public function getImportFileDir(): string + { + return $this->scopeConfig->getValue(self::XML_PATH_IMPORT_IMAGES_FILE_FIR); + } +} diff --git a/Model/Config/Source/Behavior.php b/Model/Config/Source/Behavior.php index f199d0c..c171551 100644 --- a/Model/Config/Source/Behavior.php +++ b/Model/Config/Source/Behavior.php @@ -1,34 +1,31 @@ _options) { - $this->_options = [ - ['value' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND, 'label' => __('Add/Update')], - ['value' => \Magento\ImportExport\Model\Import::BEHAVIOR_REPLACE, 'label' => __('Replace')], - ['value' => \Magento\ImportExport\Model\Import::BEHAVIOR_DELETE, 'label' => __('Delete')], + if ($this->options === null) { + $this->options = [ + ['value' => Import::BEHAVIOR_APPEND, 'label' => __('Append')], + ['value' => Import::BEHAVIOR_ADD_UPDATE, 'label' => __('Add/Update')], + ['value' => Import::BEHAVIOR_REPLACE, 'label' => __('Replace')], + ['value' => Import::BEHAVIOR_DELETE, 'label' => __('Delete')], ]; } - return $this->_options; + return $this->options; } } diff --git a/Model/Config/Source/ValidationStrategy.php b/Model/Config/Source/ValidationStrategy.php index 221f6c8..6c96998 100644 --- a/Model/Config/Source/ValidationStrategy.php +++ b/Model/Config/Source/ValidationStrategy.php @@ -1,33 +1,35 @@ _options) { - $this->_options = [ - ['value' => ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_STOP_ON_ERROR, 'label' => __('Stop on Error')], - ['value' => ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_SKIP_ERRORS, 'label' => __('Skip error entries')], + if ($this->options === null) { + $this->options = [ + [ + 'value' => ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_STOP_ON_ERROR, + 'label' => __('Stop on Error'), + ], + [ + 'value' => ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_SKIP_ERRORS, + 'label' => __('Skip error entries'), + ], ]; } - return $this->_options; + return $this->options; } } diff --git a/Model/Enterprise/CategoryImportVersion.php b/Model/Enterprise/CategoryImportVersion.php index 53c810e..bd76787 100644 --- a/Model/Enterprise/CategoryImportVersion.php +++ b/Model/Enterprise/CategoryImportVersion.php @@ -1,4 +1,9 @@ 'Invalid value in Scope column', self::ERROR_INVALID_WEBSITE => 'Invalid value in Website column (website does not exists?)', self::ERROR_INVALID_STORE => 'Invalid value in Store column (store does not exists?)', @@ -145,199 +148,75 @@ class Category extends \Magento\ImportExport\Model\Import\AbstractEntity /** * Column names that holds images files names - * - * @var array */ - protected $imagesArrayKeys = [ + private array $imagesArrayKeys = [ 'thumbnail', 'image' ]; - protected $newCategory = []; + private array $newCategory = []; /** * Column names that holds values with particular meaning. - * - * @var array */ protected $_specialAttributes = [ - self::COL_STORE, self::COL_ROOT, self::COL_CATEGORY + self::COL_STORE, + self::COL_ROOT, + self::COL_CATEGORY ]; /** * Permanent entity columns. - * - * @var array */ protected $_permanentAttributes = [ - self::COL_ROOT, self::COL_CATEGORY + self::COL_ROOT, + self::COL_CATEGORY ]; - /** - * @var int - */ - protected $errorsLimit; - - /** - * @var array - */ - protected $invalidRows = []; + private ?int $errorsLimit = null; + private array $invalidRows = []; /** * All stores code-ID pairs. - * - * @var array */ - protected $storeCodeToId = []; + private array $storeCodeToId = []; /** * Store ID to its website stores IDs. - * - * @var array */ - protected $storeIdToWebsiteStoreIds = []; + private array $storeIdToWebsiteStoreIds = []; /** * Website code-to-ID - * - * @var array - */ - protected $websiteCodeToId = []; - - /** - * Website code to store code-to-ID pairs which it consists. - * - * @var array - */ - protected $websiteCodeToStoreIds = []; - - /** - * @var CategoryImportVersion - */ - protected $categoryImportVersionFeature; - - /** - * Media files uploader - * - * @var \Magento\CatalogImportExport\Model\Import\Uploader */ - protected $fileUploader; + private array $websiteCodeToId = []; - /** - * @var \Magento\Framework\Filesystem\Directory\WriteInterface - */ - protected $mediaDirectory; - - /** @var bool */ - protected $unsetEmptyFields = false; + private bool $unsetEmptyFields = false; /** @var bool|string */ - protected $symbolEmptyFields = false; + private $symbolEmptyFields = false; /** @var bool|string */ - protected $symbolIgnoreFields = false; - - protected $defaultAttributeSetId = 0; - - /** - * @var \Magento\Store\Model\StoreManagerInterface - */ - protected $storeManager; - - /** - * @var \FireGento\FastSimpleImport\ResourceModel\Import\Category\StorageFactory - */ - protected $storageFactory; - - /** - * @var \Magento\Catalog\Model\Category - */ - protected $defaultCategory; - - /** - * @var \Magento\Catalog\Model\ResourceModel\Category\Attribute\Collection - */ - protected $attributeCollection; - - /** - * @var CategoryCollectionFactory - */ - protected $categoryCollectionFactory; - - /** - * @var \Magento\ImportExport\Model\ResourceModel\Helper - */ - protected $resourceHelper; - - /** - * @var ManagerInterface - */ - protected $eventManager; - - /** - * @var UploaderFactory - */ - protected $uploaderFactory; - - - /** - * @var ObjectRelationProcessor - */ - protected $objectRelationProcessor; - - /** - * @var TransactionManagerInterface - */ - protected $transactionManager; - - /** - * @var CategoryResourceModelFactory - */ - protected $resourceFactory; - - /** - * @var string|null - */ - protected $entityTypeId; - /** - * @var VersionFeaturesFactory - */ - private $versionFeatures; - /** - * @var \Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator - */ - private $categoryUrlRewriteGenerator; - /** - * @var UrlPersistInterface - */ - private $urlPersist; - /** - * @var CategoryRepositoryInterface - */ - private $categoryRepository; + private $symbolIgnoreFields = false; + + private int $defaultAttributeSetId = 0; + private ?CategoryImportVersion $categoryImportVersionFeature; + private ?Uploader $fileUploader = null; + private DirectoryWriteInterface $mediaDirectory; + private StoreManagerInterface $storeManager; + private CategoryModel $defaultCategory; + private CategoryAttributeCollection $attributeCollection; + private CategoryCollectionFactory $categoryCollectionFactory; + private ImportExportHelper $resourceHelper; + private ManagerInterface $eventManager; + private UploaderFactory $uploaderFactory; + private ObjectRelationProcessor $objectRelationProcessor; + private TransactionManagerInterface $transactionManager; + private CategoryResourceModelFactory $resourceFactory; + private VersionFeaturesFactory $versionFeatures; + private CategoryUrlRewriteGenerator $categoryUrlRewriteGenerator; + private UrlPersistInterface $urlPersist; + private CategoryRepositoryInterface $categoryRepository; - /** - * Category constructor. - * @param StringUtils $string - * @param ScopeConfigInterface $scopeConfig - * @param ImportFactory $importFactory - * @param ImportExportHelper $resourceHelper - * @param ResourceConnection $resource - * @param ProcessingErrorAggregatorInterface $errorAggregator - * @param StoreManagerInterface $storeManager - * @param StorageFactory $storageFactory - * @param CategoryModel $defaultCategory - * @param CategoryAttributeCollection $attributeCollection - * @param CategoryCollectionFactory $categoryCollectionFactory - * @param EavConfig $eavConfig - * @param ManagerInterface $eventManager - * @param UploaderFactory $imageUploaderFactory - * @param Filesystem $filesystem - * @param VersionFeaturesFactory $versionFeatures - * @param ObjectRelationProcessor $objectRelationProcessor - * @param TransactionManagerInterface $transactionManager - * @param CategoryResourceModelFactory $resourceFactory - * @param array $data - */ public function __construct( StringUtils $string, ScopeConfigInterface $scopeConfig, @@ -346,7 +225,6 @@ public function __construct( ResourceConnection $resource, ProcessingErrorAggregatorInterface $errorAggregator, StoreManagerInterface $storeManager, - StorageFactory $storageFactory, CategoryModel $defaultCategory, CategoryAttributeCollection $attributeCollection, CategoryCollectionFactory $categoryCollectionFactory, @@ -358,12 +236,11 @@ public function __construct( ObjectRelationProcessor $objectRelationProcessor, TransactionManagerInterface $transactionManager, CategoryResourceModelFactory $resourceFactory, - \Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator $categoryUrlRewriteGenerator, + CategoryUrlRewriteGenerator $categoryUrlRewriteGenerator, CategoryRepositoryInterface $categoryRepository, UrlPersistInterface $urlPersist, array $data = [] - ) - { + ) { parent::__construct( $string, $scopeConfig, @@ -376,29 +253,26 @@ public function __construct( $this->resourceHelper = $resourceHelper; $this->storeManager = $storeManager; - $this->storageFactory = $storageFactory; $this->defaultCategory = $defaultCategory; $this->attributeCollection = $attributeCollection; $this->categoryCollectionFactory = $categoryCollectionFactory; $this->eventManager = $eventManager; $this->uploaderFactory = $imageUploaderFactory; $this->versionFeatures = $versionFeatures; - - $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::ROOT); - - $this->objectRelationProcessor = $objectRelationProcessor; $this->transactionManager = $transactionManager; $this->resourceFactory = $resourceFactory; + $this->categoryUrlRewriteGenerator = $categoryUrlRewriteGenerator; + $this->urlPersist = $urlPersist; + $this->categoryRepository = $categoryRepository; - $entityType = $eavConfig->getEntityType($this->getEntityTypeCode()); - $this->entityTypeId = $entityType->getEntityTypeId(); + $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::ROOT); foreach ($this->messageTemplates as $errorCode => $message) { $this->getErrorAggregator()->addErrorMessageTemplate($errorCode, $message); } - $this->initOnTabAttributes() + $this->initOnTapAttributes() ->initWebsites() ->initStores() ->initCategories() @@ -407,9 +281,6 @@ public function __construct( $this->entityTable = $this->defaultCategory->getResource()->getEntityTable(); $this->categoryImportVersionFeature = $this->versionFeatures->create('CategoryImportVersion'); - $this->categoryUrlRewriteGenerator = $categoryUrlRewriteGenerator; - $this->urlPersist = $urlPersist; - $this->categoryRepository = $categoryRepository; } /** @@ -425,20 +296,17 @@ public function getEntityTypeCode() /** * Initialize the default attribute_set_id - * @return $this */ - protected function initAttributeSetId() + private function initAttributeSetId(): self { - $this->defaultAttributeSetId = $this->defaultCategory->getDefaultAttributeSetId(); + $this->defaultAttributeSetId = (int) $this->defaultCategory->getDefaultAttributeSetId(); return $this; } /** * Initialize customer attributes. - * - * @return $this */ - protected function initAttributes() + private function initAttributes(): self { foreach ($this->attributeCollection as $attribute) { $this->attributes[$attribute->getAttributeCode()] = [ @@ -457,11 +325,8 @@ protected function initAttributes() /** * Returns attributes all values in label-value or value-value pairs form. Labels are lower-cased. - * - * @param \Magento\Eav\Model\Entity\Attribute\AbstractAttribute $attribute - * @return array */ - public function getAttributeOptions(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute $attribute) + public function getAttributeOptions(AbstractAttribute $attribute): array { $options = []; @@ -470,7 +335,7 @@ public function getAttributeOptions(\Magento\Eav\Model\Entity\Attribute\Abstract $index = in_array($attribute->getAttributeCode(), $this->indexValueAttributes) ? 'value' : 'label'; // only default (admin) store values used - /** @var \Magento\Eav\Model\Entity\Attribute $attribute */ + /** @var Attribute $attribute */ $attribute->setStoreId(\Magento\Store\Model\Store::DEFAULT_STORE_ID); try { @@ -495,7 +360,7 @@ public function getAttributeOptions(\Magento\Eav\Model\Entity\Attribute\Abstract * * @return $this */ - protected function initCategories() + private function initCategories(): self { $collection = $this->getCollection(); @@ -517,12 +382,15 @@ protected function initCategories() $this->categoriesWithRoots[$rootCategoryName] = []; } - $index = $this->implodeEscaped($this->_scopeConfig->getValue(Config::XML_PATH_CATEGORY_PATH_SEPERATOR), $path); + $index = $this->implodeEscaped( + (string) $this->_scopeConfig->getValue(Config::XML_PATH_CATEGORY_PATH_SEPERATOR), + $path + ); $this->categoriesWithRoots[$rootCategoryName][$index] = [ 'entity_id' => $category->getId(), - CategoryModel::KEY_PATH => $category->getData(CategoryModel::KEY_PATH), - CategoryModel::KEY_LEVEL => $category->getData(CategoryModel::KEY_LEVEL), - CategoryModel::KEY_POSITION => $category->getData(CategoryModel::KEY_POSITION) + CategoryInterface::KEY_PATH => $category->getData(CategoryInterface::KEY_PATH), + CategoryInterface::KEY_LEVEL => $category->getData(CategoryInterface::KEY_LEVEL), + CategoryInterface::KEY_POSITION => $category->getData(CategoryInterface::KEY_POSITION) ]; //allow importing by ids. @@ -536,38 +404,29 @@ protected function initCategories() } return $this; - } - /** - * @return \Magento\Catalog\Model\ResourceModel\Category\Collection - */ - protected function getCollection() + private function getCollection(): CategoryCollection { return $this->categoryCollectionFactory->create()->setStoreId(0)->addNameToResult(); } - /** - * @param mixed $glue - * @param array $array - * @return string - */ - protected function implodeEscaped($glue, array $array) + private function implodeEscaped(string $glue, array $array): string { $newArray = []; foreach ($array as $value) { $newArray[] = str_replace($glue, '\\' . $glue, $value); } - return implode($this->_scopeConfig->getValue(Config::XML_PATH_CATEGORY_PATH_SEPERATOR), $newArray); + return implode( + $this->_scopeConfig->getValue(Config::XML_PATH_CATEGORY_PATH_SEPERATOR), + $newArray + ); } /** * Initialize stores data - * - * @param bool $withDefault - * @return $this */ - protected function initStores($withDefault = false) + private function initStores(bool $withDefault = false): self { /** @var $store \Magento\Store\Model\Store */ foreach ($this->storeManager->getStores($withDefault) as $store) { @@ -578,11 +437,8 @@ protected function initStores($withDefault = false) /** * Initialize website values. - * - * @param bool $withDefault - * @return $this */ - protected function initWebsites($withDefault = false) + private function initWebsites(bool $withDefault = false): self { /** @var $website \Magento\Store\Model\Website */ foreach ($this->storeManager->getWebsites($withDefault) as $website) { @@ -591,40 +447,25 @@ protected function initWebsites($withDefault = false) return $this; } - /** - * @return $this - */ - protected function initOnTabAttributes() + private function initOnTapAttributes(): self { // TODO: If the OnTap Merchandiser Exists, add Code here: return $this; } - /** - * @param boolean $value - * @return $this - */ - public function setUnsetEmptyFields($value) + public function setUnsetEmptyFields(bool $value): self { - $this->unsetEmptyFields = (boolean)$value; + $this->unsetEmptyFields = $value; return $this; } - /** - * @param string $value - * @return $this - */ - public function setSymbolEmptyFields($value) + public function setSymbolEmptyFields(string $value): self { $this->symbolEmptyFields = $value; return $this; } - /** - * @param string $value - * @return $this - */ - public function setSymbolIgnoreFields($value) + public function setSymbolIgnoreFields(string $value): self { $this->symbolIgnoreFields = $value; return $this; @@ -632,59 +473,50 @@ public function setSymbolIgnoreFields($value) /** * Set the error limit when the importer will stop - * - * @param $limit */ - public function setErrorLimit($limit) + public function setErrorLimit(int $limit): self { if ($limit) { $this->errorsLimit = $limit; } else { $this->errorsLimit = 100; } + return $this; } /** - * Set the error limit when the importer will stop - * - * @return int + * Get the error limit when the importer will stop */ - public function getErrorLimit() + public function getErrorLimit(): int { - return (int)$this->errorsLimit; + return (int) $this->errorsLimit; } - public function getCategoriesWithRoots() + public function getCategoriesWithRoots(): array { return $this->categoriesWithRoots; } /** * DB connection getter. - * - * @return \Magento\Framework\DB\Adapter\AdapterInterface */ - public function getConnection() + public function getConnection(): AdapterInterface { return $this->_connection; } /** * Get next bunch of validatetd rows. - * - * @return array|null */ - public function getNextBunch() + public function getNextBunch(): ?array { return $this->_dataSourceModel->getNextBunch(); } /** * All website codes to ID getter. - * - * @return array */ - public function getWebsiteCodes() + public function getWebsiteCodes(): array { return $this->websiteCodeToId; } @@ -694,7 +526,7 @@ public function getWebsiteCodes() * * @return array */ - public function getAffectedEntityIds() + public function getAffectedEntityIds(): array { $categoryIds = []; while ($bunch = $this->_dataSourceModel->getNextBunch()) { @@ -715,32 +547,25 @@ public function getAffectedEntityIds() /** * Removes empty keys in case value is null or empty string * Behavior can be turned off with config setting "fastsimpleimport/general/clear_field_on_empty_string" - * You can define a string which can be used for clearing a field, configured in "fastsimpleimport/category/symbol_for_clear_field" - * - * @param array $rowData + * You can define a string which can be used for clearing a field, + * configured in "fastsimpleimport/category/symbol_for_clear_field" */ - protected function filterRowData(&$rowData) + private function filterRowData(array &$rowData): void { if ($this->unsetEmptyFields || $this->symbolEmptyFields || $this->symbolIgnoreFields) { foreach ($rowData as $key => $fieldValue) { if ($this->unsetEmptyFields && !strlen($fieldValue)) { unset($rowData[$key]); - } else if ($this->symbolEmptyFields && trim($fieldValue) == $this->symbolEmptyFields) { - $rowData[$key] = NULL; - } else if ($this->symbolIgnoreFields && trim($fieldValue) == $this->symbolIgnoreFields) { + } elseif ($this->symbolEmptyFields && trim($fieldValue) == $this->symbolEmptyFields) { + $rowData[$key] = null; + } elseif ($this->symbolIgnoreFields && trim($fieldValue) == $this->symbolIgnoreFields) { unset($rowData[$key]); } } } } - /** - * Source model setter. - * - * @param array $source - * @return $this - */ - public function setArraySource($source) + public function setArraySource(Import\AbstractSource $source): self { $this->_source = $source; $this->_dataValidated = false; @@ -748,22 +573,18 @@ public function setArraySource($source) return $this; } - /** - * Import behavior setter - * - * @param string $behavior - */ - public function setBehavior($behavior) + public function setBehavior(string $behavior): self { $this->_parameters['behavior'] = $behavior; + return $this; } /** * Partially reindex newly created and updated categories * - * @return $this + * @throws \Exception */ - public function reindexImportedCategories() + public function reindexImportedCategories(): self { switch ($this->getBehavior()) { case Import::BEHAVIOR_DELETE: @@ -772,12 +593,10 @@ public function reindexImportedCategories() case Import::BEHAVIOR_REPLACE: case Import::BEHAVIOR_APPEND: case Import::BEHAVIOR_ADD_UPDATE: - $this->reindexUpdatedCategories(); break; default: throw new \Exception('Unsupported Mode!'); - break; } return $this; } @@ -787,7 +606,7 @@ public function reindexImportedCategories() * @throws \Exception * @return $this */ - protected function indexDeleteEvents() + private function indexDeleteEvents(): self { return $this->reindexUpdatedCategories(); } @@ -801,7 +620,7 @@ protected function reindexUpdatedCategories($categoryId) { /** @var $category \Magento\Catalog\Model\Category */ $category = $this->categoryRepository->get($categoryId); - + foreach ($category->getStoreIds() as $storeId) { if ($storeId == 0) { continue; @@ -821,12 +640,9 @@ public function updateChildrenCount() } /** - * @param string $root - * @param string $category - * * @return array|false */ - public function getEntityByCategory($root, $category) + public function getEntityByCategory(string $root, string $category) { if (isset($this->categoriesWithRoots[$root][$category])) { return $this->categoriesWithRoots[$root][$category]; @@ -840,11 +656,12 @@ public function getEntityByCategory($root, $category) } /** - * @param boolean|int $value + * @param bool|int $value */ - public function setIgnoreDuplicates($value) + public function setIgnoreDuplicates($value): self { $this->_parameters['ignore_duplicates'] = (boolean)$value; + return $this; } /** @@ -859,11 +676,9 @@ protected function _importData() $this->deleteCategories(); } else { $this->saveCategories(); - $this->saveOnTab(); + $this->saveOnTap(); } - //$this->reindexImportedCategories(); - $this->eventManager->dispatch('catalog_category_import_finish_before', ['adapter' => $this]); return true; @@ -872,10 +687,9 @@ protected function _importData() /** * Delete categories. * - * @return $this * @throws \Exception */ - protected function deleteCategories() + private function deleteCategories(): self { $categoryEntityTable = $this->resourceFactory->create()->getEntityTable(); @@ -885,7 +699,8 @@ protected function deleteCategories() foreach ($bunch as $rowNum => $rowData) { $this->filterRowData($rowData); if ($this->validateRow($rowData, $rowNum) && self::SCOPE_DEFAULT == $this->getRowScope($rowData)) { - $idToDelete[] = $this->categoriesWithRoots[$rowData[self::COL_ROOT]][$rowData[self::COL_CATEGORY]]['entity_id']; + $idToDelete[] = + $this->categoriesWithRoots[$rowData[self::COL_ROOT]][$rowData[self::COL_CATEGORY]]['entity_id']; } } if ($idToDelete) { @@ -904,7 +719,10 @@ protected function deleteCategories() $this->transactionManager->rollBack(); throw $e; } - $this->eventManager->dispatch('catalog_category_import_bunch_delete_after', ['adapter' => $this, 'bunch' => $bunch]); + $this->eventManager->dispatch( + 'catalog_category_import_bunch_delete_after', + ['adapter' => $this, 'bunch' => $bunch] + ); } } @@ -960,8 +778,9 @@ public function validateRow(array $rowData, $rowNum) } // common validation - if (self::SCOPE_DEFAULT == $rowScope) { // category is specified, row is SCOPE_DEFAULT, new category block begins - $rowData[CategoryModel::KEY_NAME] = $this->getCategoryName($rowData); + if (self::SCOPE_DEFAULT == $rowScope) { + // category is specified, row is SCOPE_DEFAULT, new category block begins + $rowData[CategoryInterface::KEY_NAME] = $this->getCategoryName($rowData); $this->_processedEntitiesCount++; @@ -976,14 +795,12 @@ public function validateRow(array $rowData, $rowNum) //check if parent category exists if ($this->getParentCategory($rowData) === false) { - $this->addRowError(self::ERROR_PARENT_NOT_FOUND, $rowNum); return false; } - if (isset($this->categoriesWithRoots[$root][$category])) { - - } else { // validate new category type and attribute set + if (!isset($this->categoriesWithRoots[$root][$category])) { + // validate new category type and attribute set if (!isset($this->newCategory[$root][$category])) { $this->newCategory[$root][$category] = ['entity_id' => null]; } @@ -1019,21 +836,15 @@ public function validateRow(array $rowData, $rowNum) return !isset($this->invalidRows[$rowNum]); } - /** - * @return bool - */ - public function getIgnoreDuplicates() + public function getIgnoreDuplicates(): bool { - return (boolean)$this->_parameters['ignore_duplicates']; + return (bool) $this->_parameters['ignore_duplicates']; } /** * Obtain scope of the row from row data. - * - * @param array $rowData - * @return int */ - public function getRowScope(array $rowData) + public function getRowScope(array $rowData): int { if (isset($rowData[self::COL_CATEGORY]) && strlen(trim($rowData[self::COL_CATEGORY]))) { return self::SCOPE_DEFAULT; @@ -1044,26 +855,20 @@ public function getRowScope(array $rowData) } } - /** - * @param array $rowData - * @return string - */ - protected function getCategoryName($rowData) + private function getCategoryName(array $rowData): string { if (isset($rowData[CategoryModel::KEY_NAME]) && strlen($rowData[CategoryModel::KEY_NAME])) { return $rowData[CategoryModel::KEY_NAME]; } - $categoryParts = $this->explodeEscaped($this->_scopeConfig->getValue(Config::XML_PATH_CATEGORY_PATH_SEPERATOR), $rowData[self::COL_CATEGORY]); + $categoryParts = $this->explodeEscaped( + (string) $this->_scopeConfig->getValue(Config::XML_PATH_CATEGORY_PATH_SEPERATOR), + $rowData[self::COL_CATEGORY] + ); return end($categoryParts); } - /** - * @param string $delimiter - * @param string $string - * @return array - */ - protected function explodeEscaped($delimiter = '/', $string) + private function explodeEscaped(string $delimiter, string $string): array { $exploded = explode($delimiter, $string); $fixed = []; @@ -1079,7 +884,9 @@ protected function explodeEscaped($delimiter = '/', $string) array_splice($exploded, $k + 1, 1); --$l; --$k; - } else $fixed[] = trim($exploded[$k]); + } else { + $fixed[] = trim($exploded[$k]); + } } return $fixed; } @@ -1087,22 +894,32 @@ protected function explodeEscaped($delimiter = '/', $string) /** * Get parent ID of category * - * @param array $rowData * @return bool|mixed */ - protected function getParentCategory($rowData) + protected function getParentCategory(array $rowData) { if ($rowData[self::COL_CATEGORY] == $this->getCategoryName($rowData)) { // if _category eq. name then we don't have parents $parent = false; - } elseif (is_numeric($rowData[self::COL_CATEGORY]) && isset($this->categoriesWithRoots[$rowData[self::COL_ROOT]][$rowData[self::COL_CATEGORY]])) { + } elseif (is_numeric($rowData[self::COL_CATEGORY]) + && isset($this->categoriesWithRoots[$rowData[self::COL_ROOT]][$rowData[self::COL_CATEGORY]])) { // existing category given via ID, retrieve correct parent - $categoryParts = explode('/', $this->categoriesWithRoots[$rowData[self::COL_ROOT]][$rowData[self::COL_CATEGORY]][CategoryModel::KEY_PATH]); + $categoryParts = explode( + '/', + $this->categoriesWithRoots + [$rowData[self::COL_ROOT]][$rowData[self::COL_CATEGORY]][CategoryModel::KEY_PATH] + ); $parent = $categoryParts[count($categoryParts) - 2]; } else { - $categoryParts = $this->explodeEscaped($this->_scopeConfig->getValue(Config::XML_PATH_CATEGORY_PATH_SEPERATOR), $rowData[self::COL_CATEGORY]); + $categoryParts = $this->explodeEscaped( + (string) $this->_scopeConfig->getValue(Config::XML_PATH_CATEGORY_PATH_SEPERATOR), + $rowData[self::COL_CATEGORY] + ); array_pop($categoryParts); - $parent = $this->implodeEscaped($this->_scopeConfig->getValue(Config::XML_PATH_CATEGORY_PATH_SEPERATOR), $categoryParts); + $parent = $this->implodeEscaped( + (string) $this->_scopeConfig->getValue(Config::XML_PATH_CATEGORY_PATH_SEPERATOR), + $categoryParts + ); } if ($parent) { @@ -1122,10 +939,8 @@ protected function getParentCategory($rowData) /** * Gather and save information about category entities. - * - * @return $this */ - protected function saveCategories() + private function saveCategories(): self { $nextEntityId = $this->resourceHelper->getNextAutoincrement($this->entityTable); static $entityId; @@ -1148,35 +963,43 @@ protected function saveCategories() if (self::SCOPE_DEFAULT == $rowScope) { $parentCategory = $this->getParentCategory($rowData); - $time = !empty($rowData[CategoryModel::KEY_CREATED_AT]) ? strtotime($rowData[CategoryModel::KEY_CREATED_AT]) : null; + $time = !empty($rowData[CategoryModel::KEY_CREATED_AT]) + ? strtotime($rowData[CategoryModel::KEY_CREATED_AT]) + : null; // entity table data $entityRow = [ - CategoryModel::KEY_PARENT_ID => $parentCategory['entity_id'], - CategoryModel::KEY_LEVEL => $parentCategory[CategoryModel::KEY_LEVEL] + 1, - CategoryModel::KEY_CREATED_AT => (new \DateTime($time))->format(DateTime::DATETIME_PHP_FORMAT), - CategoryModel::KEY_UPDATED_AT => "now()", - CategoryModel::KEY_POSITION => $rowData[CategoryModel::KEY_POSITION] + CategoryInterface::KEY_PARENT_ID => $parentCategory['entity_id'], + CategoryInterface::KEY_LEVEL => $parentCategory[CategoryInterface::KEY_LEVEL] + 1, + CategoryInterface::KEY_CREATED_AT => (new DateTime($time)) + ->format(DateTime::DATETIME_PHP_FORMAT), + CategoryInterface::KEY_UPDATED_AT => "now()", + CategoryInterface::KEY_POSITION => $rowData[CategoryInterface::KEY_POSITION] ]; - if (isset($this->categoriesWithRoots[$rowData[self::COL_ROOT]][$rowData[self::COL_CATEGORY]])) { //edit - $entityId = $this->categoriesWithRoots[$rowData[self::COL_ROOT]][$rowData[self::COL_CATEGORY]]['entity_id']; + if (isset($this->categoriesWithRoots[$rowData[self::COL_ROOT]][$rowData[self::COL_CATEGORY]])) { + //edit + $entityId = $this->categoriesWithRoots + [$rowData[self::COL_ROOT]][$rowData[self::COL_CATEGORY]]['entity_id']; $entityRow['entity_id'] = $entityId; - $entityRow[CategoryModel::KEY_PATH] = $parentCategory[CategoryModel::KEY_PATH] . '/' . $entityId; + $entityRow[CategoryInterface::KEY_PATH] = + $parentCategory[CategoryInterface::KEY_PATH] . '/' . $entityId; $entityRowsUp[] = $entityRow; $rowData['entity_id'] = $entityId; - } else { // create + } else { + // create $entityId = $nextEntityId++; $entityRow['entity_id'] = $entityId; - $entityRow[CategoryModel::KEY_PATH] = $parentCategory[CategoryModel::KEY_PATH] . '/' . $entityId; + $entityRow[CategoryInterface::KEY_PATH] = + $parentCategory[CategoryInterface::KEY_PATH] . '/' . $entityId; $entityRow['attribute_set_id'] = $this->defaultAttributeSetId; $entityRowsIn[] = $entityRow; $this->newCategory[$rowData[self::COL_ROOT]][$rowData[self::COL_CATEGORY]] = [ 'entity_id' => $entityId, - CategoryModel::KEY_PATH => $entityRow[CategoryModel::KEY_PATH], - CategoryModel::KEY_LEVEL => $entityRow[CategoryModel::KEY_LEVEL] + CategoryInterface::KEY_PATH => $entityRow[CategoryInterface::KEY_PATH], + CategoryInterface::KEY_LEVEL => $entityRow[CategoryInterface::KEY_LEVEL] ]; } } @@ -1193,13 +1016,13 @@ protected function saveCategories() // Attributes phase $rowStore = self::SCOPE_STORE == $rowScope ? $this->storeCodeToId[$rowData[self::COL_STORE]] : 0; - /** @var $category \Magento\Catalog\Model\Category */ + /** @var CategoryModel $category */ $category = $this->defaultCategory->setData($rowData); foreach (array_intersect_key($rowData, $this->attributes) as $attrCode => $attrValue) { if (!$this->attributes[$attrCode]['is_static']) { - /** @var \Magento\Eav\Model\Entity\Attribute $attribute */ + /** @var Attribute $attribute */ $attribute = $this->attributes[$attrCode]['attribute']; if ('multiselect' != $attribute->getFrontendInput() @@ -1290,11 +1113,8 @@ protected function _prepareRowForDb(array $rowData) * Uploading files into the "catalog/category" media folder. * Return a new file name if the same file is already exists. * @todo Solve the problem with images that get imported multiple times. - * - * @param string $fileName - * @return string */ - protected function uploadMediaFiles($fileName) + private function uploadMediaFiles(string $fileName): string { try { $res = $this->getUploader()->move($fileName); @@ -1308,11 +1128,10 @@ protected function uploadMediaFiles($fileName) * Returns an object for upload a media files * * @throws LocalizedException - * @return \Magento\CatalogImportExport\Model\Import\Uploader */ - protected function getUploader() + private function getUploader(): Uploader { - if (is_null($this->fileUploader)) { + if ($this->fileUploader === null) { $this->fileUploader = $this->uploaderFactory->create(); $this->fileUploader->init(); @@ -1349,11 +1168,10 @@ protected function getUploader() * @param array $entityRowsUp Row for update * @return $this */ - - protected function saveCategoryEntity(array $entityRowsIn, array $entityRowsUp) + private function saveCategoryEntity(array $entityRowsIn, array $entityRowsUp): self { if ($entityRowsIn) { - if ($this->categoryImportVersionFeature) { + if ($this->categoryImportVersionFeature !== null) { $entityRowsIn = $this->categoryImportVersionFeature->processCategory($entityRowsIn); } @@ -1364,7 +1182,13 @@ protected function saveCategoryEntity(array $entityRowsIn, array $entityRowsUp) $this->_connection->insertOnDuplicate( $this->entityTable, $entityRowsUp, - [CategoryModel::KEY_PARENT_ID, CategoryModel::KEY_PATH, CategoryModel::KEY_POSITION, CategoryModel::KEY_LEVEL, 'children_count'] + [ + CategoryInterface::KEY_PARENT_ID, + CategoryInterface::KEY_PATH, + CategoryInterface::KEY_POSITION, + CategoryInterface::KEY_LEVEL, + 'children_count' + ] ); } @@ -1373,15 +1197,13 @@ protected function saveCategoryEntity(array $entityRowsIn, array $entityRowsUp) /** * Save category attributes. - * - * @param array $attributesData - * @return $this */ - protected function saveCategoryAttributes(array $attributesData) + private function saveCategoryAttributes(array $attributesData): self { - $entityFieldName = 'entity_id'; - if ($this->categoryImportVersionFeature) { + if ($this->categoryImportVersionFeature !== null) { $entityFieldName = $this->categoryImportVersionFeature->getEntityFieldName(); + } else { + $entityFieldName = 'entity_id'; } $entityIds = array(); @@ -1411,8 +1233,6 @@ protected function saveCategoryAttributes(array $attributesData) foreach ($entityIds as $entityId) { $this->reindexUpdatedCategories($entityId); } - - return $this; } @@ -1421,51 +1241,13 @@ protected function saveCategoryAttributes(array $attributesData) * Overwritten in order to fix bug with stock data import * See http://www.magentocommerce.com/bug-tracking/issue/?issue=13539 * See https://github.com/avstudnitz/AvS_FastSimpleImport/issues/3 - * - * @return $this */ - protected function saveOnTab() + private function saveOnTap(): self { // TODO: If the OnTap Merchandiser Exists, add Code here: return $this; } - /** - * Returns boolean TRUE if row scope is default (fundamental) scope. - * - * @param array $rowData - * @return bool - */ - protected function isRowScopeDefault(array $rowData) - { - return strlen(trim($rowData[self::COL_CATEGORY])) ? true : false; - } - - /** - * Ids of categories which have been created, updated or deleted - * - * @return array - */ - protected function getProcessedCategoryIds() - { - $categoryIds = []; - $source = $this->getSource(); - - $source->rewind(); - while ($source->valid()) { - $current = $source->current(); - if (isset($this->newCategory[$current[self::COL_ROOT]][$current[self::COL_CATEGORY]])) { - $categoryIds[] = $this->newCategory[$current[self::COL_ROOT]][$current[self::COL_CATEGORY]]; - } elseif (isset($this->categoriesWithRoots[$current[self::COL_ROOT]][$current[self::COL_CATEGORY]])) { - $categoryIds[] = $this->categoriesWithRoots[$current[self::COL_ROOT]][$current[self::COL_CATEGORY]]; - } - - $source->next(); - } - - return $categoryIds; - } - /** * Validate data rows and save bunches to DB * @@ -1494,11 +1276,7 @@ protected function _saveValidatedBunches() return parent::_saveValidatedBunches(); } - /** - * @param array $rowData - * @return array - */ - protected function customFieldsMapping($rowData) + private function customFieldsMapping(array $rowData): array { return $rowData; } diff --git a/Model/Import/Proxy/Category/ResourceModel.php b/Model/Import/Proxy/Category/ResourceModel.php index 6ace5f8..d8c14d6 100644 --- a/Model/Import/Proxy/Category/ResourceModel.php +++ b/Model/Import/Proxy/Category/ResourceModel.php @@ -1,9 +1,9 @@ + * @copyright © 2016 - 2022 FireGento e.V. - All rights reserved. + * @license https://opensource.org/licenses/GPL-3.0 GPL-3 */ + namespace FireGento\FastSimpleImport\Model\Import\Proxy\Category; class ResourceModel extends \Magento\Catalog\Model\ResourceModel\Category diff --git a/Model/Importer.php b/Model/Importer.php index 263127e..9df24f9 100644 --- a/Model/Importer.php +++ b/Model/Importer.php @@ -1,232 +1,240 @@ errorHelper = $errorHelper; + ImportFactory $importModelFactory, + ImportErrorService $importErrorService, + ImportAdapterFactoryInterface $importAdapterFactory, + Config $config + ) { + $this->importErrorService = $importErrorService; $this->importAdapterFactory = $importAdapterFactory; - $this->configHelper = $configHelper; + $this->config = $config; $this->importModelFactory = $importModelFactory; $this->settings = [ - 'entity' => $this->configHelper->getEntity(), - 'behavior' => $this->configHelper->getBehavior(), - 'ignore_duplicates' => $this->configHelper->getIgnoreDuplicates(), - 'validation_strategy' => $this->configHelper->getValidationStrategy(), - 'allowed_error_count' => $this->configHelper->getAllowedErrorCount(), - 'import_images_file_dir' => $this->configHelper->getImportFileDir(), - 'category_path_seperator' => $this->configHelper->getCategoryPathSeperator(), - '_import_multiple_value_separator' => Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR + 'entity' => $this->config->getEntity(), + 'behavior' => $this->config->getBehavior(), + 'ignore_duplicates' => $this->config->getIgnoreDuplicates(), + 'validation_strategy' => $this->config->getValidationStrategy(), + 'allowed_error_count' => $this->config->getAllowedErrorCount(), + '_import_multiple_value_separator' => Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR, ]; } /** - * Getter for default Delimiter - * @return mixed + * @throws ValidationException + * @throws ImportException */ - - public function getMultipleValueSeparator() + public function processImport(array $dataArray): void { - return $this->settings['_import_multiple_value_separator']; + $this->validateData($dataArray); + $this->importData(); } /** - * Sets the default delimiter - * @param $multipleValueSeparator + * @throws ValidationException */ - public function setMultipleValueSeparator($multipleValueSeparator) + private function validateData(array $dataArray): void { - $this->settings['_import_multiple_value_separator'] = $multipleValueSeparator; + $importModel = $this->getImportModel(); + $source = $this->importAdapterFactory->create([ + 'data' => $dataArray, + 'multipleValueSeparator' => $this->getMultipleValueSeparator(), + ]); + $this->validationResult = $importModel->validateSource($source); + $errorAggregator = $this->getErrorAggregator(); + if ($errorAggregator->hasToBeTerminated()) { + throw new ValidationException( + $this->importErrorService->getImportErrorMessagesAsString($errorAggregator) + ); + } } /** - * @return Adapters\ImportAdapterFactoryInterface + * @throws ImportException */ - public function getImportAdapterFactory() + private function importData() { - return $this->importAdapterFactory; + $importModel = $this->getImportModel(); + $importModel->importSource(); + $this->handleImportResult($importModel); } /** - * @param Adapters\ImportAdapterFactoryInterface $importAdapterFactory + * @throws ImportException */ - public function setImportAdapterFactory($importAdapterFactory) + private function handleImportResult(Import $importModel) { - $this->importAdapterFactory = $importAdapterFactory; + $errorAggregator = $this->getErrorAggregator(); + $this->errorMessages = $this->importErrorService->getImportErrorMessages($errorAggregator); + if (!$errorAggregator->hasToBeTerminated()) { + $importModel->invalidateIndex(); + } else { + throw new ImportException( + $this->importErrorService->getImportErrorMessagesAsString($errorAggregator) + ); + } } - public function processImport($dataArray) + public function getImportModel(): Import { - $validation = $this->_validateData($dataArray); - if ($validation) { - $this->_importData(); + if ($this->importModel === null) { + $this->importModel = $this->importModelFactory->create(); + $this->importModel->setData($this->settings); } - - return $validation; + return $this->importModel; } - protected function _validateData($dataArray) + public function getErrorAggregator(): ProcessingErrorAggregatorInterface { - $importModel = $this->createImportModel(); - $source = $this->importAdapterFactory->create( - array( - 'data' => $dataArray, - 'multipleValueSeparator' => $this->getMultipleValueSeparator() - ) - ); - $this->validationResult = $importModel->validateSource($source); - $this->addToLogTrace($importModel); - return $this->validationResult; + return $this->getImportModel()->getErrorAggregator(); } /** - * @return \Magento\ImportExport\Model\Import + * @throws RuntimeException */ - public function createImportModel() + public function setEntityCode(string $entityCode): self { - $importModel = $this->importModelFactory->create(); - $importModel->setData($this->settings); - return $importModel; - } - - public function addToLogTrace($importModel) - { - $this->logTrace = $this->logTrace . $importModel->getFormatedLogTrace(); - } - - protected function _importData() - { - $importModel = $this->createImportModel(); - $importModel->importSource(); - $this->_handleImportResult($importModel); + $this->assertImportModelNotInitialized(); + $this->settings['entity'] = $entityCode; + return $this; } - protected function _handleImportResult($importModel) + /** + * @throws RuntimeException + */ + public function setBehavior(string $behavior): self { - $errorAggregator = $importModel->getErrorAggregator(); - $this->errorMessages = $this->errorHelper->getImportErrorMessages($errorAggregator); - $this->addToLogTrace($importModel); - if (!$importModel->getErrorAggregator()->hasToBeTerminated()) { - $importModel->invalidateIndex(); - } + $this->assertImportModelNotInitialized(); + $this->settings['behavior'] = $behavior; + return $this; } /** - * @param string $entityCode + * @throws RuntimeException */ - public function setEntityCode($entityCode) + public function setIgnoreDuplicates(bool $value): self { - $this->settings['entity'] = $entityCode; - + $this->assertImportModelNotInitialized(); + $this->settings['ignore_duplicates'] = $value; + return $this; } /** - * @param string $behavior + * @throws RuntimeException */ - public function setBehavior($behavior) + public function setValidationStrategy(string $strategy): self { - $this->settings['behavior'] = $behavior; + $this->assertImportModelNotInitialized(); + $this->settings['validation_strategy'] = $strategy; + return $this; } /** - * @param string $value + * @throws RuntimeException */ - public function setIgnoreDuplicates($value) + public function setValidationStrategySkipErrors(): self { - $this->settings['ignore_duplicates'] = $value; + return $this->setValidationStrategy(ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_SKIP_ERRORS); } /** - * @param string $strategy + * @throws RuntimeException */ - public function setValidationStrategy($strategy) + public function setValidationStrategyStopOnErrors(): self { - $this->settings['validation_strategy'] = $strategy; + return $this->setValidationStrategy(ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_STOP_ON_ERROR); } /** - * @param int $count + * @throws RuntimeException */ - public function setAllowedErrorCount($count) + public function setAllowedErrorCount(int $count): self { + $this->assertImportModelNotInitialized(); $this->settings['allowed_error_count'] = $count; + return $this; } /** - * @param string $dir + * @throws RuntimeException */ - public function setImportImagesFileDir($dir) + public function setMultipleValueSeparator(string $multipleValueSeparator): self { - $this->settings['import_images_file_dir'] = $dir; + $this->assertImportModelNotInitialized(); + $this->settings['_import_multiple_value_separator'] = $multipleValueSeparator; + return $this; + } + + public function setImportAdapterFactory(ImportAdapterFactoryInterface $importAdapterFactory): self + { + $this->importAdapterFactory = $importAdapterFactory; + return $this; } - public function getValidationResult() + public function getValidationResult(): bool { return $this->validationResult; } - public function getLogTrace() + public function getLogTrace(): string { return $this->logTrace; } - public function getErrorMessages() + public function getErrorMessages(): array { return $this->errorMessages; } + public function getMultipleValueSeparator(): string + { + return $this->settings['_import_multiple_value_separator']; + } + + public function getImportAdapterFactory(): ImportAdapterFactoryInterface + { + return $this->importAdapterFactory; + } + + /** + * @throws RuntimeException + */ + private function assertImportModelNotInitialized(): void + { + if ($this->importModel !== null) { + throw new RuntimeException( + __( + 'Method %1 cannot be called after initializing the import model.', + __METHOD__ + ) + ); + } + } } diff --git a/README.md b/README.md index fd57a51..31cec8b 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,14 @@ Wrapper for Magento 2 ImportExport functionality, which imports products and customers from arrays -## [Documentation](http://firegento-fastsimpleimport2.readthedocs.io/en/latest/) +## Documentation + +See [http://firegento-fastsimpleimport2.readthedocs.io/en/latest/](http://firegento-fastsimpleimport2.readthedocs.io/en/latest/) ## Requirements -- Magento >= 2.0.0 -- PHP >= 5.5.0 +- Magento >= 2.3.0 +- PHP >= 7.4.0 ## Support @@ -44,6 +46,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
dcole-inviqa

💻
Vincent MARMIESSE

💻
Kevin Krieger

📖 +
Simon Sprankel

💻 @@ -71,5 +74,5 @@ FireGento Team ## Copyright -(c) 2016 -2020 FireGento Team +(c) 2016 - 2022 FireGento Team diff --git a/ResourceModel/Import/Category/Storage.php b/ResourceModel/Import/Category/Storage.php deleted file mode 100644 index 586c33e..0000000 --- a/ResourceModel/Import/Category/Storage.php +++ /dev/null @@ -1,165 +0,0 @@ - array( - * [website id 1] => customer_id 1, - * [website id 2] => customer_id 2, - * ... => ... , - * [website id n] => customer_id n, - * ) - * - * @var array - */ - protected $_customerIds = []; - - /** - * Number of items to fetch from db in one query - * - * @var int - */ - protected $_pageSize; - - /** - * Collection by pages iterator - * - * @var \Magento\ImportExport\Model\ResourceModel\CollectionByPagesIterator - */ - protected $_byPagesIterator; - - /** - * @param \Magento\Customer\Model\ResourceModel\Customer\CollectionFactory $collectionFactory - * @param \Magento\ImportExport\Model\ResourceModel\CollectionByPagesIteratorFactory $colIteratorFactory - * @param array $data - */ - public function __construct( - \Magento\Customer\Model\ResourceModel\Customer\CollectionFactory $collectionFactory, - \Magento\ImportExport\Model\ResourceModel\CollectionByPagesIteratorFactory $colIteratorFactory, - array $data = [] - ) { - $this->_categoryCollection = isset( - $data['customer_collection'] - ) ? $data['customer_collection'] : $collectionFactory->create(); - $this->_pageSize = isset($data['page_size']) ? $data['page_size'] : 0; - $this->_byPagesIterator = isset( - $data['collection_by_pages_iterator'] - ) ? $data['collection_by_pages_iterator'] : $colIteratorFactory->create(); - } - - /** - * Load needed data from customer collection - * - * @return void - */ - public function load() - { - if ($this->_isCollectionLoaded == false) { - - - $collection = Mage::getResourceModel('catalog/category_collection')->addNameToResult(); - /* @var $collection Mage_Catalog_Model_Resource_Eav_Mysql4_Category_Collection */ - - foreach ($collection as $category) { - /** @var $category Mage_Catalog_Model_Category */ - $structure = explode('/', $category->getPath()); - $pathSize = count($structure); - if ($pathSize > 1) { - $path = array(); - for ($i = 1; $i < $pathSize; $i++) { - $path[] = $collection->getItemById($structure[$i])->getName(); - } - $rootCategoryName = array_shift($path); - if (!isset($this->_categoriesWithRoots[$rootCategoryName])) { - $this->_categoriesWithRoots[$rootCategoryName] = array(); - } - $index = $this->_implodeEscaped('/', $path); - - $this->_categoriesWithRoots[$rootCategoryName][$index] = array( - 'entity_id' => $category->getId(), - 'path' => $category->getPath(), - 'level' => $category->getLevel(), - 'position' => $category->getPosition() - ); - -//allow importing by ids. - if (!isset($this->_categoriesWithRoots[$structure[1]])) { - $this->_categoriesWithRoots[$structure[1]] = array(); - } - $this->_categoriesWithRoots[$structure[1]][$category->getId()] = - $this->_categoriesWithRoots[$rootCategoryName][$index]; - } - } - - - $collection = clone $this->_categoryCollection; - $collection->removeAttributeToSelect(); - $tableName = $collection->getResource()->getEntityTable(); - $collection->getSelect()->from($tableName, ['entity_id', 'website_id', 'email']); - - $this->_byPagesIterator->iterate( - $this->_categoryCollection, - $this->_pageSize, - [[$this, 'addCustomer']] - ); - - $this->_isCollectionLoaded = true; - } - } - - /** - * Add customer to array - * - * @param \Magento\Framework\DataObject|\Magento\Customer\Model\Customer $customer - * @return $this - */ - public function addCategory(\Magento\Framework\DataObject $customer) - { - $email = strtolower(trim($customer->getEmail())); - if (!isset($this->_customerIds[$email])) { - $this->_customerIds[$email] = []; - } - $this->_customerIds[$email][$customer->getWebsiteId()] = $customer->getId(); - - return $this; - } - - /** - * Get customer id - * - * @param string $email - * @param int $websiteId - * @return bool|int - */ - public function getCustomerId($email, $websiteId) - { - // lazy loading - $this->load(); - - if (isset($this->_customerIds[$email][$websiteId])) { - return $this->_customerIds[$email][$websiteId]; - } - - return false; - } -} - - diff --git a/ResourceModel/ImportData.php b/ResourceModel/ImportData.php index 1ef73e2..5ad3450 100644 --- a/ResourceModel/ImportData.php +++ b/ResourceModel/ImportData.php @@ -1,4 +1,8 @@ scopeConfig = $scopeConfig; parent::__construct($context, $jsonHelper, $connectionName); } @@ -44,5 +44,4 @@ protected function _construct() parent::_construct(); } } - -} \ No newline at end of file +} diff --git a/Service/ImportErrorService.php b/Service/ImportErrorService.php new file mode 100644 index 0000000..b1e7265 --- /dev/null +++ b/Service/ImportErrorService.php @@ -0,0 +1,71 @@ +getImportErrorMessages($errorAggregator)); + } + + /** + * @param ProcessingErrorAggregatorInterface $errorAggregator + * @return array|string[] + */ + public function getImportErrorMessages(ProcessingErrorAggregatorInterface $errorAggregator): array + { + $result = []; + if ($errorAggregator->getErrorsCount()) { + $counter = 0; + foreach ($this->getErrorMessages($errorAggregator) as $errorMessage) { + $result[] = $errorMessage; + if ($counter >= self::LIMIT_ERRORS_MESSAGE) { + $result[] = __('Aborted after %1 errors.', self::LIMIT_ERRORS_MESSAGE); + break; + } + } + if ($errorAggregator->hasFatalExceptions()) { + foreach ($this->getSystemExceptions($errorAggregator) as $processingError) { + $result[] = $processingError->getErrorMessage() . + __('Additional data') . ': ' . $processingError->getErrorDescription(); + } + } + } + + return $result; + } + + /** + * @param ProcessingErrorAggregatorInterface $errorAggregator + * @return array|string[] + */ + private function getErrorMessages(ProcessingErrorAggregatorInterface $errorAggregator): array + { + $messages = []; + $rowMessages = $errorAggregator->getRowsGroupedByErrorCode([], [AbstractEntity::ERROR_CODE_SYSTEM_EXCEPTION]); + foreach ($rowMessages as $errorCode => $rows) { + $messages[] = $errorCode . ' ' . __('in rows:') . ' ' . implode(', ', $rows); + } + return $messages; + } + + /** + * @param ProcessingErrorAggregatorInterface $errorAggregator + * @return array|ProcessingError[] + */ + private function getSystemExceptions(ProcessingErrorAggregatorInterface $errorAggregator): array + { + return $errorAggregator->getErrorsByCode([AbstractEntity::ERROR_CODE_SYSTEM_EXCEPTION]); + } +} diff --git a/composer.json b/composer.json index c6f4997..8a61dfa 100644 --- a/composer.json +++ b/composer.json @@ -10,6 +10,10 @@ "email": "team@firegento.com" } ], + "require": { + "php": "^7.4 || ^8.0 || ^8.1", + "magento/module-catalog-import-export": "^101.0.0" + }, "autoload": { "files": [ "registration.php" diff --git a/doc/Installation.md b/doc/Installation.md index 3deac4a..60e2df2 100644 --- a/doc/Installation.md +++ b/doc/Installation.md @@ -14,6 +14,6 @@ Installation Instructions for the latest development/contribution Version --------------------------------------------- composer config repositories.firegento_fastsimpleimport vcs https://github.com/firegento/FireGento_FastSimpleImport2 - composer require firegento/fastsimpleimport dev-master + composer require firegento/fastsimpleimport bin/magento module:enable FireGento_FastSimpleImport - bin/magento setup:upgrade \ No newline at end of file + bin/magento setup:upgrade diff --git a/doc/conf.py b/doc/conf.py index aac7d4d..49b0c22 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -56,7 +56,7 @@ # General information about the project. project = u'FireGento_FastSimpleImport2' -copyright = u'2016, FireGento Team' +copyright = u'2016 - 2022, FireGento Team' author = u'FireGento Team' # The version info for the project you're documenting, acts as replacement for diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 8613a4d..707d6b8 100644 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -1,8 +1,8 @@ @@ -25,12 +25,13 @@ FireGento\FastSimpleImport\Model\Config\Source\ValidationStrategy - + + Only non-fatal errors - import will always stop if any fatal errors occur. validate-number - - - + + validation-stop-on-errors + diff --git a/etc/config.xml b/etc/config.xml index a540cd3..1c482ce 100644 --- a/etc/config.xml +++ b/etc/config.xml @@ -1,75 +1,23 @@ - 0 append catalog_product validation-stop-on-errors - 10 - / + 0 + 0 + + 1 + - - - - email - - - - system_emails_forgot_email_template - general - - - 1 - - - - - - price - media_image - gallery - - - - - - 0 - - - - - - - default - - - default - - - - - - - - - - true - - - - admin/noroute/index - - - - diff --git a/etc/di.xml b/etc/di.xml index ebf948a..0d39165 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -1,14 +1,14 @@ - - \ No newline at end of file + diff --git a/etc/import.xml b/etc/import.xml index 4158b3e..fc4c082 100644 --- a/etc/import.xml +++ b/etc/import.xml @@ -1,9 +1,9 @@ diff --git a/etc/module.xml b/etc/module.xml index 918d9a5..11d574b 100644 --- a/etc/module.xml +++ b/etc/module.xml @@ -1,14 +1,14 @@ - + - \ No newline at end of file + diff --git a/registration.php b/registration.php index 78ef594..e0b6282 100644 --- a/registration.php +++ b/registration.php @@ -1,10 +1,11 @@