diff --git a/app/code/Magento/Catalog/Model/Resource/Category.php b/app/code/Magento/Catalog/Model/Resource/Category.php index d5c541c7cca51..032262d920a96 100644 --- a/app/code/Magento/Catalog/Model/Resource/Category.php +++ b/app/code/Magento/Catalog/Model/Resource/Category.php @@ -236,7 +236,9 @@ protected function _beforeSave(\Magento\Framework\Object $object) } if (!$object->getId()) { - $object->setPosition($this->_getMaxPosition($object->getPath()) + 1); + if (is_null($object->getPosition())) { + $object->setPosition($this->_getMaxPosition($object->getPath()) + 1); + } $path = explode('/', $object->getPath()); $level = count($path); $object->setLevel($level); diff --git a/app/code/Magento/CatalogImportExport/Model/Export/Product.php b/app/code/Magento/CatalogImportExport/Model/Export/Product.php index 923f303f798ce..58aa1666678f9 100644 --- a/app/code/Magento/CatalogImportExport/Model/Export/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Export/Product.php @@ -5,6 +5,8 @@ */ namespace Magento\CatalogImportExport\Model\Export; +use \Magento\Store\Model\Store; + /** * Export entity product model * @@ -81,6 +83,11 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity 'custom_design', ]; + /** + * @var array + */ + protected $collectedMultiselectsData = []; + /** * Permanent entity columns. * @@ -252,12 +259,12 @@ public function __construct( parent::__construct($localeDate, $config, $resource, $storeManager); - $this->_initTypeModels() - ->_initAttributes() + $this->initTypeModels() + ->initAttributes() ->_initStores() - ->_initAttributeSets() - ->_initWebsites() - ->_initCategories(); + ->initAttributeSets() + ->initWebsites() + ->initCategories(); } /** @@ -265,7 +272,7 @@ public function __construct( * * @return $this */ - protected function _initAttributeSets() + protected function initAttributeSets() { $productTypeId = $this->_productFactory->create()->getTypeId(); foreach ($this->_attrSetColFactory->create()->setEntityTypeFilter($productTypeId) as $attributeSet) { @@ -279,7 +286,7 @@ protected function _initAttributeSets() * * @return $this */ - protected function _initCategories() + protected function initCategories() { $collection = $this->_categoryColFactory->create()->addNameToResult(); /* @var $collection \Magento\Catalog\Model\Resource\Category\Collection */ @@ -306,7 +313,7 @@ protected function _initCategories() * @throws \Magento\Framework\Model\Exception * @return $this */ - protected function _initTypeModels() + protected function initTypeModels() { $productTypes = $this->_exportConfig->getEntityTypes($this->getEntityTypeCode()); foreach ($productTypes as $productTypeName => $productTypeConfig) { @@ -345,7 +352,7 @@ protected function _initTypeModels() * * @return $this */ - protected function _initWebsites() + protected function initWebsites() { /** @var $website \Magento\Store\Model\Website */ foreach ($this->_storeManager->getWebsites() as $website) { @@ -360,7 +367,7 @@ protected function _initWebsites() * @param int[] $productIds * @return array */ - protected function _prepareTierPrices(array $productIds) + protected function prepareTierPrices(array $productIds) { if (empty($productIds)) { return []; @@ -395,7 +402,7 @@ protected function _prepareTierPrices(array $productIds) * @param int[] $productIds * @return array */ - protected function _prepareGroupPrices(array $productIds) + protected function prepareGroupPrices(array $productIds) { if (empty($productIds)) { return []; @@ -429,7 +436,7 @@ protected function _prepareGroupPrices(array $productIds) * @param int[] $productIds * @return array */ - protected function _prepareMediaGallery(array $productIds) + protected function getMediaGallery(array $productIds) { if (empty($productIds)) { return []; @@ -474,7 +481,7 @@ protected function _prepareMediaGallery(array $productIds) * @param int[] $productIds * @return array */ - protected function _prepareCatalogInventory(array $productIds) + protected function prepareCatalogInventory(array $productIds) { if (empty($productIds)) { return []; @@ -508,7 +515,7 @@ protected function _prepareCatalogInventory(array $productIds) * @param int[] $productIds * @return array */ - protected function _prepareLinks(array $productIds) + protected function prepareLinks(array $productIds) { if (empty($productIds)) { return []; @@ -578,7 +585,7 @@ protected function _prepareLinks(array $productIds) * @param int $productId * @return bool */ - protected function _updateDataWithCategoryColumns(&$dataRow, &$rowCategories, $productId) + protected function updateDataWithCategoryColumns(&$dataRow, &$rowCategories, $productId) { if (!isset($rowCategories[$productId])) { return false; @@ -610,7 +617,7 @@ public function _getHeaderColumns() * @param array $stockItemRows * @return void */ - protected function _setHeaderColumns($customOptionsData, $stockItemRows) + protected function setHeaderColumns($customOptionsData, $stockItemRows) { if (!$this->_headerColumns) { $customOptCols = [ @@ -674,7 +681,7 @@ protected function _getEntityCollection() * * @return int */ - protected function _getItemsPerPage() + protected function getItemsPerPage() { if (is_null($this->_itemsPerPage)) { $memoryLimit = trim(ini_get('memory_limit')); @@ -718,7 +725,7 @@ protected function _getItemsPerPage() * @param int $pageSize * @return void */ - protected function _paginateCollection($page, $pageSize) + protected function paginateCollection($page, $pageSize) { $this->_getEntityCollection()->setPage($page, $pageSize); } @@ -736,16 +743,16 @@ public function export() $this->_prepareEntityCollection($this->_getEntityCollection()); $this->_getEntityCollection()->setOrder('has_options', 'asc'); - $this->_getEntityCollection()->setStoreId(\Magento\Store\Model\Store::DEFAULT_STORE_ID); + $this->_getEntityCollection()->setStoreId(Store::DEFAULT_STORE_ID); $writer = $this->getWriter(); $page = 0; while (true) { ++$page; - $this->_paginateCollection($page, $this->_getItemsPerPage()); + $this->paginateCollection($page, $this->getItemsPerPage()); if ($this->_getEntityCollection()->count() == 0) { break; } - $exportData = $this->_getExportData(); + $exportData = $this->getExportData(); if ($page == 1) { $writer->setHeaderCols($this->_getHeaderColumns()); } @@ -768,355 +775,364 @@ public function export() * @SuppressWarnings(PHPMD.ExcessiveMethodLength) * @SuppressWarnings(PHPMD.UnusedLocalVariable) */ - protected function _getExportData() + protected function getExportData() { $exportData = []; try { - $collection = $this->_getEntityCollection(); - $validAttrCodes = $this->_getExportAttrCodes(); - $defaultStoreId = \Magento\Store\Model\Store::DEFAULT_STORE_ID; - $dataRows = []; - $rowCategories = []; - $rowWebsites = []; - $rowTierPrices = []; - $rowGroupPrices = []; - $rowMultiselects = []; - $mediaGalery = []; - - // prepare multi-store values and system columns values - foreach ($this->_storeIdToCode as $storeId => &$storeCode) { - // go through all stores - $collection->setStoreId($storeId); - - if ($defaultStoreId == $storeId) { - $collection->addCategoryIds()->addWebsiteNamesToResult(); - - // tier and group price data getting only once - $rowTierPrices = $this->_prepareTierPrices($collection->getAllIds()); - $rowGroupPrices = $this->_prepareGroupPrices($collection->getAllIds()); - - // getting media gallery data - $mediaGalery = $this->_prepareMediaGallery($collection->getAllIds()); + $rawData = $this->collectRawData(); + $multirawData = $this->collectMultirawData(); + + $productIds = array_keys($rawData); + $stockItemRows = $this->prepareCatalogInventory($productIds); + + $this->rowCustomizer->prepareData($this->_getEntityCollection(), $productIds); + + $this->setHeaderColumns($multirawData['customOptionsData'], $stockItemRows); + $this->_headerColumns = $this->rowCustomizer->addHeaderColumns($this->_headerColumns); + + foreach ($rawData as $productId => $productData) { + foreach ($productData as $storeId => $dataRow) { + if ($storeId == Store::DEFAULT_STORE_ID && isset($stockItemRows[$productId])) { + $dataRow = array_merge($dataRow, $stockItemRows[$productId]); + } + + $exportData = array_merge($exportData, $this->addMultirowData($dataRow, $multirawData)); } - foreach ($collection as $itemId => $item) { - // go through all products - $rowIsEmpty = true; - // row is empty by default - - foreach ($validAttrCodes as &$attrCode) { - // go through all valid attribute codes - $attrValue = $item->getData($attrCode); - - if (!empty($this->_attributeValues[$attrCode])) { - if ($this->_attributeTypes[$attrCode] == 'multiselect') { - $attrValue = explode(',', $attrValue); - $attrValue = array_intersect_key( - $this->_attributeValues[$attrCode], - array_flip($attrValue) - ); - $rowMultiselects[$storeId][$itemId][$attrCode] = $attrValue; - } else { - if (isset($this->_attributeValues[$attrCode][$attrValue])) { - $attrValue = $this->_attributeValues[$attrCode][$attrValue]; - } else { - $attrValue = null; - } - } - } - // do not save value same as default or not existent - if ($storeId != $defaultStoreId && isset( - $dataRows[$itemId][$defaultStoreId][$attrCode] - ) && $dataRows[$itemId][$defaultStoreId][$attrCode] == $attrValue - ) { - $attrValue = null; - } + } + } catch (\Exception $e) { + $this->_logger->logException($e); + } + return $exportData; + } + + /** + * Collect export data for all products + * + * @return array + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + protected function collectRawData() + { + $data = []; + $collection = $this->_getEntityCollection(); + foreach ($this->_storeIdToCode as $storeId => $storeCode) { + $collection->setStoreId($storeId); + /** + * @var int $itemId + * @var \Magento\Catalog\Model\Product $item + */ + foreach ($collection as $itemId => $item) { + foreach ($this->_getExportAttrCodes() as $code) { + $attrValue = $item->getData($code); + if (!$this->isValidAttributeValue($code, $attrValue)) { + continue; + } + + if (isset($this->_attributeValues[$code][$attrValue]) && !empty($this->_attributeValues[$code])) { + $attrValue = $this->_attributeValues[$code][$attrValue]; + } + + if ($storeId != Store::DEFAULT_STORE_ID + && isset($data[$itemId][Store::DEFAULT_STORE_ID][$code]) + && $data[$itemId][Store::DEFAULT_STORE_ID][$code] == $attrValue + ) { + continue; + } + + if ($this->_attributeTypes[$code] !== 'multiselect') { if (is_scalar($attrValue)) { - $dataRows[$itemId][$storeId][$attrCode] = $attrValue; - // mark row as not empty - $rowIsEmpty = false; + $data[$itemId][$storeId][$code] = $attrValue; } - if (!empty($rowMultiselects[$storeId][$itemId][$attrCode])) { - $rowIsEmpty = false; - } - } - if ($rowIsEmpty) { - // remove empty rows - unset($dataRows[$itemId][$storeId]); } else { - $attrSetId = $item->getAttributeSetId(); - $dataRows[$itemId][$storeId][self::COL_STORE] = $storeCode; - $dataRows[$itemId][$storeId][self::COL_ATTR_SET] = $this->_attrSetIdToName[$attrSetId]; - $dataRows[$itemId][$storeId][self::COL_TYPE] = $item->getTypeId(); - - if ($defaultStoreId == $storeId) { - $rowWebsites[$itemId] = array_intersect( - array_keys($this->_websiteIdToCode), - $item->getWebsites() - ); - $rowCategories[$itemId] = $item->getCategoryIds(); - } + $this->collectMultiselectValues($item, $code, $storeId); } - $item = null; } - $collection->clear(); - } - // remove unused categories - $allCategoriesIds = array_merge(array_keys($this->_categories), array_keys($this->_rootCategories)); - foreach ($rowCategories as &$categories) { - $categories = array_intersect($categories, $allCategoriesIds); + if (!empty($data[$itemId][$storeId]) || $this->hasMultiselectData($item, $storeId)) { + $attrSetId = $item->getAttributeSetId(); + $data[$itemId][$storeId][self::COL_STORE] = $storeCode; + $data[$itemId][$storeId][self::COL_ATTR_SET] = $this->_attrSetIdToName[$attrSetId]; + $data[$itemId][$storeId][self::COL_TYPE] = $item->getTypeId(); + } + $data[$itemId][$storeId]['store_id'] = $storeId; + $data[$itemId][$storeId]['product_id'] = $itemId; } + $collection->clear(); + } - // prepare catalog inventory information - $productIds = array_keys($dataRows); - $stockItemRows = $this->_prepareCatalogInventory($productIds); + return $data; + } - // prepare links information - $linksRows = $this->_prepareLinks($productIds); - $linkIdColPrefix = []; - foreach ($this->_linkTypeProvider->getLinkTypes() as $linkTypeName => $linkTypeId) { - $linkIdColPrefix[$linkTypeId] = '_' . $linkTypeName . '_'; - } + /** + * @return array + */ + protected function collectMultirawData() + { + $data = []; + $productIds = []; + $rowWebsites = []; + $rowCategories = []; + + $collection = $this->_getEntityCollection(); + $collection->setStoreId(Store::DEFAULT_STORE_ID); + $collection->addCategoryIds()->addWebsiteNamesToResult(); + /** @var \Magento\Catalog\Model\Product $item */ + foreach ($collection as $item) { + $productIds[] = $item->getId(); + $rowWebsites[$item->getId()] = array_intersect( + array_keys($this->_websiteIdToCode), + $item->getWebsites() + ); + $rowCategories[$item->getId()] = $item->getCategoryIds(); + } + $collection->clear(); - $this->rowCustomizer->prepareData($this->_entityCollection, $productIds); - - // prepare custom options information - $customOptionsData = []; - $customOptionsDataPre = []; - - foreach ($this->_storeIdToCode as $storeId => &$storeCode) { - $options = $this->_optionColFactory->create()->reset()->addTitleToResult( - $storeId - )->addPriceToResult( - $storeId - )->addProductToFilter( - $productIds - )->addValuesToResult( - $storeId - ); + $allCategoriesIds = array_merge(array_keys($this->_categories), array_keys($this->_rootCategories)); + foreach ($rowCategories as &$categories) { + $categories = array_intersect($categories, $allCategoriesIds); + } - foreach ($options as $option) { - $row = []; - $productId = $option['product_id']; - $optionId = $option['option_id']; - $customOptions = isset( - $customOptionsDataPre[$productId][$optionId] - ) ? $customOptionsDataPre[$productId][$optionId] : []; - - if ($defaultStoreId == $storeId) { - $row['_custom_option_type'] = $option['type']; - $row['_custom_option_title'] = $option['title']; - $row['_custom_option_is_required'] = $option['is_require']; - $row['_custom_option_price'] = $option['price'] . ($option['price_type'] == - 'percent' ? '%' : ''); - $row['_custom_option_sku'] = $option['sku']; - $row['_custom_option_max_characters'] = $option['max_characters']; - $row['_custom_option_sort_order'] = $option['sort_order']; - - // remember default title for later comparisons - $defaultTitles[$option['option_id']] = $option['title']; - } else { - $row['_custom_option_title'] = $option['title']; - } - $values = $option->getValues(); - if ($values) { - $firstValue = array_shift($values); - $priceType = $firstValue['price_type'] == 'percent' ? '%' : ''; - - if ($defaultStoreId == $storeId) { - $row['_custom_option_row_title'] = $firstValue['title']; - $row['_custom_option_row_price'] = $firstValue['price'] . $priceType; - $row['_custom_option_row_sku'] = $firstValue['sku']; - $row['_custom_option_row_sort'] = $firstValue['sort_order']; - - $defaultValueTitles[$firstValue['option_type_id']] = $firstValue['title']; - } else { - $row['_custom_option_row_title'] = $firstValue['title']; - } - } - if ($row) { - if ($defaultStoreId != $storeId) { - $row['_custom_option_store'] = $this->_storeIdToCode[$storeId]; + $data['rowWebsites'] = $rowWebsites; + $data['rowCategories'] = $rowCategories; + $data['mediaGalery'] = $this->getMediaGallery($productIds); + $data['rowTierPrices'] = $this->prepareTierPrices($productIds); + $data['rowGroupPrices'] = $this->prepareGroupPrices($productIds); + $data['linksRows'] = $this->prepareLinks($productIds); + + $data['customOptionsData'] = $this->getCustomOptionsData($productIds); + + return $data; + } + + /** + * @param \Magento\Catalog\Model\Product $item + * @param int $storeId + * @return bool + */ + protected function hasMultiselectData($item, $storeId) + { + return !empty($this->collectedMultiselectsData[$storeId][$item->getId()]); + } + + /** + * @param \Magento\Catalog\Model\Product $item + * @param string $attrCode + * @param int $storeId + * @return $this + */ + protected function collectMultiselectValues($item, $attrCode, $storeId) + { + $attrValue = $item->getData($attrCode); + $optionIds = explode(',', $attrValue); + $options = array_intersect_key( + $this->_attributeValues[$attrCode], + array_flip($optionIds) + ); + if (!(isset($this->collectedMultiselectsData[Store::DEFAULT_STORE_ID][$item->getId()][$attrCode]) + && $this->collectedMultiselectsData[Store::DEFAULT_STORE_ID][$item->getId()][$attrCode] == $options) + ) { + $this->collectedMultiselectsData[$storeId][$item->getId()][$attrCode] = $options; + } + + return $this; + } + + /** + * @param string $code + * @param mixed $value + * @return bool + */ + protected function isValidAttributeValue($code, $value) + { + $isValid = true; + if (!is_numeric($value) && empty($value)) { + $isValid = false; + } + + if (!isset($this->_attributeValues[$code])) { + $isValid = false; + } + + return $isValid; + } + + /** + * @param array $dataRow + * @param array $multirawData + * @return array + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + protected function addMultirowData($dataRow, $multirawData) + { + $result = []; + $productId = $dataRow['product_id']; + $storeId = $dataRow['store_id']; + + unset($dataRow['product_id']); + unset($dataRow['store_id']); + + while (true) { + if (Store::DEFAULT_STORE_ID == $storeId) { + unset($dataRow[self::COL_STORE]); + $this->updateDataWithCategoryColumns($dataRow, $multirawData['rowCategories'], $productId); + if (!empty($multirawData['rowWebsites'][$productId])) { + $dataRow['_product_websites'] = $this->_websiteIdToCode[ + array_shift($multirawData['rowWebsites'][$productId]) + ]; + } + if (!empty($multirawData['rowTierPrices'][$productId])) { + $dataRow = array_merge($dataRow, array_shift($multirawData['rowTierPrices'][$productId])); + } + if (!empty($multirawData['rowGroupPrices'][$productId])) { + $dataRow = array_merge($dataRow, array_shift($multirawData['rowGroupPrices'][$productId])); + } + if (!empty($multirawData['mediaGalery'][$productId])) { + $dataRow = array_merge($dataRow, array_shift($multirawData['mediaGalery'][$productId])); + } + foreach ($this->_linkTypeProvider->getLinkTypes() as $linkTypeName => $linkId) { + if (!empty($multirawData['linksRows'][$productId][$linkId])) { + $colPrefix = '_' . $linkTypeName . '_'; + + $linkData = array_shift($multirawData['linksRows'][$productId][$linkId]); + $dataRow[$colPrefix . 'position'] = $linkData['position']; + $dataRow[$colPrefix . 'sku'] = $linkData['sku']; + + if (!is_null($linkData['default_qty'])) { + $dataRow[$colPrefix . 'default_qty'] = $linkData['default_qty']; } - $customOptionsDataPre[$productId][$optionId][] = $row; } - foreach ($values as $value) { - $row = []; - $valuePriceType = $value['price_type'] == 'percent' ? '%' : ''; - - if ($defaultStoreId == $storeId) { - $row['_custom_option_row_title'] = $value['title']; - $row['_custom_option_row_price'] = $value['price'] . $valuePriceType; - $row['_custom_option_row_sku'] = $value['sku']; - $row['_custom_option_row_sort'] = $value['sort_order']; - } else { - $row['_custom_option_row_title'] = $value['title']; - } - if ($row) { - if ($defaultStoreId != $storeId) { - $row['_custom_option_store'] = $this->_storeIdToCode[$storeId]; - } - $customOptionsDataPre[$option['product_id']][$option['option_id']][] = $row; - } + } + $dataRow = $this->rowCustomizer->addData($dataRow, $productId); + + if (!empty($multirawData['customOptionsData'][$productId])) { + $dataRow = array_merge($dataRow, array_shift($multirawData['customOptionsData'][$productId])); + } + } + + if (!empty($this->collectedMultiselectsData[$storeId][$productId])) { + foreach (array_keys($this->collectedMultiselectsData[$storeId][$productId]) as $attrKey) { + if (!empty($this->collectedMultiselectsData[$storeId][$productId][$attrKey])) { + $dataRow[$attrKey] = array_shift( + $this->collectedMultiselectsData[$storeId][$productId][$attrKey] + ); } - $option = null; } - $options = null; } - foreach ($customOptionsDataPre as $productId => &$optionsData) { - $customOptionsData[$productId] = []; - foreach ($optionsData as $optionId => &$optionRows) { - $customOptionsData[$productId] = array_merge($customOptionsData[$productId], $optionRows); + if (empty($dataRow)) { + break; + } elseif ($storeId != Store::DEFAULT_STORE_ID) { + $dataRow[self::COL_STORE] = $this->_storeIdToCode[$storeId]; + $dataRow[self::COL_SKU] = null; + $dataRow[self::COL_ATTR_SET] = null; + $dataRow[self::COL_TYPE] = null; + if (isset($productData[Store::DEFAULT_STORE_ID][self::COL_VISIBILITY])) { + $dataRow[self::COL_VISIBILITY] = $productData[Store::DEFAULT_STORE_ID][self::COL_VISIBILITY]; } - unset($optionRows, $optionsData); } - unset($customOptionsDataPre); - $this->_setHeaderColumns($customOptionsData, $stockItemRows); - $this->_headerColumns = $this->rowCustomizer->addHeaderColumns($this->_headerColumns); + $result[] = $dataRow; + $dataRow = []; + } - foreach ($dataRows as $productId => &$productData) { - foreach ($productData as $storeId => &$dataRow) { - if ($defaultStoreId != $storeId) { - $dataRow[self::COL_SKU] = null; - $dataRow[self::COL_ATTR_SET] = null; - $dataRow[self::COL_TYPE] = null; - if (isset($productData[$defaultStoreId][self::COL_VISIBILITY])) { - $dataRow[self::COL_VISIBILITY] = $productData[$defaultStoreId][self::COL_VISIBILITY]; - } + return $result; + } + + /** + * @param int[] $productIds + * @return array + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + protected function getCustomOptionsData($productIds) + { + $customOptionsData = []; + $customOptionsDataPre = []; + + foreach (array_keys($this->_storeIdToCode) as $storeId) { + $options = $this->_optionColFactory->create()->reset()->addTitleToResult( + $storeId + )->addPriceToResult( + $storeId + )->addProductToFilter( + $productIds + )->addValuesToResult( + $storeId + ); + + foreach ($options as $option) { + $row = []; + $productId = $option['product_id']; + $optionId = $option['option_id']; + + if (Store::DEFAULT_STORE_ID == $storeId) { + $row['_custom_option_type'] = $option['type']; + $row['_custom_option_title'] = $option['title']; + $row['_custom_option_is_required'] = $option['is_require']; + $row['_custom_option_price'] = $option['price'] . ($option['price_type'] == 'percent' ? '%' : ''); + $row['_custom_option_sku'] = $option['sku']; + $row['_custom_option_max_characters'] = $option['max_characters']; + $row['_custom_option_sort_order'] = $option['sort_order']; + } else { + $row['_custom_option_title'] = $option['title']; + } + $values = $option->getValues(); + if ($values) { + $firstValue = array_shift($values); + $priceType = $firstValue['price_type'] == 'percent' ? '%' : ''; + + if (Store::DEFAULT_STORE_ID == $storeId) { + $row['_custom_option_row_title'] = $firstValue['title']; + $row['_custom_option_row_price'] = $firstValue['price'] . $priceType; + $row['_custom_option_row_sku'] = $firstValue['sku']; + $row['_custom_option_row_sort'] = $firstValue['sort_order']; } else { - $dataRow[self::COL_STORE] = null; - if (isset($stockItemRows[$productId])) { - $dataRow = array_merge($dataRow, $stockItemRows[$productId]); - } + $row['_custom_option_row_title'] = $firstValue['title']; } + } - $this->_updateDataWithCategoryColumns($dataRow, $rowCategories, $productId); - if ($rowWebsites[$productId]) { - $dataRow['_product_websites'] = $this->_websiteIdToCode[array_shift($rowWebsites[$productId])]; - } - if (!empty($rowTierPrices[$productId])) { - $dataRow = array_merge($dataRow, array_shift($rowTierPrices[$productId])); - } - if (!empty($rowGroupPrices[$productId])) { - $dataRow = array_merge($dataRow, array_shift($rowGroupPrices[$productId])); - } - if (!empty($mediaGalery[$productId])) { - $dataRow = array_merge($dataRow, array_shift($mediaGalery[$productId])); - } - foreach ($linkIdColPrefix as $linkId => &$colPrefix) { - if (!empty($linksRows[$productId][$linkId])) { - $linkData = array_shift($linksRows[$productId][$linkId]); - $dataRow[$colPrefix . 'position'] = $linkData['position']; - $dataRow[$colPrefix . 'sku'] = $linkData['sku']; - - if (null !== $linkData['default_qty']) { - $dataRow[$colPrefix . 'default_qty'] = $linkData['default_qty']; - } - } - } - if (!empty($customOptionsData[$productId])) { - $dataRow = array_merge($dataRow, array_shift($customOptionsData[$productId])); - } - $dataRow = $this->rowCustomizer->addData($dataRow, $productId); - if (!empty($rowMultiselects[$storeId][$productId])) { - foreach ($rowMultiselects[$storeId][$productId] as $attrKey => $attrVal) { - if (!empty($rowMultiselects[$storeId][$productId][$attrKey])) { - $dataRow[$attrKey] = array_shift($rowMultiselects[$storeId][$productId][$attrKey]); - } - } - } - $exportData[] = $dataRow; + if (Store::DEFAULT_STORE_ID != $storeId) { + $row['_custom_option_store'] = $this->_storeIdToCode[$storeId]; + } + $customOptionsDataPre[$productId][$optionId][] = $row; - // calculate largest links block - $largestLinks = 0; + foreach ($values as $value) { + $row = []; + $valuePriceType = $value['price_type'] == 'percent' ? '%' : ''; - if (isset($linksRows[$productId])) { - $linksRowsKeys = array_keys($linksRows[$productId]); - foreach ($linksRowsKeys as $linksRowsKey) { - $largestLinks = max($largestLinks, count($linksRows[$productId][$linksRowsKey])); - } - } - $additionalRowsCount = max( - count($rowCategories[$productId]), - count($rowWebsites[$productId]), - $largestLinks - ); - if (!empty($rowTierPrices[$productId])) { - $additionalRowsCount = max($additionalRowsCount, count($rowTierPrices[$productId])); - } - if (!empty($rowGroupPrices[$productId])) { - $additionalRowsCount = max($additionalRowsCount, count($rowGroupPrices[$productId])); - } - if (!empty($mediaGalery[$productId])) { - $additionalRowsCount = max($additionalRowsCount, count($mediaGalery[$productId])); - } - if (!empty($customOptionsData[$productId])) { - $additionalRowsCount = max($additionalRowsCount, count($customOptionsData[$productId])); - } - $additionalRowsCount = $this->rowCustomizer - ->getAdditionalRowsCount($additionalRowsCount, $productId); - if (!empty($rowMultiselects[$storeId][$productId])) { - foreach ($rowMultiselects[$storeId][$productId] as $attributes) { - $additionalRowsCount = max($additionalRowsCount, count($attributes)); - } + if (Store::DEFAULT_STORE_ID == $storeId) { + $row['_custom_option_row_title'] = $value['title']; + $row['_custom_option_row_price'] = $value['price'] . $valuePriceType; + $row['_custom_option_row_sku'] = $value['sku']; + $row['_custom_option_row_sort'] = $value['sort_order']; + } else { + $row['_custom_option_row_title'] = $value['title']; } - - if ($additionalRowsCount) { - for ($i = 0; $i < $additionalRowsCount; $i++) { - $dataRow = []; - if ($defaultStoreId != $storeId) { - $dataRow[self::COL_STORE] = $this->_storeIdToCode[$storeId]; - } - $this->_updateDataWithCategoryColumns($dataRow, $rowCategories, $productId); - if ($rowWebsites[$productId]) { - $dataRow['_product_websites'] = $this->_websiteIdToCode[array_shift( - $rowWebsites[$productId] - )]; - } - if (!empty($rowTierPrices[$productId])) { - $dataRow = array_merge($dataRow, array_shift($rowTierPrices[$productId])); - } - if (!empty($rowGroupPrices[$productId])) { - $dataRow = array_merge($dataRow, array_shift($rowGroupPrices[$productId])); - } - if (!empty($mediaGalery[$productId])) { - $dataRow = array_merge($dataRow, array_shift($mediaGalery[$productId])); - } - foreach ($linkIdColPrefix as $linkId => &$colPrefix) { - if (!empty($linksRows[$productId][$linkId])) { - $linkData = array_shift($linksRows[$productId][$linkId]); - $dataRow[$colPrefix . 'position'] = $linkData['position']; - $dataRow[$colPrefix . 'sku'] = $linkData['sku']; - - if (null !== $linkData['default_qty']) { - $dataRow[$colPrefix . 'default_qty'] = $linkData['default_qty']; - } - } - } - if (!empty($customOptionsData[$productId])) { - $dataRow = array_merge($dataRow, array_shift($customOptionsData[$productId])); - } - $dataRow = $this->rowCustomizer->addData($dataRow, $productId); - if (!empty($rowMultiselects[$storeId][$productId])) { - foreach ($rowMultiselects[$storeId][$productId] as $attrKey => $attrVal) { - if (!empty($rowMultiselects[$storeId][$productId][$attrKey])) { - $dataRow[$attrKey] = array_shift( - $rowMultiselects[$storeId][$productId][$attrKey] - ); - } - } - } - $exportData[] = $dataRow; + if ($row) { + if (Store::DEFAULT_STORE_ID != $storeId) { + $row['_custom_option_store'] = $this->_storeIdToCode[$storeId]; } + $customOptionsDataPre[$option['product_id']][$optionId][] = $row; } } + $option = null; } - } catch (\Exception $e) { - $this->_logger->critical($e); + $options = null; } - return $exportData; + + foreach ($customOptionsDataPre as $productId => $optionsData) { + $customOptionsData[$productId] = []; + foreach ($optionsData as $optionId => $optionRows) { + $customOptionsData[$productId] = array_merge( + $customOptionsData[$productId], + $optionRows + ); + } + } + + return $customOptionsData; } /** @@ -1177,7 +1193,7 @@ public function getEntityTypeCode() * * @return $this */ - protected function _initAttributes() + protected function initAttributes() { foreach ($this->getAttributeCollection() as $attribute) { $this->_attributeValues[$attribute->getAttributeCode()] = $this->getAttributeOptions($attribute); diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php index 40abe3cd9757d..072f4cdb74f42 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php @@ -9,6 +9,7 @@ namespace Magento\CatalogImportExport\Model\Import; use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface as ValidatorInterface; /** * Import entity product model @@ -59,63 +60,6 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity const COL_SKU = 'sku'; - /** - * Error codes. - */ - const ERROR_INVALID_SCOPE = 'invalidScope'; - - const ERROR_INVALID_WEBSITE = 'invalidWebsite'; - - const ERROR_INVALID_STORE = 'invalidStore'; - - const ERROR_INVALID_ATTR_SET = 'invalidAttrSet'; - - const ERROR_INVALID_TYPE = 'invalidType'; - - const ERROR_INVALID_CATEGORY = 'invalidCategory'; - - const ERROR_VALUE_IS_REQUIRED = 'isRequired'; - - const ERROR_TYPE_CHANGED = 'typeChanged'; - - const ERROR_SKU_IS_EMPTY = 'skuEmpty'; - - const ERROR_NO_DEFAULT_ROW = 'noDefaultRow'; - - const ERROR_CHANGE_TYPE = 'changeProductType'; - - const ERROR_DUPLICATE_SCOPE = 'duplicateScope'; - - const ERROR_DUPLICATE_SKU = 'duplicateSKU'; - - const ERROR_CHANGE_ATTR_SET = 'changeAttrSet'; - - const ERROR_TYPE_UNSUPPORTED = 'productTypeUnsupported'; - - const ERROR_ROW_IS_ORPHAN = 'rowIsOrphan'; - - const ERROR_INVALID_TIER_PRICE_QTY = 'invalidTierPriceOrQty'; - - const ERROR_INVALID_TIER_PRICE_SITE = 'tierPriceWebsiteInvalid'; - - const ERROR_INVALID_TIER_PRICE_GROUP = 'tierPriceGroupInvalid'; - - const ERROR_TIER_DATA_INCOMPLETE = 'tierPriceDataIsIncomplete'; - - const ERROR_INVALID_GROUP_PRICE_SITE = 'groupPriceWebsiteInvalid'; - - const ERROR_INVALID_GROUP_PRICE_GROUP = 'groupPriceGroupInvalid'; - - const ERROR_GROUP_PRICE_DATA_INCOMPLETE = 'groupPriceDataIsIncomplete'; - - const ERROR_SKU_NOT_FOUND_FOR_DELETE = 'skuNotFoundToDelete'; - - const ERROR_SUPER_PRODUCTS_SKU_NOT_FOUND = 'superProductsSkuNotFound'; - - const ERROR_MEDIA_DATA_INCOMPLETE = 'mediaDataIsIncomplete'; - - const ERROR_INVALID_WEIGHT = 'invalidWeight'; - /** * Pairs of attribute set ID-to-name. * @@ -130,27 +74,6 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity */ protected $_attrSetNameToId = []; - /** - * Categories text-path to ID hash. - * - * @var array - */ - protected $_categories = []; - - /** - * Categories text-path to ID hash with roots checking. - * - * @var array - */ - protected $_categoriesWithRoots = []; - - /** - * Customer groups ID-to-name. - * - * @var array - */ - protected $_customerGroups = []; - /** * Attributes with index (not label) value. * @@ -181,46 +104,32 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity * @var array */ protected $_messageTemplates = [ - self::ERROR_INVALID_SCOPE => '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?)', - self::ERROR_INVALID_ATTR_SET => 'Invalid value for Attribute Set column (set does not exists?)', - self::ERROR_INVALID_TYPE => 'Product Type is invalid or not supported', - self::ERROR_INVALID_CATEGORY => 'Category does not exists', - self::ERROR_VALUE_IS_REQUIRED => "Required attribute '%s' has an empty value", - self::ERROR_TYPE_CHANGED => 'Trying to change type of existing products', - self::ERROR_SKU_IS_EMPTY => 'SKU is empty', - self::ERROR_NO_DEFAULT_ROW => 'Default values row does not exists', - self::ERROR_CHANGE_TYPE => 'Product type change is not allowed', - self::ERROR_DUPLICATE_SCOPE => 'Duplicate scope', - self::ERROR_DUPLICATE_SKU => 'Duplicate SKU', - self::ERROR_CHANGE_ATTR_SET => 'Product attribute set change is not allowed', - self::ERROR_TYPE_UNSUPPORTED => 'Product type is not supported', - self::ERROR_ROW_IS_ORPHAN => 'Orphan rows that will be skipped due default row errors', - self::ERROR_INVALID_TIER_PRICE_QTY => 'Tier Price data price or quantity value is invalid', - self::ERROR_INVALID_TIER_PRICE_SITE => 'Tier Price data website is invalid', - self::ERROR_INVALID_TIER_PRICE_GROUP => 'Tier Price customer group ID is invalid', - self::ERROR_TIER_DATA_INCOMPLETE => 'Tier Price data is incomplete', - self::ERROR_SKU_NOT_FOUND_FOR_DELETE => 'Product with specified SKU not found', - self::ERROR_SUPER_PRODUCTS_SKU_NOT_FOUND => 'Product with specified super products SKU not found', - self::ERROR_MEDIA_DATA_INCOMPLETE => 'Media data is incomplete', - self::ERROR_INVALID_WEIGHT => 'Product weight is invalid', + ValidatorInterface::ERROR_INVALID_SCOPE => 'Invalid value in Scope column', + ValidatorInterface::ERROR_INVALID_WEBSITE => 'Invalid value in Website column (website does not exists?)', + ValidatorInterface::ERROR_INVALID_STORE => 'Invalid value in Store column (store does not exists?)', + ValidatorInterface::ERROR_INVALID_ATTR_SET => 'Invalid value for Attribute Set column (set does not exists?)', + ValidatorInterface::ERROR_INVALID_TYPE => 'Product Type is invalid or not supported', + ValidatorInterface::ERROR_INVALID_CATEGORY => 'Category does not exists', + ValidatorInterface::ERROR_VALUE_IS_REQUIRED => "Required attribute '%s' has an empty value", + ValidatorInterface::ERROR_TYPE_CHANGED => 'Trying to change type of existing products', + ValidatorInterface::ERROR_SKU_IS_EMPTY => 'SKU is empty', + ValidatorInterface::ERROR_NO_DEFAULT_ROW => 'Default values row does not exists', + ValidatorInterface::ERROR_CHANGE_TYPE => 'Product type change is not allowed', + ValidatorInterface::ERROR_DUPLICATE_SCOPE => 'Duplicate scope', + ValidatorInterface::ERROR_DUPLICATE_SKU => 'Duplicate SKU', + ValidatorInterface::ERROR_CHANGE_ATTR_SET => 'Product attribute set change is not allowed', + ValidatorInterface::ERROR_TYPE_UNSUPPORTED => 'Product type is not supported', + ValidatorInterface::ERROR_ROW_IS_ORPHAN => 'Orphan rows that will be skipped due default row errors', + ValidatorInterface::ERROR_INVALID_TIER_PRICE_QTY => 'Tier Price data price or quantity value is invalid', + ValidatorInterface::ERROR_INVALID_TIER_PRICE_SITE => 'Tier Price data website is invalid', + ValidatorInterface::ERROR_INVALID_TIER_PRICE_GROUP => 'Tier Price customer group ID is invalid', + ValidatorInterface::ERROR_TIER_DATA_INCOMPLETE => 'Tier Price data is incomplete', + ValidatorInterface::ERROR_SKU_NOT_FOUND_FOR_DELETE => 'Product with specified SKU not found', + ValidatorInterface::ERROR_SUPER_PRODUCTS_SKU_NOT_FOUND => 'Product with specified super products SKU not found', + ValidatorInterface::ERROR_MEDIA_DATA_INCOMPLETE => 'Media data is incomplete', + ValidatorInterface::ERROR_INVALID_WEIGHT => 'Product weight is invalid', ]; - /** - * Dry-runned products information from import file. - * - * [SKU] => array( - * 'type_id' => (string) product type - * 'attr_set_id' => (int) product attribute set ID - * 'entity_id' => (int) product ID (value for new products will be set after entity save) - * 'attr_set_code' => (string) attribute set code - * ) - * - * @var array - */ - protected $_newSku = []; - /** * Existing products SKU-related information in form of array: * @@ -331,34 +240,6 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity */ protected $_productTypeModels = []; - /** - * All stores code-ID pairs. - * - * @var array - */ - protected $_storeCodeToId = []; - - /** - * Store ID to its website stores IDs. - * - * @var array - */ - protected $_storeIdToWebsiteStoreIds = []; - - /** - * Website code-to-ID - * - * @var array - */ - protected $_websiteCodeToId = []; - - /** - * Website code to store code-to-ID pairs which it consists. - * - * @var array - */ - protected $_websiteCodeToStoreIds = []; - /** * Media files uploader * @@ -417,31 +298,6 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity */ protected $_setColFactory; - /** - * @var \Magento\Catalog\Model\Resource\Category\CollectionFactory - */ - protected $_categoryColFactory; - - /** - * @var \Magento\Customer\Api\GroupRepositoryInterface - */ - protected $groupRepository; - - /** - * @var \Magento\Framework\Api\SearchCriteriaBuilder - */ - protected $searchCriteriaBuilder; - - /** - * @var \Magento\Catalog\Model\ProductFactory - */ - protected $_productFactory; - - /** - * @var \Magento\Store\Model\StoreManagerInterface - */ - protected $_storeManager; - /** * @var \Magento\CatalogImportExport\Model\Import\Product\Type\Factory */ @@ -487,6 +343,26 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity */ protected $indexerRegistry; + /** + * @var Product\StoreResolver + */ + protected $storeResolver; + + /** + * @var Product\SkuProcessor + */ + protected $skuProcessor; + + /** + * @var Product\CategoryProcessor + */ + protected $categoryProcessor; + + /** + * @var Product\Validator + */ + protected $validator; + /** * @var \Psr\Log\LoggerInterface */ @@ -514,11 +390,6 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity * @param Proxy\Product\ResourceFactory $resourceFactory * @param Product\OptionFactory $optionFactory * @param \Magento\Eav\Model\Resource\Entity\Attribute\Set\CollectionFactory $setColFactory - * @param \Magento\Catalog\Model\Resource\Category\CollectionFactory $categoryColFactory - * @param \Magento\Customer\Api\GroupRepositoryInterface $groupRepository - * @param \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder - * @param \Magento\Catalog\Model\ProductFactory $productFactory - * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param Product\Type\Factory $productTypeFactory * @param \Magento\Catalog\Model\Resource\Product\LinkFactory $linkFactory * @param Proxy\ProductFactory $proxyProdFactory @@ -529,6 +400,10 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity * @param \Magento\Framework\Stdlib\DateTime $dateTime * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Indexer\Model\IndexerRegistry $indexerRegistry + * @param Product\StoreResolver $storeResolver + * @param Product\SkuProcessor $skuProcessor + * @param Product\CategoryProcessor $categoryProcessor + * @param Product\Validator $validator * @param array $data * @throws \Magento\Framework\Model\Exception * @SuppressWarnings(PHPMD.ExcessiveParameterList) @@ -550,11 +425,6 @@ public function __construct( \Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceFactory $resourceFactory, \Magento\CatalogImportExport\Model\Import\Product\OptionFactory $optionFactory, \Magento\Eav\Model\Resource\Entity\Attribute\Set\CollectionFactory $setColFactory, - \Magento\Catalog\Model\Resource\Category\CollectionFactory $categoryColFactory, - \Magento\Customer\Api\GroupRepositoryInterface $groupRepository, - \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder, - \Magento\Catalog\Model\ProductFactory $productFactory, - \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\CatalogImportExport\Model\Import\Product\Type\Factory $productTypeFactory, \Magento\Catalog\Model\Resource\Product\LinkFactory $linkFactory, \Magento\CatalogImportExport\Model\Import\Proxy\ProductFactory $proxyProdFactory, @@ -565,6 +435,10 @@ public function __construct( \Magento\Framework\Stdlib\DateTime $dateTime, \Psr\Log\LoggerInterface $logger, \Magento\Indexer\Model\IndexerRegistry $indexerRegistry, + Product\StoreResolver $storeResolver, + Product\SkuProcessor $skuProcessor, + Product\CategoryProcessor $categoryProcessor, + Product\Validator $validator, array $data = [] ) { $this->_eventManager = $eventManager; @@ -575,11 +449,6 @@ public function __construct( $this->_importConfig = $importConfig; $this->_resourceFactory = $resourceFactory; $this->_setColFactory = $setColFactory; - $this->_categoryColFactory = $categoryColFactory; - $this->groupRepository = $groupRepository; - $this->searchCriteriaBuilder = $searchCriteriaBuilder; - $this->_productFactory = $productFactory; - $this->_storeManager = $storeManager; $this->_productTypeFactory = $productTypeFactory; $this->_linkFactory = $linkFactory; $this->_proxyProdFactory = $proxyProdFactory; @@ -590,6 +459,10 @@ public function __construct( $this->dateTime = $dateTime; $this->indexerRegistry = $indexerRegistry; $this->_logger = $logger; + $this->storeResolver = $storeResolver; + $this->skuProcessor = $skuProcessor; + $this->categoryProcessor = $categoryProcessor; + $this->validator = $validator; parent::__construct($coreData, $importExportData, $importData, $config, $resource, $resourceHelper, $string); $this->_optionEntity = isset( $data['option_entity'] @@ -597,13 +470,10 @@ public function __construct( ['data' => ['product_entity' => $this]] ); - $this->_initWebsites() - ->_initStores() - ->_initAttributeSets() + $this->_initAttributeSets() ->_initTypeModels() - ->_initCategories() - ->_initSkus() - ->_initCustomerGroups(); + ->_initSkus(); + $this->validator->init(); } /** @@ -696,50 +566,6 @@ protected function _initAttributeSets() return $this; } - /** - * Initialize categories text-path to ID hash. - * - * @return $this - */ - protected function _initCategories() - { - $collection = $this->_categoryColFactory->create()->addNameToResult(); - /* @var $collection \Magento\Catalog\Model\Resource\Category\Collection */ - foreach ($collection as $category) { - $structure = explode('/', $category->getPath()); - $pathSize = count($structure); - if ($pathSize > 1) { - $path = []; - for ($i = 1; $i < $pathSize; $i++) { - $path[] = $collection->getItemById($structure[$i])->getName(); - } - $rootCategoryName = array_shift($path); - if (!isset($this->_categoriesWithRoots[$rootCategoryName])) { - $this->_categoriesWithRoots[$rootCategoryName] = []; - } - $index = implode('/', $path); - $this->_categoriesWithRoots[$rootCategoryName][$index] = $category->getId(); - if ($pathSize > 2) { - $this->_categories[$index] = $category->getId(); - } - } - } - return $this; - } - - /** - * Initialize customer groups. - * - * @return $this - */ - protected function _initCustomerGroups() - { - foreach ($this->groupRepository->getList($this->searchCriteriaBuilder->create())->getItems() as $group) { - $this->_customerGroups[$group->getId()] = true; - } - return $this; - } - /** * Initialize existent product SKUs. * @@ -747,31 +573,8 @@ protected function _initCustomerGroups() */ protected function _initSkus() { - $columns = ['entity_id', 'type_id', 'attribute_set_id', 'sku']; - foreach ($this->_productFactory->create()->getProductEntitiesInfo($columns) as $info) { - $typeId = $info['type_id']; - $sku = $info['sku']; - $this->_oldSku[$sku] = [ - 'type_id' => $typeId, - 'attr_set_id' => $info['attribute_set_id'], - 'entity_id' => $info['entity_id'], - 'supported_type' => isset($this->_productTypeModels[$typeId]), - ]; - } - return $this; - } - - /** - * Initialize stores hash. - * - * @return $this - */ - protected function _initStores() - { - foreach ($this->_storeManager->getStores() as $store) { - $this->_storeCodeToId[$store->getCode()] = $store->getId(); - $this->_storeIdToWebsiteStoreIds[$store->getId()] = $store->getWebsite()->getStoreIds(); - } + $this->skuProcessor->setTypeModels($this->_productTypeModels); + $this->_oldSku = $this->skuProcessor->getOldSkus(); return $this; } @@ -811,64 +614,6 @@ protected function _initTypeModels() return $this; } - /** - * Initialize website values. - * - * @return $this - */ - protected function _initWebsites() - { - /** @var $website \Magento\Store\Model\Website */ - foreach ($this->_storeManager->getWebsites() as $website) { - $this->_websiteCodeToId[$website->getCode()] = $website->getId(); - $this->_websiteCodeToStoreIds[$website->getCode()] = array_flip($website->getStoreCodes()); - } - return $this; - } - - /** - * Check product category validity. - * - * @param array $rowData - * @param int $rowNum - * @return bool - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - */ - protected function _isProductCategoryValid(array $rowData, $rowNum) - { - $emptyCategory = empty($rowData[self::COL_CATEGORY]); - $emptyRootCategory = empty($rowData[self::COL_ROOT_CATEGORY]); - $hasCategory = $emptyCategory ? false : isset($this->_categories[$rowData[self::COL_CATEGORY]]); - $category = $emptyRootCategory ? null : $this->_categoriesWithRoots[$rowData[self::COL_ROOT_CATEGORY]]; - if (!$emptyCategory && !$hasCategory || !$emptyRootCategory && !isset( - $category - ) || !$emptyRootCategory && !$emptyCategory && !isset( - $category[$rowData[self::COL_CATEGORY]] - ) - ) { - $this->addRowError(self::ERROR_INVALID_CATEGORY, $rowNum); - return false; - } - return true; - } - - /** - * Check product website belonging. - * - * @param array $rowData - * @param int $rowNum - * @return bool - */ - protected function _isProductWebsiteValid(array $rowData, $rowNum) - { - if (!empty($rowData['_product_websites']) && !isset($this->_websiteCodeToId[$rowData['_product_websites']])) { - $this->addRowError(self::ERROR_INVALID_WEBSITE, $rowNum); - return false; - } - return true; - } - /** * Set valid attribute set and product type to rows with all scopes * to ensure that existing products doesn't changed. @@ -889,173 +634,14 @@ protected function _prepareRowForDb(array $rowData) $lastSku = $rowData[self::COL_SKU]; } if (isset($this->_oldSku[$lastSku])) { - $rowData[self::COL_ATTR_SET] = $this->_newSku[$lastSku]['attr_set_code']; - $rowData[self::COL_TYPE] = $this->_newSku[$lastSku]['type_id']; + $newSku = $this->skuProcessor->getNewSku($lastSku); + $rowData[self::COL_ATTR_SET] = $newSku['attr_set_code']; + $rowData[self::COL_TYPE] = $newSku['type_id']; } return $rowData; } - /** - * Check tier price data validity. - * - * @param array $rowData - * @param int $rowNum - * @return bool - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - */ - protected function _isTierPriceValid(array $rowData, $rowNum) - { - if (isset( - $rowData['_tier_price_website'] - ) && strlen( - $rowData['_tier_price_website'] - ) || isset( - $rowData['_tier_price_customer_group'] - ) && strlen( - $rowData['_tier_price_customer_group'] - ) || isset( - $rowData['_tier_price_qty'] - ) && strlen( - $rowData['_tier_price_qty'] - ) || isset( - $rowData['_tier_price_price'] - ) && strlen( - $rowData['_tier_price_price'] - ) - ) { - if (!isset( - $rowData['_tier_price_website'] - ) || !isset( - $rowData['_tier_price_customer_group'] - ) || !isset( - $rowData['_tier_price_qty'] - ) || !isset( - $rowData['_tier_price_price'] - ) || !strlen( - $rowData['_tier_price_website'] - ) || !strlen( - $rowData['_tier_price_customer_group'] - ) || !strlen( - $rowData['_tier_price_qty'] - ) || !strlen( - $rowData['_tier_price_price'] - ) - ) { - $this->addRowError(self::ERROR_TIER_DATA_INCOMPLETE, $rowNum); - return false; - } elseif ($rowData['_tier_price_website'] != self::VALUE_ALL && !isset( - $this->_websiteCodeToId[$rowData['_tier_price_website']] - ) - ) { - $this->addRowError(self::ERROR_INVALID_TIER_PRICE_SITE, $rowNum); - return false; - } elseif ($rowData['_tier_price_customer_group'] != self::VALUE_ALL && !isset( - $this->_customerGroups[$rowData['_tier_price_customer_group']] - ) - ) { - $this->addRowError(self::ERROR_INVALID_TIER_PRICE_GROUP, $rowNum); - return false; - } elseif ($rowData['_tier_price_qty'] <= 0 || $rowData['_tier_price_price'] <= 0) { - $this->addRowError(self::ERROR_INVALID_TIER_PRICE_QTY, $rowNum); - return false; - } - } - return true; - } - - /** - * Check group price data validity. - * - * @param array $rowData - * @param int $rowNum - * @return bool - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - */ - protected function _isGroupPriceValid(array $rowData, $rowNum) - { - if (isset( - $rowData['_group_price_website'] - ) && strlen( - $rowData['_group_price_website'] - ) || isset( - $rowData['_group_price_customer_group'] - ) && strlen( - $rowData['_group_price_customer_group'] - ) || isset( - $rowData['_group_price_price'] - ) && strlen( - $rowData['_group_price_price'] - ) - ) { - if (!isset( - $rowData['_group_price_website'] - ) || !isset( - $rowData['_group_price_customer_group'] - ) || !strlen( - $rowData['_group_price_website'] - ) || !strlen( - $rowData['_group_price_customer_group'] - ) || !strlen( - $rowData['_group_price_price'] - ) - ) { - $this->addRowError(self::ERROR_GROUP_PRICE_DATA_INCOMPLETE, $rowNum); - return false; - } elseif ($rowData['_group_price_website'] != self::VALUE_ALL && !isset( - $this->_websiteCodeToId[$rowData['_group_price_website']] - ) - ) { - $this->addRowError(self::ERROR_INVALID_GROUP_PRICE_SITE, $rowNum); - return false; - } elseif ($rowData['_group_price_customer_group'] != self::VALUE_ALL && !isset( - $this->_customerGroups[$rowData['_group_price_customer_group']] - ) - ) { - $this->addRowError(self::ERROR_INVALID_GROUP_PRICE_GROUP, $rowNum); - return false; - } - } - return true; - } - - /** - * Check media information - * - * @param array $rowData - * @param int $rowNum - * @return bool - */ - protected function _isMediaValid($rowData, $rowNum) - { - if (!empty($rowData['_media_image']) && empty($rowData['_media_attribute_id'])) { - $this->addRowError(self::ERROR_MEDIA_DATA_INCOMPLETE, $rowNum); - return false; - } - return true; - } - - /** - * Check super products SKU - * - * @param array $rowData - * @param int $rowNum - * @return bool - */ - protected function _isSuperProductsSkuValid($rowData, $rowNum) - { - if (!empty($rowData['_super_products_sku']) && (!isset( - $this->_oldSku[$rowData['_super_products_sku']] - ) && !isset( - $this->_newSku[$rowData['_super_products_sku']] - )) - ) { - $this->addRowError(self::ERROR_SUPER_PRODUCTS_SKU_NOT_FOUND, $rowNum); - return false; - } - return true; - } - /** * Gather and save information about product links. * Must be called after ALL products saving done. @@ -1097,19 +683,20 @@ protected function _saveLinks() $sku = $rowData[self::COL_SKU]; } foreach ($this->_linkNameToId as $linkName => $linkId) { - $productId = $this->_newSku[$sku]['entity_id']; + $productId = $this->skuProcessor->getNewSku($sku)['entity_id']; $productIds[] = $productId; if (isset($rowData[$linkName . 'sku'])) { $linkedSku = $rowData[$linkName . 'sku']; - if ((isset( - $this->_newSku[$linkedSku] + if ((!is_null( + $this->skuProcessor->getNewSku($linkedSku) ) || isset( $this->_oldSku[$linkedSku] )) && $linkedSku != $sku ) { - if (isset($this->_newSku[$linkedSku])) { - $linkedId = $this->_newSku[$linkedSku]['entity_id']; + $newSku = $this->skuProcessor->getNewSku($linkedSku); + if (!empty($newSku)) { + $linkedId = $newSku['entity_id']; } else { $linkedId = $this->_oldSku[$linkedSku]['entity_id']; } @@ -1180,7 +767,7 @@ protected function _saveProductAttributes(array $attributesData) $tableData = []; foreach ($skuData as $sku => $attributes) { - $productId = $this->_newSku[$sku]['entity_id']; + $productId = $this->skuProcessor->getNewSku($sku)['entity_id']; foreach ($attributes as $attributeId => $storeValues) { foreach ($storeValues as $storeId => $storeValue) { @@ -1232,7 +819,7 @@ protected function _saveProductCategories(array $categoriesData) $delProductId = []; foreach ($categoriesData as $delSku => $categories) { - $productId = $this->_newSku[$delSku]['entity_id']; + $productId = $this->skuProcessor->getNewSku($delSku)['entity_id']; $delProductId[] = $productId; foreach (array_keys($categories) as $categoryId) { @@ -1283,7 +870,7 @@ protected function _saveProductEntity(array $entityRowsIn, array $entityRowsUp) ); foreach ($newProducts as $sku => $newId) { // fill up entity_id for new products - $this->_newSku[$sku]['entity_id'] = $newId; + $this->skuProcessor->setNewSkuData($sku, 'entity_id', $newId); } } return $this; @@ -1338,8 +925,8 @@ protected function _saveProducts() // new row if (!$productLimit || $productsQty < $productLimit) { $entityRowsIn[$rowSku] = [ - 'attribute_set_id' => $this->_newSku[$rowSku]['attr_set_id'], - 'type_id' => $this->_newSku[$rowSku]['type_id'], + 'attribute_set_id' => $this->skuProcessor->getNewSku($rowSku)['attr_set_id'], + 'type_id' => $this->skuProcessor->getNewSku($rowSku)['type_id'], 'sku' => $rowSku, 'has_options' => isset($rowData['has_options']) ? $rowData['has_options'] : 0, 'created_at' => $this->dateTime->now(), @@ -1359,23 +946,26 @@ protected function _saveProducts() continue; } elseif (self::SCOPE_STORE == $rowScope) { // set necessary data from SCOPE_DEFAULT row - $rowData[self::COL_TYPE] = $this->_newSku[$rowSku]['type_id']; - $rowData['attribute_set_id'] = $this->_newSku[$rowSku]['attr_set_id']; - $rowData[self::COL_ATTR_SET] = $this->_newSku[$rowSku]['attr_set_code']; + $rowData[self::COL_TYPE] = $this->skuProcessor->getNewSku($rowSku)['type_id']; + $rowData['attribute_set_id'] = $this->skuProcessor->getNewSku($rowSku)['attr_set_id']; + $rowData[self::COL_ATTR_SET] = $this->skuProcessor->getNewSku($rowSku)['attr_set_code']; } // 2. Product-to-Website phase if (!empty($rowData['_product_websites'])) { - $websites[$rowSku][$this->_websiteCodeToId[$rowData['_product_websites']]] = true; + $websites[$rowSku][$this->storeResolver->getWebsiteCodeToId($rowData['_product_websites'])] = true; } // 3. Categories phase $categoryPath = empty($rowData[self::COL_CATEGORY]) ? '' : $rowData[self::COL_CATEGORY]; if (!empty($rowData[self::COL_ROOT_CATEGORY])) { - $categoryId = $this->_categoriesWithRoots[$rowData[self::COL_ROOT_CATEGORY]][$categoryPath]; + $categoryId = $this->categoryProcessor->getCategoryWithRoot( + $rowData[self::COL_ROOT_CATEGORY], + $categoryPath + ); $categories[$rowSku][$categoryId] = true; } elseif (!empty($categoryPath)) { - $categories[$rowSku][$this->_categories[$categoryPath]] = true; + $categories[$rowSku][$this->categoryProcessor->getCategory($categoryPath)] = true; } // 4.1. Tier prices phase @@ -1387,7 +977,7 @@ protected function _saveProducts() 'qty' => $rowData['_tier_price_qty'], 'value' => $rowData['_tier_price_price'], 'website_id' => self::VALUE_ALL == $rowData['_tier_price_website'] || - $priceIsGlobal ? 0 : $this->_websiteCodeToId[$rowData['_tier_price_website']], + $priceIsGlobal ? 0 : $this->storeResolver->getWebsiteCodeToId($rowData['_tier_price_website']), ]; } @@ -1399,7 +989,7 @@ protected function _saveProducts() self::VALUE_ALL ? 0 : $rowData['_group_price_customer_group'], 'value' => $rowData['_group_price_price'], 'website_id' => self::VALUE_ALL == $rowData['_group_price_website'] || - $priceIsGlobal ? 0 : $this->_websiteCodeToId[$rowData['_group_price_website']], + $priceIsGlobal ? 0 : $this->storeResolver->getWebsiteCodeToId($rowData['_group_price_website']), ]; } @@ -1423,7 +1013,9 @@ protected function _saveProducts() } // 6. Attributes phase - $rowStore = self::SCOPE_STORE == $rowScope ? $this->_storeCodeToId[$rowData[self::COL_STORE]] : 0; + $rowStore = (self::SCOPE_STORE == $rowScope) + ? $this->storeResolver->getStoreCodeToId($rowData[self::COL_STORE]) + : 0; $productType = isset($rowData[self::COL_TYPE]) ? $rowData[self::COL_TYPE] : null; if (!is_null($productType)) { $previousType = $productType; @@ -1478,7 +1070,7 @@ protected function _saveProducts() if (self::SCOPE_WEBSITE == $attribute->getIsGlobal()) { // check website defaults already set if (!isset($attributes[$attrTable][$rowSku][$attrId][$rowStore])) { - $storeIds = $this->_storeIdToWebsiteStoreIds[$rowStore]; + $storeIds = $this->storeResolver->getStoreIdToWebsiteStoreIds($rowStore); } } elseif (self::SCOPE_STORE == $attribute->getIsGlobal()) { $storeIds = [$rowStore]; @@ -1539,7 +1131,7 @@ protected function _saveProductTierPrices(array $tierPriceData) $delProductId = []; foreach ($tierPriceData as $delSku => $tierPriceRows) { - $productId = $this->_newSku[$delSku]['entity_id']; + $productId = $this->skuProcessor->getNewSku($delSku)['entity_id']; $delProductId[] = $productId; foreach ($tierPriceRows as $row) { @@ -1578,7 +1170,7 @@ protected function _saveProductGroupPrices(array $groupPriceData) $delProductId = []; foreach ($groupPriceData as $delSku => $groupPriceRows) { - $productId = $this->_newSku[$delSku]['entity_id']; + $productId = $this->skuProcessor->getNewSku($delSku)['entity_id']; $delProductId[] = $productId; foreach ($groupPriceRows as $row) { @@ -1621,7 +1213,9 @@ protected function _getUploader() $this->_mediaDirectory->create($destinationDir); if (!$this->_fileUploader->setDestDir($destinationPath)) { - throw new \Magento\Framework\Model\Exception(sprintf("File directory '%s' is not writable.", $destinationPath)); + throw new \Magento\Framework\Model\Exception( + sprintf("File directory '%s' is not writable.", $destinationPath) + ); } } return $this->_fileUploader; @@ -1674,7 +1268,7 @@ protected function _saveMediaGallery(array $mediaGalleryData) } foreach ($mediaGalleryData as $productSku => $mediaGalleryRows) { - $productId = $this->_newSku[$productSku]['entity_id']; + $productId = $this->skuProcessor->getNewSku($productSku)['entity_id']; $insertedGalleryImgs = []; if (\Magento\ImportExport\Model\Import::BEHAVIOR_APPEND != $this->getBehavior()) { @@ -1752,7 +1346,7 @@ protected function _saveProductWebsites(array $websiteData) $delProductId = []; foreach ($websiteData as $delSku => $websites) { - $productId = $this->_newSku[$delSku]['entity_id']; + $productId = $this->skuProcessor->getNewSku($delSku)['entity_id']; $delProductId[] = $productId; foreach (array_keys($websites) as $websiteId) { @@ -1797,7 +1391,7 @@ protected function _saveStockItem() } $row = []; - $row['product_id'] = $this->_newSku[$rowData[self::COL_SKU]]['entity_id']; + $row['product_id'] = $this->skuProcessor->getNewSku($rowData[self::COL_SKU])['entity_id']; $productIdsToReindex[] = $row['product_id']; $row['website_id'] = $this->stockConfiguration->getDefaultWebsiteId(); @@ -1813,7 +1407,9 @@ protected function _saveStockItem() $row ); - if ($this->stockConfiguration->isQty($this->_newSku[$rowData[self::COL_SKU]]['type_id'])) { + if ($this->stockConfiguration->isQty( + $this->skuProcessor->getNewSku($rowData[self::COL_SKU])['type_id'] + )) { $stockItemDo->setData($row); $row['is_in_stock'] = $this->stockStateProvider->verifyStock($stockItemDo); if ($this->stockStateProvider->verifyNotification($stockItemDo)) { @@ -1878,7 +1474,7 @@ public function getEntityTypeCode() */ public function getNewSku() { - return $this->_newSku; + return $this->skuProcessor->getNewSku(); } /** @@ -1918,16 +1514,6 @@ public function getRowScope(array $rowData) return self::SCOPE_STORE; } - /** - * All website codes to ID getter. - * - * @return array - */ - public function getWebsiteCodes() - { - return $this->_websiteCodeToId; - } - /** * Validate data row. * @@ -1940,17 +1526,16 @@ public function getWebsiteCodes() */ public function validateRow(array $rowData, $rowNum) { - static $sku = null; // SKU is remembered through all product rows - + static $sku = null; if (isset($this->_validatedRows[$rowNum])) { // check that row is already validated return !isset($this->_invalidRows[$rowNum]); } $this->_validatedRows[$rowNum] = true; - if (isset($this->_newSku[$rowData[self::COL_SKU]])) { - $this->addRowError(self::ERROR_DUPLICATE_SKU, $rowNum); + if (!is_null($this->skuProcessor->getNewSku($rowData[self::COL_SKU]))) { + $this->addRowError(ValidatorInterface::ERROR_DUPLICATE_SKU, $rowNum); return false; } $rowScope = $this->getRowScope($rowData); @@ -1958,19 +1543,17 @@ public function validateRow(array $rowData, $rowNum) // BEHAVIOR_DELETE use specific validation logic if (\Magento\ImportExport\Model\Import::BEHAVIOR_DELETE == $this->getBehavior()) { if (self::SCOPE_DEFAULT == $rowScope && !isset($this->_oldSku[$rowData[self::COL_SKU]])) { - $this->addRowError(self::ERROR_SKU_NOT_FOUND_FOR_DELETE, $rowNum); + $this->addRowError(ValidatorInterface::ERROR_SKU_NOT_FOUND_FOR_DELETE, $rowNum); return false; } return true; } - // common validation - $this->_isProductWebsiteValid($rowData, $rowNum); - $this->_isProductCategoryValid($rowData, $rowNum); - $this->_isTierPriceValid($rowData, $rowNum); - $this->_isGroupPriceValid($rowData, $rowNum); - $this->_isSuperProductsSkuValid($rowData, $rowNum); - $this->_isMediaValid($rowData, $rowNum); - $this->isWeightValid($rowData, $rowNum); + + if (!$this->validator->isValid($rowData)) { + foreach ($this->validator->getMessages() as $message) { + $this->addRowError($message, $rowNum); + } + } if (self::SCOPE_DEFAULT == $rowScope) { // SKU is specified, row is SCOPE_DEFAULT, new product block begins @@ -1982,35 +1565,41 @@ public function validateRow(array $rowData, $rowNum) // can we get all necessary data from existent DB product? // check for supported type of existing product if (isset($this->_productTypeModels[$this->_oldSku[$sku]['type_id']])) { - $this->_newSku[$sku] = [ - 'entity_id' => $this->_oldSku[$sku]['entity_id'], - 'type_id' => $this->_oldSku[$sku]['type_id'], - 'attr_set_id' => $this->_oldSku[$sku]['attr_set_id'], - 'attr_set_code' => $this->_attrSetIdToName[$this->_oldSku[$sku]['attr_set_id']], - ]; + $this->skuProcessor->addNewSku( + $sku, + [ + 'entity_id' => $this->_oldSku[$sku]['entity_id'], + 'type_id' => $this->_oldSku[$sku]['type_id'], + 'attr_set_id' => $this->_oldSku[$sku]['attr_set_id'], + 'attr_set_code' => $this->_attrSetIdToName[$this->_oldSku[$sku]['attr_set_id']], + ] + ); } else { - $this->addRowError(self::ERROR_TYPE_UNSUPPORTED, $rowNum); + $this->addRowError(ValidatorInterface::ERROR_TYPE_UNSUPPORTED, $rowNum); // child rows of legacy products with unsupported types are orphans $sku = false; } } else { // validate new product type and attribute set if (!isset($rowData[self::COL_TYPE]) || !isset($this->_productTypeModels[$rowData[self::COL_TYPE]])) { - $this->addRowError(self::ERROR_INVALID_TYPE, $rowNum); + $this->addRowError(ValidatorInterface::ERROR_INVALID_TYPE, $rowNum); } elseif (!isset( $rowData[self::COL_ATTR_SET] ) || !isset( $this->_attrSetNameToId[$rowData[self::COL_ATTR_SET]] ) ) { - $this->addRowError(self::ERROR_INVALID_ATTR_SET, $rowNum); - } elseif (!isset($this->_newSku[$sku])) { - $this->_newSku[$sku] = [ - 'entity_id' => null, - 'type_id' => $rowData[self::COL_TYPE], - 'attr_set_id' => $this->_attrSetNameToId[$rowData[self::COL_ATTR_SET]], - 'attr_set_code' => $rowData[self::COL_ATTR_SET], - ]; + $this->addRowError(ValidatorInterface::ERROR_INVALID_ATTR_SET, $rowNum); + } elseif (is_null($this->skuProcessor->getNewSku($sku))) { + $this->skuProcessor->addNewSku( + $sku, + [ + 'entity_id' => null, + 'type_id' => $rowData[self::COL_TYPE], + 'attr_set_id' => $this->_attrSetNameToId[$rowData[self::COL_ATTR_SET]], + 'attr_set_code' => $rowData[self::COL_ATTR_SET], + ] + ); } if (isset($this->_invalidRows[$rowNum])) { // mark SCOPE_DEFAULT row as invalid for future child rows if product not in DB already @@ -2019,18 +1608,21 @@ public function validateRow(array $rowData, $rowNum) } } else { if (null === $sku) { - $this->addRowError(self::ERROR_SKU_IS_EMPTY, $rowNum); + $this->addRowError(ValidatorInterface::ERROR_SKU_IS_EMPTY, $rowNum); } elseif (false === $sku) { - $this->addRowError(self::ERROR_ROW_IS_ORPHAN, $rowNum); - } elseif (self::SCOPE_STORE == $rowScope && !isset($this->_storeCodeToId[$rowData[self::COL_STORE]])) { - $this->addRowError(self::ERROR_INVALID_STORE, $rowNum); + $this->addRowError(ValidatorInterface::ERROR_ROW_IS_ORPHAN, $rowNum); + } elseif (self::SCOPE_STORE == $rowScope + && !$this->storeResolver->getStoreCodeToId($rowData[self::COL_STORE]) + ) { + $this->addRowError(ValidatorInterface::ERROR_INVALID_STORE, $rowNum); } } if (!isset($this->_invalidRows[$rowNum])) { + $newSku = $this->skuProcessor->getNewSku($sku); // set attribute set code into row data for followed attribute validation in type model - $rowData[self::COL_ATTR_SET] = $this->_newSku[$sku]['attr_set_code']; + $rowData[self::COL_ATTR_SET] = $newSku['attr_set_code']; - $rowAttributesValid = $this->_productTypeModels[$this->_newSku[$sku]['type_id']]->isRowValid( + $rowAttributesValid = $this->_productTypeModels[$newSku['type_id']]->isRowValid( $rowData, $rowNum, !isset($this->_oldSku[$sku]) @@ -2081,28 +1673,13 @@ public function getAffectedEntityIds() if (!$this->isRowAllowedToImport($rowData, $rowNum)) { continue; } - if (!isset($this->_newSku[$rowData[self::COL_SKU]]['entity_id'])) { + $newSku = $this->skuProcessor->getNewSku($rowData[self::COL_SKU]); + if (empty($newSku) || !isset($newSku['entity_id'])) { continue; } - $productIds[] = $this->_newSku[$rowData[self::COL_SKU]]['entity_id']; + $productIds[] = $newSku['entity_id']; } } return $productIds; } - - /** - * Check weight data - * - * @param array $rowData - * @param int $rowNum - * @return bool - */ - protected function isWeightValid($rowData, $rowNum) - { - if (!empty($rowData['weight']) && (!is_numeric($rowData['weight']) || $rowData['weight'] < 0)) { - $this->addRowError(self::ERROR_INVALID_WEIGHT, $rowNum); - return false; - } - return true; - } } diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/CategoryProcessor.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/CategoryProcessor.php new file mode 100644 index 0000000000000..45de826f9f543 --- /dev/null +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/CategoryProcessor.php @@ -0,0 +1,93 @@ +categoryColFactory = $categoryColFactory; + } + + /** + * @return $this + */ + protected function initCategories() + { + if (empty($this->categories) && empty($this->categoriesWithRoots)) { + $collection = $this->categoryColFactory->create()->addNameToResult(); + /* @var $collection \Magento\Catalog\Model\Resource\Category\Collection */ + foreach ($collection as $category) { + $structure = explode('/', $category->getPath()); + $pathSize = count($structure); + if ($pathSize > 1) { + $path = []; + for ($i = 1; $i < $pathSize; $i++) { + $path[] = $collection->getItemById($structure[$i])->getName(); + } + $rootCategoryName = array_shift($path); + if (!isset($this->categoriesWithRoots[$rootCategoryName])) { + $this->categoriesWithRoots[$rootCategoryName] = []; + } + $index = implode('/', $path); + $this->categoriesWithRoots[$rootCategoryName][$index] = $category->getId(); + if ($pathSize > 2) { + $this->categories[$index] = $category->getId(); + } + } + } + } + return $this; + } + + /** + * @param string $root + * @param null|string $index + * @return mixed + */ + public function getCategoryWithRoot($root, $index = null) + { + $this->initCategories(); + $returnVal = isset($this->categoriesWithRoots[$root]) ? $this->categoriesWithRoots[$root] : null; + if (empty($returnVal) || is_null($index)) { + return $returnVal; + } + return isset($returnVal[$index]) ? $returnVal[$index] : null; + } + + /** + * @param string $index + * @return null|string + */ + public function getCategory($index) + { + $this->initCategories(); + return isset($this->categories[$index]) ? $this->categories[$index] : null; + } +} diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php index f0e7b75f25d90..979a5ede17cf5 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php @@ -17,7 +17,6 @@ * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @todo Need to explode this class because of several responsibilities - * @todo Refactor in the scope of https://wiki.magento.com/display/MAGE2/Technical+Debt+%28Team-Donetsk-B%29 */ class Option extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity { diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/RowValidatorInterface.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/RowValidatorInterface.php new file mode 100644 index 0000000000000..4e986422eee52 --- /dev/null +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/RowValidatorInterface.php @@ -0,0 +1,75 @@ + array( + * 'type_id' => (string) product type + * 'attr_set_id' => (int) product attribute set ID + * 'entity_id' => (int) product ID (value for new products will be set after entity save) + * 'attr_set_code' => (string) attribute set code + * ) + * + * @var array + */ + protected $newSkus; + + /** + * @var array + */ + protected $productTypeModels; + + /** + * @param \Magento\Catalog\Model\ProductFactory $productFactory + */ + public function __construct(\Magento\Catalog\Model\ProductFactory $productFactory) + { + $this->productFactory = $productFactory; + } + + /** + * @param array $typeModels + * @return $this + */ + public function setTypeModels($typeModels) + { + $this->productTypeModels = $typeModels; + return $this; + } + + /** + * @return array + */ + public function getOldSkus() + { + if (!$this->oldSkus) { + $columns = ['entity_id', 'type_id', 'attribute_set_id', 'sku']; + foreach ($this->productFactory->create()->getProductEntitiesInfo($columns) as $info) { + $typeId = $info['type_id']; + $sku = $info['sku']; + $this->oldSkus[$sku] = [ + 'type_id' => $typeId, + 'attr_set_id' => $info['attribute_set_id'], + 'entity_id' => $info['entity_id'], + 'supported_type' => isset($this->productTypeModels[$typeId]), + ]; + } + } + return $this->oldSkus; + } + + /** + * @param string $sku + * @param array $data + * @return $this + */ + public function addNewSku($sku, $data) + { + $this->newSkus[$sku] = $data; + return $this; + } + + /** + * @param string $sku + * @param string $key + * @param mixed $data + * @return $this + */ + public function setNewSkuData($sku, $key, $data) + { + if ($this->newSkus[$sku]) { + $this->newSkus[$sku][$key] = $data; + } + return $this; + } + + /** + * @param null|string $sku + * @return array|null + */ + public function getNewSku($sku = null) + { + if (!is_null($sku)) { + return isset($this->newSkus[$sku]) ? $this->newSkus[$sku] : null; + } + return $this->newSkus; + } +} diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/StoreResolver.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/StoreResolver.php new file mode 100644 index 0000000000000..af478e82e4c3f --- /dev/null +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/StoreResolver.php @@ -0,0 +1,138 @@ +storeManager = $storeManager; + } + + /** + * Initialize website values. + * + * @return $this + */ + protected function _initWebsites() + { + /** @var $website \Magento\Store\Model\Website */ + foreach ($this->storeManager->getWebsites() as $website) { + $this->websiteCodeToId[$website->getCode()] = $website->getId(); + $this->websiteCodeToStoreIds[$website->getCode()] = array_flip($website->getStoreCodes()); + } + return $this; + } + + /** + * @param null|string $code + * @return array|string|null + */ + public function getWebsiteCodeToId($code = null) + { + if (empty($this->websiteCodeToId)) { + $this->_initWebsites(); + } + if ($code) { + return isset($this->websiteCodeToId[$code]) ? $this->websiteCodeToId[$code] : null; + } + return $this->websiteCodeToId; + } + + /** + * @param null|string $code + * @return array|string|null + */ + public function getWebsiteCodeToStoreIds($code = null) + { + if (empty($this->websiteCodeToStoreIds)) { + $this->_initWebsites(); + } + if ($code) { + return isset($this->websiteCodeToStoreIds[$code]) ? $this->websiteCodeToStoreIds[$code] : null; + } + return $this->websiteCodeToStoreIds; + } + + /** + * Initialize stores hash. + * + * @return $this + */ + protected function _initStores() + { + foreach ($this->storeManager->getStores() as $store) { + $this->storeCodeToId[$store->getCode()] = $store->getId(); + $this->storeIdToWebsiteStoreIds[$store->getId()] = $store->getWebsite()->getStoreIds(); + } + return $this; + } + + /** + * @param null|string $code + * @return array|string|null + */ + public function getStoreCodeToId($code = null) + { + if (empty($this->storeCodeToId)) { + $this->_initStores(); + } + if ($code) { + return isset($this->storeCodeToId[$code]) ? $this->storeCodeToId[$code] : null; + } + return $this->storeCodeToId; + } + + /** + * @param null|string $code + * @return array|string|null + */ + public function getStoreIdToWebsiteStoreIds($code = null) + { + if (empty($this->storeIdToWebsiteStoreIds)) { + $this->_initStores(); + } + if ($code) { + return isset($this->storeIdToWebsiteStoreIds[$code]) ? $this->storeIdToWebsiteStoreIds[$code] : null; + } + return $this->storeIdToWebsiteStoreIds; + } +} diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator.php new file mode 100644 index 0000000000000..0f44d54947164 --- /dev/null +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator.php @@ -0,0 +1,50 @@ +validators = $validators; + } + + /** + * {@inheritdoc} + */ + public function isValid($value) + { + $returnValue = true; + $this->_clearMessages(); + foreach ($this->validators as $validator) { + if (!$validator->isValid($value)) { + $returnValue = false; + $this->_addMessages($validator->getMessages()); + } + } + return $returnValue; + } + + /** + * {@inheritdoc} + */ + public function init() + { + foreach ($this->validators as $validator) { + $validator->init(); + } + } +} diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/AbstractPrice.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/AbstractPrice.php new file mode 100644 index 0000000000000..1f6f41ffaa5b4 --- /dev/null +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/AbstractPrice.php @@ -0,0 +1,52 @@ +groupRepository = $groupRepository; + $this->searchCriteriaBuilder = $searchCriteriaBuilder; + } + + /** + * {@inheritdoc} + */ + public function init() + { + foreach ($this->groupRepository->getList($this->searchCriteriaBuilder->create())->getItems() as $group) { + $this->customerGroups[$group->getId()] = true; + } + return $this; + } +} diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Category.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Category.php new file mode 100644 index 0000000000000..6c3e0e54d180d --- /dev/null +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Category.php @@ -0,0 +1,63 @@ +categoryProcessor = $categoryProcessor; + } + + /** + * {@inheritdoc} + */ + public function init() + { + return $this; + } + + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + public function isValid($value) + { + $this->_clearMessages(); + $emptyCategory = empty($value[Product::COL_CATEGORY]); + $emptyRootCategory = empty($value[Product::COL_ROOT_CATEGORY]); + $hasCategory = $emptyCategory + ? false + : !is_null($this->categoryProcessor->getCategory($value[Product::COL_CATEGORY])); + $category = $emptyRootCategory + ? null + : $this->categoryProcessor->getCategoryWithRoot($value[Product::COL_ROOT_CATEGORY]); + if (!$emptyCategory && !$hasCategory || !$emptyRootCategory && !isset( + $category + ) || !$emptyRootCategory && !$emptyCategory && !isset( + $category[$value[Product::COL_CATEGORY]] + ) + ) { + $this->_addMessages([self::ERROR_INVALID_CATEGORY]); + return false; + } + return true; + } +} diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/GroupPrice.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/GroupPrice.php new file mode 100644 index 0000000000000..2d27b9867a9a4 --- /dev/null +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/GroupPrice.php @@ -0,0 +1,89 @@ +storeResolver = $storeResolver; + parent::__construct($groupRepository, $searchCriteriaBuilder); + } + + /** + * {@inheritdoc} + */ + public function init() + { + return parent::init(); + } + + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + */ + public function isValid($value) + { + $this->_clearMessages(); + if (isset( + $value['_group_price_website'] + ) && strlen( + $value['_group_price_website'] + ) || isset( + $value['_group_price_customer_group'] + ) && strlen( + $value['_group_price_customer_group'] + ) || isset( + $value['_group_price_price'] + ) && strlen( + $value['_group_price_price'] + ) + ) { + if (!isset( + $value['_group_price_website'] + ) || !isset( + $value['_group_price_customer_group'] + ) || !strlen( + $value['_group_price_website'] + ) || !strlen( + $value['_group_price_customer_group'] + ) || !strlen( + $value['_group_price_price'] + ) + ) { + $this->_addMessages([self::ERROR_GROUP_PRICE_DATA_INCOMPLETE]); + return false; + } elseif ($value['_group_price_website'] != self::VALUE_ALL + && !$this->storeResolver->getWebsiteCodeToId($value['_group_price_website']) + ) { + $this->_addMessages([self::ERROR_INVALID_GROUP_PRICE_SITE]); + return false; + } elseif ($value['_group_price_customer_group'] != self::VALUE_ALL && !isset( + $this->customerGroups[$value['_group_price_customer_group']] + ) + ) { + $this->_addMessages([self::ERROR_INVALID_GROUP_PRICE_GROUP]); + return false; + } + } + return true; + } +} diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Media.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Media.php new file mode 100644 index 0000000000000..076477d1d4d7b --- /dev/null +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Media.php @@ -0,0 +1,33 @@ +_clearMessages(); + if (!empty($value['_media_image']) && empty($value['_media_attribute_id'])) { + $this->_addMessages([self::ERROR_MEDIA_DATA_INCOMPLETE]); + return false; + } + return true; + } +} diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/SuperProductsSku.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/SuperProductsSku.php new file mode 100644 index 0000000000000..aa5d4a0e1f1f2 --- /dev/null +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/SuperProductsSku.php @@ -0,0 +1,54 @@ +skuProcessor = $skuProcessor; + } + + /** + * {@inheritdoc} + */ + public function init() + { + return $this; + } + + /** + * {@inheritdoc} + */ + public function isValid($value) + { + $this->_clearMessages(); + $oldSku = $this->skuProcessor->getOldSkus(); + if (!empty($value['_super_products_sku']) && (!isset( + $oldSku[$value['_super_products_sku']] + ) && is_null( + $this->skuProcessor->getNewSku($value['_super_products_sku']) + )) + ) { + $this->_addMessages([self::ERROR_SUPER_PRODUCTS_SKU_NOT_FOUND]); + return false; + } + return true; + + } +} diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/TierPrice.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/TierPrice.php new file mode 100644 index 0000000000000..489bbe11a3f9f --- /dev/null +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/TierPrice.php @@ -0,0 +1,102 @@ +storeResolver = $storeResolver; + parent::__construct($groupRepository, $searchCriteriaBuilder); + } + + /** + * {@inheritdoc} + */ + public function init() + { + return parent::init(); + } + + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + */ + public function isValid($value) + { + $this->_clearMessages(); + if (isset( + $value['_tier_price_website'] + ) && strlen( + $value['_tier_price_website'] + ) || isset( + $value['_tier_price_customer_group'] + ) && strlen( + $value['_tier_price_customer_group'] + ) || isset( + $value['_tier_price_qty'] + ) && strlen( + $value['_tier_price_qty'] + ) || isset( + $value['_tier_price_price'] + ) && strlen( + $value['_tier_price_price'] + ) + ) { + if (!isset( + $value['_tier_price_website'] + ) || !isset( + $value['_tier_price_customer_group'] + ) || !isset( + $value['_tier_price_qty'] + ) || !isset( + $value['_tier_price_price'] + ) || !strlen( + $value['_tier_price_website'] + ) || !strlen( + $value['_tier_price_customer_group'] + ) || !strlen( + $value['_tier_price_qty'] + ) || !strlen( + $value['_tier_price_price'] + ) + ) { + $this->_addMessages([self::ERROR_TIER_DATA_INCOMPLETE]); + return false; + } elseif ($value['_tier_price_website'] != self::VALUE_ALL + && !$this->storeResolver->getWebsiteCodeToId($value['_tier_price_website']) + ) { + $this->_addMessages([self::ERROR_INVALID_TIER_PRICE_SITE]); + return false; + } elseif ($value['_tier_price_customer_group'] != self::VALUE_ALL && !isset( + $this->customerGroups[$value['_tier_price_customer_group']] + ) + ) { + $this->_addMessages([self::ERROR_INVALID_TIER_PRICE_GROUP]); + return false; + } elseif ($value['_tier_price_qty'] <= 0 || $value['_tier_price_price'] <= 0) { + $this->_addMessages([self::ERROR_INVALID_TIER_PRICE_QTY]); + return false; + } + } + return true; + } +} diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Website.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Website.php new file mode 100644 index 0000000000000..0547d7820036f --- /dev/null +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Website.php @@ -0,0 +1,48 @@ +storeResolver = $storeResolver; + } + + /** + * {@inheritdoc} + */ + public function init() + { + return $this; + } + + /** + * {@inheritdoc} + */ + public function isValid($value) + { + $this->_clearMessages(); + if (!empty($value['_product_websites']) + && !$this->storeResolver->getWebsiteCodeToId($value['_product_websites']) + ) { + $this->_addMessages([self::ERROR_INVALID_WEBSITE]); + return false; + } + return true; + } +} diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Weight.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Weight.php new file mode 100644 index 0000000000000..5e6cea959fa8e --- /dev/null +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Weight.php @@ -0,0 +1,33 @@ +_clearMessages(); + if (!empty($value['weight']) && (!is_numeric($value['weight']) || $value['weight'] < 0)) { + $this->_addMessages([self::ERROR_INVALID_WEIGHT]); + return false; + } + return true; + } +} diff --git a/app/code/Magento/CatalogImportExport/etc/di.xml b/app/code/Magento/CatalogImportExport/etc/di.xml index b2c5ceeed0988..9fda72ab31642 100644 --- a/app/code/Magento/CatalogImportExport/etc/di.xml +++ b/app/code/Magento/CatalogImportExport/etc/di.xml @@ -15,4 +15,17 @@ + + + + Magento\CatalogImportExport\Model\Import\Product\Validator\Category + Magento\CatalogImportExport\Model\Import\Product\Validator\GroupPrice + Magento\CatalogImportExport\Model\Import\Product\Validator\Media + Magento\CatalogImportExport\Model\Import\Product\Validator\SuperProductsSku + Magento\CatalogImportExport\Model\Import\Product\Validator\TierPrice + Magento\CatalogImportExport\Model\Import\Product\Validator\Website + Magento\CatalogImportExport\Model\Import\Product\Validator\Weight + + + diff --git a/app/code/Magento/Cms/data/cms_setup/data-install-2.0.0.php b/app/code/Magento/Cms/data/cms_setup/data-install-2.0.0.php index 46847bf5cff2a..54d3289b97e39 100644 --- a/app/code/Magento/Cms/data/cms_setup/data-install-2.0.0.php +++ b/app/code/Magento/Cms/data/cms_setup/data-install-2.0.0.php @@ -50,212 +50,214 @@ } $pageContent = << - - Please replace this text with you Privacy Policy. - Please add any additional cookies your website uses below (e.g., Google Analytics) - +
+
+ + Please replace this text with you Privacy Policy. + Please add any additional cookies your website uses below (e.g., Google Analytics) + +
+

+ This privacy policy sets out how {{config path="general/store_information/name"}} uses and protects any information + that you give {{config path="general/store_information/name"}} when you use this website. + {{config path="general/store_information/name"}} is committed to ensuring that your privacy is protected. + Should we ask you to provide certain information by which you can be identified when using this website, + then you can be assured that it will only be used in accordance with this privacy statement. + {{config path="general/store_information/name"}} may change this policy from time to time by updating this page. + You should check this page from time to time to ensure that you are happy with any changes. +

+

What we collect

+

We may collect the following information:

+
    +
  • name
  • +
  • contact information including email address
  • +
  • demographic information such as postcode, preferences and interests
  • +
  • other information relevant to customer surveys and/or offers
  • +
+

+ For the exhaustive list of cookies we collect see the List of cookies we collect section. +

+

What we do with the information we gather

+

+ We require this information to understand your needs and provide you with a better service, + and in particular for the following reasons: +

+
    +
  • Internal record keeping.
  • +
  • We may use the information to improve our products and services.
  • +
  • + We may periodically send promotional emails about new products, special offers or other information which we + think you may find interesting using the email address which you have provided. +
  • +
  • + From time to time, we may also use your information to contact you for market research purposes. + We may contact you by email, phone, fax or mail. We may use the information to customise the website + according to your interests. +
  • +
+

Security

+

+ We are committed to ensuring that your information is secure. In order to prevent unauthorised access or disclosure, + we have put in place suitable physical, electronic and managerial procedures to safeguard and secure + the information we collect online. +

+

How we use cookies

+

+ A cookie is a small file which asks permission to be placed on your computer's hard drive. + Once you agree, the file is added and the cookie helps analyse web traffic or lets you know when you visit + a particular site. Cookies allow web applications to respond to you as an individual. The web application + can tailor its operations to your needs, likes and dislikes by gathering and remembering information about + your preferences. +

+

+ We use traffic log cookies to identify which pages are being used. This helps us analyse data about web page traffic + and improve our website in order to tailor it to customer needs. We only use this information for statistical + analysis purposes and then the data is removed from the system. +

+

+ Overall, cookies help us provide you with a better website, by enabling us to monitor which pages you find useful + and which you do not. A cookie in no way gives us access to your computer or any information about you, + other than the data you choose to share with us. You can choose to accept or decline cookies. + Most web browsers automatically accept cookies, but you can usually modify your browser setting + to decline cookies if you prefer. This may prevent you from taking full advantage of the website. +

+

Links to other websites

+

+ Our website may contain links to other websites of interest. However, once you have used these links + to leave our site, you should note that we do not have any control over that other website. + Therefore, we cannot be responsible for the protection and privacy of any information which you provide whilst + visiting such sites and such sites are not governed by this privacy statement. + You should exercise caution and look at the privacy statement applicable to the website in question. +

+

Controlling your personal information

+

You may choose to restrict the collection or use of your personal information in the following ways:

+
    +
  • + whenever you are asked to fill in a form on the website, look for the box that you can click to indicate + that you do not want the information to be used by anybody for direct marketing purposes +
  • +
  • + if you have previously agreed to us using your personal information for direct marketing purposes, + you may change your mind at any time by writing to or emailing us at + {{config path="trans_email/ident_general/email"}} +
  • +
+

+ We will not sell, distribute or lease your personal information to third parties unless we have your permission + or are required by law to do so. We may use your personal information to send you promotional information + about third parties which we think you may find interesting if you tell us that you wish this to happen. +

+

+ You may request details of personal information which we hold about you under the Data Protection Act 1998. + A small fee will be payable. If you would like a copy of the information held on you please write to + {{config path="general/store_information/address"}}. +

+

+ If you believe that any information we are holding on you is incorrect or incomplete, + please write to or email us as soon as possible, at the above address. + We will promptly correct any information found to be incorrect. +

+

List of cookies we collect

+

The table below lists the cookies we collect and what information they store.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
COOKIE nameCOOKIE Description
CARTThe association with your shopping cart.
CATEGORY_INFOStores the category info on the page, that allows to display pages more quickly.
COMPAREThe items that you have in the Compare Products list.
CUSTOMERAn encrypted version of your customer id with the store.
CUSTOMER_AUTHAn indicator if you are currently logged into the store.
CUSTOMER_INFOAn encrypted version of the customer group you belong to.
CUSTOMER_SEGMENT_IDSStores the Customer Segment ID
EXTERNAL_NO_CACHEA flag, which indicates whether caching is disabled or not.
FRONTENDYou sesssion ID on the server.
GUEST-VIEWAllows guests to edit their orders.
LAST_CATEGORYThe last category you visited.
LAST_PRODUCTThe most recent product you have viewed.
NEWMESSAGEIndicates whether a new message has been received.
NO_CACHEIndicates whether it is allowed to use cache.
PERSISTENT_SHOPPING_CARTA link to information about your cart and viewing history if you have asked the site.
RECENTLYCOMPAREDThe items that you have recently compared.
STFInformation on products you have emailed to friends.
STOREThe store view or language you have selected.
USER_ALLOWED_SAVE_COOKIEIndicates whether a customer allowed to use cookies.
VIEWED_PRODUCT_IDSThe products that you have recently viewed.
WISHLISTAn encrypted list of products added to your Wishlist.
WISHLIST_CNTThe number of items in your Wishlist.
-

- This privacy policy sets out how {{config path="general/store_information/name"}} uses and protects any information - that you give {{config path="general/store_information/name"}} when you use this website. - {{config path="general/store_information/name"}} is committed to ensuring that your privacy is protected. - Should we ask you to provide certain information by which you can be identified when using this website, - then you can be assured that it will only be used in accordance with this privacy statement. - {{config path="general/store_information/name"}} may change this policy from time to time by updating this page. - You should check this page from time to time to ensure that you are happy with any changes. -

-

What we collect

-

We may collect the following information:

-
    -
  • name
  • -
  • contact information including email address
  • -
  • demographic information such as postcode, preferences and interests
  • -
  • other information relevant to customer surveys and/or offers
  • -
-

- For the exhaustive list of cookies we collect see the List of cookies we collect section. -

-

What we do with the information we gather

-

- We require this information to understand your needs and provide you with a better service, - and in particular for the following reasons: -

-
    -
  • Internal record keeping.
  • -
  • We may use the information to improve our products and services.
  • -
  • - We may periodically send promotional emails about new products, special offers or other information which we - think you may find interesting using the email address which you have provided. -
  • -
  • - From time to time, we may also use your information to contact you for market research purposes. - We may contact you by email, phone, fax or mail. We may use the information to customise the website - according to your interests. -
  • -
-

Security

-

- We are committed to ensuring that your information is secure. In order to prevent unauthorised access or disclosure, - we have put in place suitable physical, electronic and managerial procedures to safeguard and secure - the information we collect online. -

-

How we use cookies

-

- A cookie is a small file which asks permission to be placed on your computer's hard drive. - Once you agree, the file is added and the cookie helps analyse web traffic or lets you know when you visit - a particular site. Cookies allow web applications to respond to you as an individual. The web application - can tailor its operations to your needs, likes and dislikes by gathering and remembering information about - your preferences. -

-

- We use traffic log cookies to identify which pages are being used. This helps us analyse data about web page traffic - and improve our website in order to tailor it to customer needs. We only use this information for statistical - analysis purposes and then the data is removed from the system. -

-

- Overall, cookies help us provide you with a better website, by enabling us to monitor which pages you find useful - and which you do not. A cookie in no way gives us access to your computer or any information about you, - other than the data you choose to share with us. You can choose to accept or decline cookies. - Most web browsers automatically accept cookies, but you can usually modify your browser setting - to decline cookies if you prefer. This may prevent you from taking full advantage of the website. -

-

Links to other websites

-

- Our website may contain links to other websites of interest. However, once you have used these links - to leave our site, you should note that we do not have any control over that other website. - Therefore, we cannot be responsible for the protection and privacy of any information which you provide whilst - visiting such sites and such sites are not governed by this privacy statement. - You should exercise caution and look at the privacy statement applicable to the website in question. -

-

Controlling your personal information

-

You may choose to restrict the collection or use of your personal information in the following ways:

-
    -
  • - whenever you are asked to fill in a form on the website, look for the box that you can click to indicate - that you do not want the information to be used by anybody for direct marketing purposes -
  • -
  • - if you have previously agreed to us using your personal information for direct marketing purposes, - you may change your mind at any time by writing to or emailing us at - {{config path="trans_email/ident_general/email"}} -
  • -
-

- We will not sell, distribute or lease your personal information to third parties unless we have your permission - or are required by law to do so. We may use your personal information to send you promotional information - about third parties which we think you may find interesting if you tell us that you wish this to happen. -

-

- You may request details of personal information which we hold about you under the Data Protection Act 1998. - A small fee will be payable. If you would like a copy of the information held on you please write to - {{config path="general/store_information/address"}}. -

-

- If you believe that any information we are holding on you is incorrect or incomplete, - please write to or email us as soon as possible, at the above address. - We will promptly correct any information found to be incorrect. -

-

List of cookies we collect

-

The table below lists the cookies we collect and what information they store.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
COOKIE nameCOOKIE Description
CARTThe association with your shopping cart.
CATEGORY_INFOStores the category info on the page, that allows to display pages more quickly.
COMPAREThe items that you have in the Compare Products list.
CUSTOMERAn encrypted version of your customer id with the store.
CUSTOMER_AUTHAn indicator if you are currently logged into the store.
CUSTOMER_INFOAn encrypted version of the customer group you belong to.
CUSTOMER_SEGMENT_IDSStores the Customer Segment ID
EXTERNAL_NO_CACHEA flag, which indicates whether caching is disabled or not.
FRONTENDYou sesssion ID on the server.
GUEST-VIEWAllows guests to edit their orders.
LAST_CATEGORYThe last category you visited.
LAST_PRODUCTThe most recent product you have viewed.
NEWMESSAGEIndicates whether a new message has been received.
NO_CACHEIndicates whether it is allowed to use cache.
PERSISTENT_SHOPPING_CARTA link to information about your cart and viewing history if you have asked the site.
RECENTLYCOMPAREDThe items that you have recently compared.
STFInformation on products you have emailed to friends.
STOREThe store view or language you have selected.
USER_ALLOWED_SAVE_COOKIEIndicates whether a customer allowed to use cookies.
VIEWED_PRODUCT_IDSThe products that you have recently viewed.
WISHLISTAn encrypted list of products added to your Wishlist.
WISHLIST_CNTThe number of items in your Wishlist.
EOD; $privacyPageData = [ diff --git a/app/code/Magento/GoogleShopping/Helper/Data.php b/app/code/Magento/GoogleShopping/Helper/Data.php index 30e39ba157abf..04f617eb913c7 100644 --- a/app/code/Magento/GoogleShopping/Helper/Data.php +++ b/app/code/Magento/GoogleShopping/Helper/Data.php @@ -112,13 +112,13 @@ public function parseGdataExceptionMessage($message, $product = null) // parse not well-formatted xml preg_match_all('/(reason|field|type)=\"([^\"]+)\"/', $row, $matches); - if (is_array($matches) && count($matches) == 3) { - if (is_array($matches[1]) && count($matches[1]) > 0) { - $c = count($matches[1]); - for ($i = 0; $i < $c; $i++) { - if (isset($matches[2][$i])) { - $result[] = ucfirst($matches[1][$i]) . ': ' . $matches[2][$i]; - } + if (is_array($matches) && count($matches) == 3 + && is_array($matches[1]) && count($matches[1]) > 0 + ) { + $c = count($matches[1]); + for ($i = 0; $i < $c; $i++) { + if (isset($matches[2][$i])) { + $result[] = ucfirst($matches[1][$i]) . ': ' . $matches[2][$i]; } } } diff --git a/app/code/Magento/GroupedImportExport/Model/Import/Product/Type/Grouped.php b/app/code/Magento/GroupedImportExport/Model/Import/Product/Type/Grouped.php index 8f6b287941845..2fbdbb4a86cba 100644 --- a/app/code/Magento/GroupedImportExport/Model/Import/Product/Type/Grouped.php +++ b/app/code/Magento/GroupedImportExport/Model/Import/Product/Type/Grouped.php @@ -17,62 +17,26 @@ class Grouped extends \Magento\CatalogImportExport\Model\Import\Product\Type\Abs protected $_specialAttributes = ['_associated_sku', '_associated_default_qty', '_associated_position']; /** - * Import model behavior - * - * @var string - */ - protected $_behavior; - - /** - * @var \Magento\ImportExport\Model\ImportFactory - */ - protected $_importFactory; - - /** - * @var \Magento\Framework\App\Resource + * @var Grouped\Links */ - protected $_resource; - - /** - * @var \Magento\Catalog\Model\Resource\Product\LinkFactory - */ - protected $_productLinkFactory; + protected $links; /** * @param \Magento\Eav\Model\Resource\Entity\Attribute\Set\CollectionFactory $attrSetColFac * @param \Magento\Catalog\Model\Resource\Product\Attribute\CollectionFactory $prodAttrColFac * @param array $params - * @param \Magento\ImportExport\Model\ImportFactory $importFactory - * @param \Magento\Catalog\Model\Resource\Product\LinkFactory $productLinkFactory - * @param \Magento\Framework\App\Resource $resource + * @param Grouped\Links $links */ public function __construct( \Magento\Eav\Model\Resource\Entity\Attribute\Set\CollectionFactory $attrSetColFac, \Magento\Catalog\Model\Resource\Product\Attribute\CollectionFactory $prodAttrColFac, array $params, - \Magento\ImportExport\Model\ImportFactory $importFactory, - \Magento\Catalog\Model\Resource\Product\LinkFactory $productLinkFactory, - \Magento\Framework\App\Resource $resource + Grouped\Links $links ) { - $this->_importFactory = $importFactory; - $this->_resource = $resource; - $this->_productLinkFactory = $productLinkFactory; + $this->links = $links; parent::__construct($attrSetColFac, $prodAttrColFac, $params); } - /** - * Retrieve model behavior - * - * @return string - */ - public function getBehavior() - { - if (is_null($this->_behavior)) { - $this->_behavior = $this->_importFactory->create()->getDataSourceModel()->getBehavior(); - } - return $this->_behavior; - } - /** * Save product type specific data. * @@ -80,51 +44,30 @@ public function getBehavior() * * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function saveData() { - $groupedLinkId = \Magento\GroupedProduct\Model\Resource\Product\Link::LINK_TYPE_GROUPED; - $connection = $this->_resource->getConnection('write'); - $resource = $this->_productLinkFactory->create(); - $mainTable = $resource->getMainTable(); - $relationTable = $resource->getTable('catalog_product_relation'); $newSku = $this->_entityModel->getNewSku(); $oldSku = $this->_entityModel->getOldSku(); - $attributes = []; - - // pre-load attributes parameters - $select = $connection->select()->from( - $resource->getTable('catalog_product_link_attribute'), - ['id' => 'product_link_attribute_id', 'code' => 'product_link_attribute_code', 'type' => 'data_type'] - )->where( - 'link_type_id = ?', - $groupedLinkId - ); - foreach ($connection->fetchAll($select) as $row) { - $attributes[$row['code']] = [ - 'id' => $row['id'], - 'table' => $resource->getAttributeTypeTable($row['type']), - ]; - } + $attributes = $this->links->getAttributes(); + $productData = []; while ($bunch = $this->_entityModel->getNextBunch()) { $linksData = [ 'product_ids' => [], - 'links' => [], 'attr_product_ids' => [], 'position' => [], 'qty' => [], - 'relation' => [], + 'relation' => [] ]; foreach ($bunch as $rowNum => $rowData) { - if (!$this->_entityModel->isRowAllowedToImport($rowData, $rowNum) || empty($rowData['_associated_sku']) - ) { + $associatedSku = isset($rowData['_associated_sku']) ? $rowData['_associated_sku'] : null; + if (!$this->_entityModel->isRowAllowedToImport($rowData, $rowNum) || empty($associatedSku)) { continue; } - if (isset($newSku[$rowData['_associated_sku']])) { - $linkedProductId = $newSku[$rowData['_associated_sku']]['entity_id']; - } elseif (isset($oldSku[$rowData['_associated_sku']])) { - $linkedProductId = $oldSku[$rowData['_associated_sku']]['entity_id']; + if (isset($newSku[$associatedSku])) { + $linkedProductId = $newSku[$associatedSku]['entity_id']; + } elseif (isset($oldSku[$associatedSku])) { + $linkedProductId = $oldSku[$associatedSku]['entity_id']; } else { continue; } @@ -142,80 +85,26 @@ public function saveData() continue; } $linksData['product_ids'][$productId] = true; - $linksData['links'][$productId][$linkedProductId] = $groupedLinkId; $linksData['relation'][] = ['parent_id' => $productId, 'child_id' => $linkedProductId]; $qty = empty($rowData['_associated_default_qty']) ? 0 : $rowData['_associated_default_qty']; $pos = empty($rowData['_associated_position']) ? 0 : $rowData['_associated_position']; - if ($qty || $pos) { + if ($pos) { $linksData['attr_product_ids'][$productId] = true; - if ($pos) { - $linksData['position']["{$productId} {$linkedProductId}"] = [ - 'product_link_attribute_id' => $attributes['position']['id'], - 'value' => $pos, - ]; - } - if ($qty) { - $linksData['qty']["{$productId} {$linkedProductId}"] = [ - 'product_link_attribute_id' => $attributes['qty']['id'], - 'value' => $qty, - ]; - } - } - } - // save links and relations - if ($linksData['product_ids'] && - $this->getBehavior() != \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND - ) { - $connection->delete( - $mainTable, - $connection->quoteInto( - 'product_id IN (?) AND link_type_id = ' . $groupedLinkId, - array_keys($linksData['product_ids']) - ) - ); - } - if ($linksData['links']) { - $mainData = []; - - foreach ($linksData['links'] as $productId => $linkedData) { - foreach ($linkedData as $linkedId => $linkType) { - $mainData[] = [ - 'product_id' => $productId, - 'linked_product_id' => $linkedId, - 'link_type_id' => $linkType, - ]; - } + $linksData['position']["{$productId} {$linkedProductId}"] = [ + 'product_link_attribute_id' => $attributes['position']['id'], + 'value' => $pos + ]; } - $connection->insertOnDuplicate($mainTable, $mainData); - $connection->insertOnDuplicate($relationTable, $linksData['relation']); - } - // save positions and default quantity - if ($linksData['attr_product_ids']) { - $savedData = $connection->fetchPairs( - $connection->select()->from( - $mainTable, - [new \Zend_Db_Expr('CONCAT_WS(" ", product_id, linked_product_id)'), 'link_id'] - )->where( - 'product_id IN (?) AND link_type_id = ' . $groupedLinkId, - array_keys($linksData['attr_product_ids']) - ) - ); - foreach ($savedData as $pseudoKey => $linkId) { - if (isset($linksData['position'][$pseudoKey])) { - $linksData['position'][$pseudoKey]['link_id'] = $linkId; - } - if (isset($linksData['qty'][$pseudoKey])) { - $linksData['qty'][$pseudoKey]['link_id'] = $linkId; - } - } - if ($linksData['position']) { - $connection->insertOnDuplicate($attributes['position']['table'], $linksData['position']); - } - if ($linksData['qty']) { - $connection->insertOnDuplicate($attributes['qty']['table'], $linksData['qty']); + if ($qty) { + $linksData['attr_product_ids'][$productId] = true; + $linksData['qty']["{$productId} {$linkedProductId}"] = [ + 'product_link_attribute_id' => $attributes['qty']['id'], + 'value' => $qty + ]; } } + $this->links->saveLinksData($linksData); } return $this; } diff --git a/app/code/Magento/GroupedImportExport/Model/Import/Product/Type/Grouped/Links.php b/app/code/Magento/GroupedImportExport/Model/Import/Product/Type/Grouped/Links.php new file mode 100644 index 0000000000000..4a2f1c93faa61 --- /dev/null +++ b/app/code/Magento/GroupedImportExport/Model/Import/Product/Type/Grouped/Links.php @@ -0,0 +1,165 @@ +productLink = $productLink; + $this->importFactory = $importFactory; + $this->connection = $resource->getConnection('write'); + } + + /** + * @param array $linksData + * @return void + */ + public function saveLinksData($linksData) + { + $mainTable = $this->productLink->getMainTable(); + $relationTable = $this->productLink->getTable('catalog_product_relation'); + // save links and relations + if ($linksData['product_ids']) { + $this->deleteOldLinks(array_keys($linksData['product_ids'])); + $mainData = []; + foreach ($linksData['relation'] as $productData) { + $mainData[] = [ + 'product_id' => $productData['parent_id'], + 'linked_product_id' => $productData['child_id'], + 'link_type_id' => $this->getLinkTypeId() + ]; + } + $this->connection->insertOnDuplicate($mainTable, $mainData); + $this->connection->insertOnDuplicate($relationTable, $linksData['relation']); + } + + $attributes = $this->getAttributes(); + // save positions and default quantity + if ($linksData['attr_product_ids']) { + $savedData = $this->connection->fetchPairs( + $this->connection->select()->from( + $mainTable, + [new \Zend_Db_Expr('CONCAT_WS(" ", product_id, linked_product_id)'), 'link_id'] + )->where( + 'product_id IN (?) AND link_type_id = ' . $this->connection->quote($this->getLinkTypeId()), + array_keys($linksData['attr_product_ids']) + ) + ); + foreach ($savedData as $pseudoKey => $linkId) { + if (isset($linksData['position'][$pseudoKey])) { + $linksData['position'][$pseudoKey]['link_id'] = $linkId; + } + if (isset($linksData['qty'][$pseudoKey])) { + $linksData['qty'][$pseudoKey]['link_id'] = $linkId; + } + } + if (!empty($linksData['position'])) { + $this->connection->insertOnDuplicate($attributes['position']['table'], $linksData['position']); + } + if (!empty($linksData['qty'])) { + $this->connection->insertOnDuplicate($attributes['qty']['table'], $linksData['qty']); + } + } + } + + /** + * @param array $productIds + * @throws \Magento\Framework\Model\Exception + * @return void + */ + protected function deleteOldLinks($productIds) + { + if ($this->getBehavior() != \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND) { + $this->connection->delete( + $this->productLink->getMainTable(), + $this->connection->quoteInto( + 'product_id IN (?) AND link_type_id = ' . $this->getLinkTypeId(), + $productIds + ) + ); + } + } + + /** + * @return array + */ + public function getAttributes() + { + if (empty($this->attributes)) { + $select = $this->connection->select()->from( + $this->productLink->getTable('catalog_product_link_attribute'), + ['id' => 'product_link_attribute_id', 'code' => 'product_link_attribute_code', 'type' => 'data_type'] + )->where('link_type_id = ?', $this->getLinkTypeId()); + foreach ($this->connection->fetchAll($select) as $row) { + $this->attributes[$row['code']] = [ + 'id' => $row['id'], + 'table' => $this->productLink->getAttributeTypeTable($row['type']) + ]; + } + } + return $this->attributes; + } + + /** + * @return int + */ + protected function getLinkTypeId() + { + return \Magento\GroupedProduct\Model\Resource\Product\Link::LINK_TYPE_GROUPED; + } + + /** + * Retrieve model behavior + * + * @return string + */ + protected function getBehavior() + { + if (is_null($this->behavior)) { + $this->behavior = $this->importFactory->create()->getDataSourceModel()->getBehavior(); + } + return $this->behavior; + } +} diff --git a/app/code/Magento/ImportExport/view/adminhtml/templates/export/form/before.phtml b/app/code/Magento/ImportExport/view/adminhtml/templates/export/form/before.phtml index 60cef499d263d..0379c646f870f 100644 --- a/app/code/Magento/ImportExport/view/adminhtml/templates/export/form/before.phtml +++ b/app/code/Magento/ImportExport/view/adminhtml/templates/export/form/before.phtml @@ -54,6 +54,7 @@ require(['prototype'], function(){ $('export_filter_grid_container').update(responseText); this.modifyFilterGrid(); $('export_filter_container').show(); + $('messages').update(); }.bind(this) }); } else { diff --git a/app/code/Magento/Review/Block/Adminhtml/Rating/Edit/Tab/Form.php b/app/code/Magento/Review/Block/Adminhtml/Rating/Edit/Tab/Form.php index d3971e9e08abb..57989416a511c 100644 --- a/app/code/Magento/Review/Block/Adminhtml/Rating/Edit/Tab/Form.php +++ b/app/code/Magento/Review/Block/Adminhtml/Rating/Edit/Tab/Form.php @@ -12,7 +12,7 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic * * @var \Magento\Store\Model\System\Store */ - protected $_systemStore; + protected $systemStore; /** * @var string @@ -24,14 +24,19 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic * * @var \Magento\Framework\Session\SessionManagerInterface */ - protected $_session; + protected $session; /** * Option factory * * @var \Magento\Review\Model\Rating\OptionFactory */ - protected $_optionFactory; + protected $optionFactory; + + /** + * @var \Magento\Framework\Data\Form\Element\Fieldset + */ + protected $fieldset; /** * @param \Magento\Backend\Block\Template\Context $context @@ -51,9 +56,9 @@ public function __construct( \Magento\Store\Model\System\Store $systemStore, array $data = [] ) { - $this->_optionFactory = $optionFactory; - $this->_session = $session; - $this->_systemStore = $systemStore; + $this->optionFactory = $optionFactory; + $this->session = $session; + $this->systemStore = $systemStore; parent::__construct($context, $registry, $formFactory, $data); } @@ -67,13 +72,30 @@ public function __construct( */ protected function _prepareForm() { - /** @var \Magento\Framework\Data\Form $form */ - $form = $this->_formFactory->create(); - $this->setForm($form); + $this->setForm($this->_formFactory->create()); + $this->addRatingFieldset(); + $this->addVisibilityFieldset(); + if ($this->_coreRegistry->registry('rating_data')) { + $this->getForm()->getElement('position')->setValue( + $this->_coreRegistry->registry('rating_data')->getPosition() + ); + $this->getForm()->getElement('is_active')->setIsChecked( + $this->_coreRegistry->registry('rating_data')->getIsActive() + ); + } - $fieldset = $form->addFieldset('rating_form', ['legend' => __('Rating Title')]); + return parent::_prepareForm(); + } - $fieldset->addField( + /** + * Add rating fieldset to form + * + * @return void + */ + protected function addRatingFieldset() + { + $this->initFieldset('rating_form', ['legend' => __('Rating Title')]); + $this->getFieldset('rating_form')->addField( 'rating_code', 'text', [ @@ -84,36 +106,71 @@ protected function _prepareForm() ] ); - foreach ($this->_systemStore->getStoreCollection() as $store) { - $fieldset->addField( + foreach ($this->systemStore->getStoreCollection() as $store) { + $this->getFieldset('rating_form')->addField( 'rating_code_' . $store->getId(), 'text', ['label' => $store->getName(), 'name' => 'rating_codes[' . $store->getId() . ']'] ); } + $this->setRatingData(); + } - if ($this->_session->getRatingData()) { - $form->setValues($this->_session->getRatingData()); - $data = $this->_session->getRatingData(); + /** + * Set rating data to form + * + * @return void + */ + protected function setRatingData() + { + if ($this->session->getRatingData()) { + $this->getForm()->setValues($this->session->getRatingData()); + $data = $this->session->getRatingData(); if (isset($data['rating_codes'])) { - $this->_setRatingCodes($data['rating_codes']); + $this->setRatingCodes($data['rating_codes']); } - $this->_session->setRatingData(null); + $this->session->setRatingData(null); } elseif ($this->_coreRegistry->registry('rating_data')) { - $form->setValues($this->_coreRegistry->registry('rating_data')->getData()); + $this->getForm()->setValues($this->_coreRegistry->registry('rating_data')->getData()); if ($this->_coreRegistry->registry('rating_data')->getRatingCodes()) { - $this->_setRatingCodes($this->_coreRegistry->registry('rating_data')->getRatingCodes()); + $this->setRatingCodes($this->_coreRegistry->registry('rating_data')->getRatingCodes()); } } + $this->setRatingOptions(); + } + + /** + * Set rating codes to form + * + * @param array $ratingCodes + * @return void + */ + protected function setRatingCodes($ratingCodes) + { + foreach ($ratingCodes as $store => $value) { + $element = $this->getForm()->getElement('rating_code_' . $store); + if ($element) { + $element->setValue($value); + } + } + } + + /** + * Set rating options to form + * + * @return void + */ + protected function setRatingOptions() + { if ($this->_coreRegistry->registry('rating_data')) { - $collection = $this->_optionFactory->create()->getResourceCollection()->addRatingFilter( + $collection = $this->optionFactory->create()->getResourceCollection()->addRatingFilter( $this->_coreRegistry->registry('rating_data')->getId() )->load(); $i = 1; foreach ($collection->getItems() as $item) { - $fieldset->addField( + $this->getFieldset('rating_form')->addField( 'option_code_' . $item->getId(), 'hidden', [ @@ -127,62 +184,80 @@ protected function _prepareForm() } } else { for ($i = 1; $i <= 5; $i++) { - $fieldset->addField( + $this->getFieldset('rating_form')->addField( 'option_code_' . $i, 'hidden', ['required' => true, 'name' => 'option_title[add_' . $i . ']', 'value' => $i] ); } } + } - $fieldset = $form->addFieldset('visibility_form', ['legend' => __('Rating Visibility')]); + /** + * Add visibility fieldset to form + * + * @return void + */ + protected function addVisibilityFieldset() + { + $this->initFieldset('visibility_form', ['legend' => __('Rating Visibility')]); if (!$this->_storeManager->isSingleStoreMode()) { - $field = $fieldset->addField( + $field = $this->getFieldset('visibility_form')->addField( 'stores', 'multiselect', [ 'label' => __('Visible In'), 'name' => 'stores[]', - 'values' => $this->_systemStore->getStoreValuesForForm() + 'values' => $this->systemStore->getStoreValuesForForm() ] ); $renderer = $this->getLayout()->createBlock( 'Magento\Backend\Block\Store\Switcher\Form\Renderer\Fieldset\Element' ); $field->setRenderer($renderer); - if ($this->_coreRegistry->registry('rating_data')) { - $form->getElement('stores')->setValue($this->_coreRegistry->registry('rating_data')->getStores()); + $this->getForm()->getElement('stores')->setValue( + $this->_coreRegistry->registry('rating_data')->getStores() + ); } } - - $fieldset->addField( + $this->getFieldset('visibility_form')->addField( 'is_active', 'checkbox', ['label' => __('Is Active'), 'name' => 'is_active', 'value' => 1] ); + $this->getFieldset('visibility_form') + ->addField('position', 'text', ['label' => __('Sort Order'), 'name' => 'position']); + } - $fieldset->addField('position', 'text', ['label' => __('Sort Order'), 'name' => 'position']); - - if ($this->_coreRegistry->registry('rating_data')) { - $form->getElement('position')->setValue($this->_coreRegistry->registry('rating_data')->getPosition()); - $form->getElement('is_active')->setIsChecked($this->_coreRegistry->registry('rating_data')->getIsActive()); + /** + * Initialize form fieldset + * + * @param string $formId + * @param array $config + * @return void + */ + protected function initFieldset($formId, array $config) + { + if (!isset($this->fieldset[$formId])) { + if (!$this->getForm()->getElement($formId)) { + $this->fieldset[$formId] = $this->getForm()->addFieldset($formId, $config); + } elseif ($this->getForm()->getElement($formId)); } - - return parent::_prepareForm(); } /** - * @param array $ratingCodes - * @return void + * Get fieldset by form id + * + * @param string $formId + * @return \Magento\Framework\Data\Form\Element\Fieldset|null */ - protected function _setRatingCodes($ratingCodes) + protected function getFieldset($formId) { - foreach ($ratingCodes as $store => $value) { - $element = $this->getForm()->getElement('rating_code_' . $store); - if ($element) { - $element->setValue($value); - } + if (!empty($this->fieldset) && isset($this->fieldset[$formId])) { + return $this->fieldset[$formId]; + } else { + return null; } } } diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php index 536fbc15526a0..dc1f09fdf1650 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php @@ -24,7 +24,7 @@ public function testGet() { $expected = [ 'parent_id' => 2, - 'path' => '1/2/3', + 'path' => '1/2/333', 'position' => 1, 'level' => 2, 'available_sort_by' => ['position', 'name'], diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTest.php index f950d3c4b8017..72a723413d214 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTest.php @@ -257,4 +257,13 @@ public function testValidate() ]); $this->assertNotEmpty($this->_model->validate()); } + + /** + * @magentoDataFixture Magento/Catalog/_files/category_with_position.php + */ + public function testSaveCategoryWithPosition() + { + $category = $this->_model->load('444'); + $this->assertEquals('5', $category->getPosition()); + } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/category.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/category.php index c84567063bce1..f5dba33f2bcf6 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/category.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/category.php @@ -15,7 +15,7 @@ )->setParentId( 2 )->setPath( - '1/2/3' + '1/2/333' )->setLevel( 2 )->setAvailableSortBy( diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_position.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_position.php new file mode 100644 index 0000000000000..e7cee3dc36a0f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_position.php @@ -0,0 +1,27 @@ +create('Magento\Catalog\Model\Category'); +$category->isObjectNew(true); +$category->setId( + '444' +)->setName( + 'Category 1' +)->setAttributeSetId( + '3' +)->setParentId( + 2 +)->setPath( + '1/2' +)->setLevel( + '2' +)->setDefaultSortBy( + 'name' +)->setIsActive( + true +)->setPosition( + '5' +)->save(); diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php index c834fc99e27c6..def5584983e61 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php @@ -50,7 +50,7 @@ protected function setUp() } /** - * @magentoDataFixture Magento/ImportExport/_files/product.php + * @magentoDataFixture Magento/CatalogImportExport/_files/product_export_data.php */ public function testExport() { @@ -66,7 +66,7 @@ public function testExport() * Verify that all stock item attribute values are exported (aren't equal to empty string) * * @covers \Magento\CatalogImportExport\Model\Export\Product::export - * @magentoDataFixture Magento/ImportExport/_files/product.php + * @magentoDataFixture Magento/CatalogImportExport/_files/product_export_data.php */ public function testExportStockItemAttributesAreFilled() { diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php index 49b3901576e4a..6c0af79022f84 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php @@ -91,7 +91,8 @@ protected function setUp() /** * Test if visibility properly saved after import * - * magentoDataFixture Magento/Catalog/_files/multiple_products.php + * @magentoDataFixture Magento/Catalog/_files/multiple_products.php + * @magentoAppIsolation enabled */ public function testSaveProductsVisibility() { @@ -191,6 +192,7 @@ public function testSaveStockItemQty() * Test if stock state properly changed after import * * @magentoDataFixture Magento/Catalog/_files/multiple_products.php + * @magentoAppIsolation enabled */ public function testStockState() { @@ -225,6 +227,7 @@ public function testStockState() * @param string $behavior * @param string $importFile * @param string $sku + * @magentoAppIsolation enabled */ public function testSaveCustomOptions($behavior, $importFile, $sku) { @@ -286,6 +289,7 @@ public function testSaveCustomOptions($behavior, $importFile, $sku) * Test if datetime properly saved after import * * @magentoDataFixture Magento/Catalog/_files/multiple_products.php + * @magentoAppIsolation enabled * TODO MAGETWO-31206 */ public function testSaveDatetimeAttribute() @@ -743,6 +747,7 @@ public function testInvalidSkuLink() /** * @magentoDataFixture Magento/Catalog/_files/products_with_multiselect_attribute.php + * @magentoAppIsolation enabled */ public function testValidateInvalidMultiselectValues() { @@ -777,6 +782,7 @@ public function testValidateInvalidMultiselectValues() * @magentoDataFixture Magento/Core/_files/store.php * @magentoDataFixture Magento/Catalog/Model/Layer/Filter/_files/attribute_with_option.php * @magentoDataFixture Magento/ConfigurableProduct/_files/configurable_attribute.php + * @magentoAppIsolation enabled */ public function testProductsWithMultipleStores() { diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_data.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_data.php new file mode 100644 index 0000000000000..86d5916e5446f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_data.php @@ -0,0 +1,62 @@ +create('Magento\Catalog\Model\Product'); + +$customOptions = [ + 1 => [ + 'id' => '1', + 'option_id' => '0', + 'sort_order' => '0', + 'title' => 'Option 1', + 'type' => 'drop_down', + 'is_require' => 1, + 'values' => [ + 1 => ['option_type_id' => -1, 'title' => 'Option 1 Value 1', 'price' => '1.00', 'price_type' => 'fixed'], + 2 => ['option_type_id' => -1, 'title' => 'Option 1 Value 2', 'price' => '2.00', 'price_type' => 'fixed'] + ] + ] +]; + +$productModel->setTypeId( + \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE +)->setId( + 1 +)->setAttributeSetId( + 4 +)->setName( + 'New Product' +)->setSku( + 'simple' +)->setPrice( + 10 +)->setGroupPrice( + [0 => ['website_id' => 0, 'cust_group' => 0, 'price' => 9]] +)->setTierPrice( + [0 => ['website_id' => 0, 'cust_group' => 0, 'price_qty' => 3, 'price' => 8]] +)->setVisibility( + \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH +)->setStatus( + \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED +)->setWebsiteIds( + [1] +)->setCateroryIds( + [] +)->setStockData( + ['qty' => 100, 'is_in_stock' => 1] +)->setCanSaveCustomOptions( + true +)->setProductOptions( + $customOptions +)->setCategoryIds( + [333] +)->setUpSellLinkData( + [$product->getId() => ['position' => 1]] +)->save(); diff --git a/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php b/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php index 70295a3b30957..5700750c355b7 100644 --- a/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php +++ b/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php @@ -8,7 +8,7 @@ class ProductTest extends \PHPUnit_Framework_TestCase { /** - * @var Stub_UnitTest_\Magento\CatalogImportExport\Model\Export\Product + * @var StubProduct|\Magento\CatalogImportExport\Model\Export\Product */ protected $_object; diff --git a/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Export/StubProduct.php b/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Export/StubProduct.php index b17e8a199aa88..5eec23dbd7a85 100644 --- a/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Export/StubProduct.php +++ b/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Export/StubProduct.php @@ -24,6 +24,6 @@ public function __construct() */ public function updateDataWithCategoryColumns(&$dataRow, &$rowCategories, $productId) { - return $this->_updateDataWithCategoryColumns($dataRow, $rowCategories, $productId); + return parent::updateDataWithCategoryColumns($dataRow, $rowCategories, $productId); } } diff --git a/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Import/Product/Validator/MediaTest.php b/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Import/Product/Validator/MediaTest.php new file mode 100644 index 0000000000000..f20a77ac51fad --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Import/Product/Validator/MediaTest.php @@ -0,0 +1,70 @@ +objectManagerHelper = new ObjectManagerHelper($this); + $this->media = $this->objectManagerHelper->getObject( + 'Magento\CatalogImportExport\Model\Import\Product\Validator\Media', + [ + + ] + ); + } + + public function testInit() + { + $result = $this->media->init(); + $this->assertEquals($this->media, $result); + } + + /** + * @param array $data + * @param array $expected + * @dataProvider isMediaValidDataProvider + */ + public function testIsValid($data, $expected) + { + $result = $this->media->isValid($data); + $this->assertEquals($expected['result'], $result); + $messages = $this->media->getMessages(); + $this->assertEquals($expected['messages'], $messages); + } + + /** + * @return array + */ + public function isMediaValidDataProvider() + { + return [ + 'valid' => [ + ['_media_image' => 1, '_media_attribute_id' => 1], + ['result' => true, 'messages' => []], + ], + 'valid2' => [ + ['_media_attribute_id' => 1], + ['result' => true, 'messages' => []], + ], + 'invalid' => [ + ['_media_image' => 1], + ['result' => false,'messages' => [0 => 'mediaDataIsIncomplete']], + ] + ]; + } +} diff --git a/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Import/Product/Validator/TierPriceTest.php b/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Import/Product/Validator/TierPriceTest.php new file mode 100644 index 0000000000000..018c617c1ed86 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Import/Product/Validator/TierPriceTest.php @@ -0,0 +1,191 @@ +groupRepositoryInterface = $this->getMock( + 'Magento\Customer\Model\Resource\GroupRepository', + [], + [], + '', + false + ); + $this->searchCriteriaSearch = $this->getMock('Magento\Framework\Api\SearchCriteria', [], [], '', false); + $this->searchCriteriaBuilder = $this->getMock('Magento\Framework\Api\SearchCriteriaBuilder', [], [], '', false); + $this->searchCriteriaBuilder->expects($this->any())->method('create')->willReturn($this->searchCriteriaSearch); + $this->storeResolver = $this->getMock( + 'Magento\CatalogImportExport\Model\Import\Product\StoreResolver', + [], + [], + '', + false + ); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->tierPrice = $this->objectManagerHelper->getObject( + 'Magento\CatalogImportExport\Model\Import\Product\Validator\TierPrice', + [ + 'groupRepository' => $this->groupRepositoryInterface, + 'searchCriteriaBuilder' => $this->searchCriteriaBuilder, + 'storeResolver' => $this->storeResolver + ] + ); + } + + protected function processInit($groupId) + { + $searchResult = $this->getMock('Magento\Customer\Api\Data\GroupSearchResultsInterface', [], [], '', false); + $this->groupRepositoryInterface->expects($this->once())->method('getList')->willReturn($searchResult); + $group = $this->getMock('Magento\Customer\Model\Data\Group', [], [], '', false); + $group->expects($this->once())->method('getId')->willReturn($groupId); + $searchResult->expects($this->once())->method('getItems')->willReturn([$group]); + return $this->tierPrice->init(); + } + + public function testInit() + { + $result = $this->processInit(3); + $this->assertEquals($this->tierPrice, $result); + } + + /** + * @param array $data + * @param int $groupId + * @param array|null $website + * @param array $expected + * @dataProvider tierPriceDataProvider + */ + public function testIsValid($data, $groupId, $website, $expected) + { + $this->processInit($groupId); + if ($website) { + $this->storeResolver + ->expects($this->any()) + ->method('getWebsiteCodeToId') + ->with($website['id']) + ->willReturn($website['code']); + } + $result = $this->tierPrice->isValid($data); + $this->assertEquals($expected['result'], $result); + $messages = $this->tierPrice->getMessages(); + $this->assertEquals($expected['messages'], $messages); + } + + /** + * @return array + */ + public function tierPriceDataProvider() + { + return [ + 'empty' => [ + [], + 1, + ['id' => 0, 'code' => ''], + ['result' => true, 'messages' => []], + ], + 'valid1' => [ + [ + '_tier_price_website' => 'all', + '_tier_price_customer_group' => '1', + '_tier_price_qty' => '1', + '_tier_price_price' => '1' + ], + 1, + null, + ['result' => true, 'messages' => []], + ], + 'invalidPriceWebsite' => [ + [ + '_tier_price_website' => '1', + '_tier_price_customer_group' => '1', + '_tier_price_qty' => '1', + '_tier_price_price' => '1' + ], + 1, + null, + ['result' => false, 'messages' => [ 0 => 'tierPriceWebsiteInvalid']], + ], + 'invalidIncomplete1' => [ + [ + '_tier_price_qty' => '1' + ], + 1, + null, + ['result' => false, 'messages' => [ 0 => 'tierPriceDataIsIncomplete']], + ], + 'invalidIncomplete2' => [ + [ + '_tier_price_customer_group' => '1' + ], + 1, + null, + ['result' => false, 'messages' => [ 0 => 'tierPriceDataIsIncomplete']], + ], + 'invalidIncomplete3' => [ + [ + '_tier_price_price' => '1' + ], + 1, + null, + ['result' => false, 'messages' => [ 0 => 'tierPriceDataIsIncomplete']], + ], + 'invalidSite' => [ + [ + '_tier_price_website' => '1', + '_tier_price_customer_group' => 'all', + '_tier_price_qty' => '1', + '_tier_price_price' => '1' + ], + 1, + null, + ['result' => false, 'messages' => [ 0 => 'tierPriceWebsiteInvalid']], + ], + 'invalidGroup' => [ + [ + '_tier_price_website' => 'all', + '_tier_price_customer_group' => '1', + '_tier_price_qty' => '1', + '_tier_price_price' => '1' + ], + 2, + null, + ['result' => false, 'messages' => [ 0 => 'tierPriceGroupInvalid']], + ], + 'invalidQty' => [ + [ + '_tier_price_website' => 'all', + '_tier_price_customer_group' => '1', + '_tier_price_qty' => '-1', + '_tier_price_price' => '-1' + ], + 1, + null, + ['result' => false, 'messages' => [ 0 => 'invalidTierPriceOrQty']], + ], + ]; + } +} diff --git a/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Import/Product/ValidatorTest.php b/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Import/Product/ValidatorTest.php new file mode 100644 index 0000000000000..b27f205d0516d --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Import/Product/ValidatorTest.php @@ -0,0 +1,80 @@ +validator1 = $this->getMock( + 'Magento\CatalogImportExport\Model\Import\Product\Validator\Media', + [], + [], + '', + false + ); + $this->validator2 = $this->getMock( + 'Magento\CatalogImportExport\Model\Import\Product\Validator\Category', + [], + [], + '', + false + ); + + $this->validators = [$this->validator1, $this->validator2]; + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->validator = $this->objectManagerHelper->getObject( + 'Magento\CatalogImportExport\Model\Import\Product\Validator', + ['validators' => $this->validators] + ); + } + + public function testIsValidCorrect() + { + $value = 'val'; + $this->validator1->expects($this->once())->method('isValid')->with($value)->willReturn(true); + $this->validator2->expects($this->once())->method('isValid')->with($value)->willReturn(true); + $result = $this->validator->isValid($value); + $this->assertTrue($result); + } + + public function testIsValidIncorrect() + { + $value = 'val'; + $this->validator1->expects($this->once())->method('isValid')->with($value)->willReturn(true); + $this->validator2->expects($this->once())->method('isValid')->with($value)->willReturn(false); + $messages = ['errorMessage']; + $this->validator2->expects($this->once())->method('getMessages')->willReturn($messages); + $result = $this->validator->isValid($value); + $this->assertFalse($result); + $this->assertEquals($messages, $this->validator->getMessages()); + } + + public function testInit() + { + $this->validator1->expects($this->once())->method('init'); + $this->validator2->expects($this->once())->method('init'); + $this->validator->init(); + } +} diff --git a/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php b/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php deleted file mode 100644 index 40175c3ac43a7..0000000000000 --- a/dev/tests/unit/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php +++ /dev/null @@ -1,341 +0,0 @@ -_eavConfig = $this->getMock( - 'Magento\Eav\Model\Config', - ['getEntityType', 'getEntityTypeId'], - [], - '', - false - ); - - $this->_eavConfig->expects( - $this->atLeastOnce() - )->method( - 'getEntityType' - )->with( - $this->equalTo('catalog_product') - )->will( - $this->returnSelf() - ); - $this->_eavConfig->expects($this->atLeastOnce())->method('getEntityTypeId')->will($this->returnValue('1')); - - $this->_optionModel = $this->getMock( - '\Magento\CatalogImportExport\Model\Import\Product\Option', - [], - [], - '', - false - ); - $this->_optionFactory = $this->getMock( - '\Magento\CatalogImportExport\Model\Import\Product\OptionFactory', - ['create'], - [], - '', - false - ); - $this->_optionFactory->expects( - $this->atLeastOnce() - )->method( - 'create' - )->will( - $this->returnValue($this->_optionModel) - ); - - $this->_storeManager = $this->getMock( - '\Magento\Store\Model\StoreManager', - ['getWebsites', 'getStores'], - [], - '', - false - ); - - $this->_storeManager->expects($this->atLeastOnce())->method('getWebsites')->will($this->returnValue([])); - $this->_storeManager->expects($this->atLeastOnce())->method('getStores')->will($this->returnValue([])); - - $this->_setCol = $this->getMock( - '\Magento\Eav\Model\Resource\Entity\Attribute\Set\Collection', - ['setEntityTypeFilter'], - [], - '', - false - ); - $this->_setCol->expects( - $this->atLeastOnce() - )->method( - 'setEntityTypeFilter' - )->with( - $this->equalTo('1') - )->will( - $this->returnValue([]) - ); - - $this->_setColFactory = $this->getMock( - '\Magento\Eav\Model\Resource\Entity\Attribute\Set\CollectionFactory', - ['create'], - [], - '', - false - ); - $this->_setColFactory->expects( - $this->atLeastOnce() - )->method( - 'create' - )->will( - $this->returnValue($this->_setCol) - ); - - $this->_importConfig = $this->getMock( - '\Magento\ImportExport\Model\Import\Config', - ['getEntityTypes'], - [], - '', - false - ); - $this->_importConfig->expects( - $this->atLeastOnce() - )->method( - 'getEntityTypes' - )->with( - 'catalog_product' - )->will( - $this->returnValue([]) - ); - - $this->_categoryCol = $this->getMock( - '\Magento\Catalog\Model\Resource\Category\Collection', - ['addNameToResult'], - [], - '', - false - ); - $this->_categoryCol->expects( - $this->atLeastOnce() - )->method( - 'addNameToResult' - )->will( - $this->returnValue([]) - ); - - $this->_categoryColFactory = $this->getMock( - '\Magento\Catalog\Model\Resource\Category\CollectionFactory', - ['create'], - [], - '', - false - ); - $this->_categoryColFactory->expects( - $this->atLeastOnce() - )->method( - 'create' - )->will( - $this->returnValue($this->_categoryCol) - ); - - $this->_product = $this->getMock( - '\Magento\Catalog\Model\Product', - ['getProductEntitiesInfo', '__wakeup'], - [], - '', - false - ); - $this->_product->expects( - $this->atLeastOnce() - )->method( - 'getProductEntitiesInfo' - )->with( - $this->equalTo(['entity_id', 'type_id', 'attribute_set_id', 'sku']) - )->will( - $this->returnValue([]) - ); - - $this->_productFactory = $this->getMock( - '\Magento\Catalog\Model\ProductFactory', - ['create'], - [], - '', - false - ); - $this->_productFactory->expects( - $this->atLeastOnce() - )->method( - 'create' - )->will( - $this->returnValue($this->_product) - ); - - $groupRepository = $this->getMockBuilder('Magento\Customer\Api\GroupRepositoryInterface') - ->setMethods(['getList']) - ->getMockForAbstractClass(); - $searchResults = $this->getMockBuilder('Magento\Customer\Api\Data\GroupSearchResultsInterface') - ->setMethods(['getItems']) - ->getMockForAbstractClass(); - $searchResults->expects($this->once()) - ->method('getItems') - ->will($this->returnValue([])); - $groupRepository->expects($this->once()) - ->method('getList') - ->will($this->returnValue($searchResults)); - $searchCriteriaBuilder = $this->getMockBuilder('Magento\Framework\Api\SearchCriteriaBuilder') - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $searchCriteria = $this->getMockBuilder('Magento\Framework\Api\SearchCriteriaInterface') - ->getMockForAbstractClass(); - $searchCriteriaBuilder->expects($this->once()) - ->method('create') - ->will($this->returnValue($searchCriteria)); - - $objectManager = new \Magento\TestFramework\Helper\ObjectManager($this); - - $this->_model = $objectManager->getObject( - 'Magento\CatalogImportExport\Model\Import\Product', - [ - 'config' => $this->_eavConfig, - 'optionFactory' => $this->_optionFactory, - 'storeManager' => $this->_storeManager, - 'setColFactory' => $this->_setColFactory, - 'importConfig' => $this->_importConfig, - 'categoryColFactory' => $this->_categoryColFactory, - 'productFactory' => $this->_productFactory, - 'groupRepository' => $groupRepository, - 'searchCriteriaBuilder' => $searchCriteriaBuilder - ] - ); - } - - protected function tearDown() - { - unset($this->_model); - } - - /** - * @param array $data - * @param array $expected - * @dataProvider isMediaValidDataProvider - */ - public function testIsMediaValid($data, $expected) - { - $method = new \ReflectionMethod('\Magento\CatalogImportExport\Model\Import\Product', '_isMediaValid'); - $method->setAccessible(true); - - $this->assertEquals($expected['method_return'], $method->invoke($this->_model, $data, 1)); - - $errors = new \ReflectionProperty('\Magento\CatalogImportExport\Model\Import\Product', '_errors'); - $errors->setAccessible(true); - $this->assertEquals($expected['_errors'], $errors->getValue($this->_model)); - - $invalidRows = new \ReflectionProperty('\Magento\CatalogImportExport\Model\Import\Product', '_invalidRows'); - $invalidRows->setAccessible(true); - $this->assertEquals($expected['_invalidRows'], $invalidRows->getValue($this->_model)); - - $errorsCount = new \ReflectionProperty('\Magento\CatalogImportExport\Model\Import\Product', '_errorsCount'); - $errorsCount->setAccessible(true); - $this->assertEquals($expected['_errorsCount'], $errorsCount->getValue($this->_model)); - } - - /** - * @return array - */ - public function isMediaValidDataProvider() - { - return [ - 'valid' => [ - ['_media_image' => 1, '_media_attribute_id' => 1], - ['method_return' => true, '_errors' => [], '_invalidRows' => [], '_errorsCount' => 0], - ], - 'valid2' => [ - ['_media_attribute_id' => 1], - ['method_return' => true, '_errors' => [], '_invalidRows' => [], '_errorsCount' => 0], - ], - 'invalid' => [ - ['_media_image' => 1], - [ - 'method_return' => false, - '_errors' => ['mediaDataIsIncomplete' => [[2, null]]], - '_invalidRows' => [1 => 1], - '_errorsCount' => 1 - ], - ] - ]; - } -} diff --git a/dev/tests/unit/testsuite/Magento/GoogleShopping/Helper/DataTest.php b/dev/tests/unit/testsuite/Magento/GoogleShopping/Helper/DataTest.php new file mode 100644 index 0000000000000..f005bf9c10912 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/GoogleShopping/Helper/DataTest.php @@ -0,0 +1,125 @@ +context = $this->getMock('Magento\Framework\App\Helper\Context', [], [], '', false); + $this->string = $this->getMock('Magento\Framework\Stdlib\String'); + $this->storeManagerInterface = $this->getMock('Magento\Store\Model\StoreManager', ['getStore'], [], '', false); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->data = $this->objectManagerHelper->getObject( + 'Magento\GoogleShopping\Helper\Data', + [ + 'context' => $this->context, + 'string' => $this->string, + 'storeManager' => $this->storeManagerInterface + ] + ); + } + + public function testBuildContentProductId() + { + $result = $this->data->buildContentProductId(2, 5); + $this->assertEquals("2_5", $result); + } + + public function gdataMessageDataProvider() + { + return [ + [ + 'message' => 'Some string', + 'expectedResult' => 'Some string' + ], + [ + 'message' => 'insidetagoutsidetag', + 'expectedResult' => '' + ], + [ + 'message' => "multiline\n\nmessage", + 'expectedResult' => 'multiline. message' + ], + [ + 'message' => '>', + 'expectedResult' => 'Reason: anyreason. Type: anutype' + ] + ]; + } + + /** + * @param string $message + * @param string $expectedResult + * + * @dataProvider gdataMessageDataProvider + */ + public function testParseGdataExceptionMessage($message, $expectedResult) + { + $result = $this->data->parseGdataExceptionMessage($message); + $this->assertEquals($expectedResult, $result); + } + + public function nameDataProvider() + { + return [ + ['name' => 'somename', 'normalizedName' => 'somename'], + ['name' => 'so/m e\name', 'normalizedName' => 'so/m_e\name'], + ['name' => '', 'normalizedName' => ''] + ]; + } + + /** + * @param string $name + * @param string $normalizedName + * + * @dataProvider nameDataProvider + */ + public function testNormalizeName($name, $normalizedName) + { + $resultingName = $this->data->normalizeName($name); + $this->assertEquals($normalizedName, $resultingName); + } + + public function testParseGdataExceptionMessageWithProduct() + { + $message = "some message\n\nother message"; + $product = $this->getMock('Magento\Catalog\Model\Product', ['getName', 'getStoreId'], [], '', false); + $product->expects($this->any())->method('getName')->will($this->returnValue("product name")); + $storeId = 1; + $product->expects($this->any())->method('getStoreId')->will($this->returnValue($storeId)); + $store = $this->getMock('Magento\Store\Model\Store', [], [], '', false); + $this->storeManagerInterface->expects($this->any())->method('getStore')->with($storeId)->will( + $this->returnValue($store) + ); + $store->expects($this->any())->method('getName')->will($this->returnValue('store name')); + $result = $this->data->parseGdataExceptionMessage($message, $product); + $this->assertEquals( + "some message for product 'product name' (in 'store name' store). " . + "other message for product 'product name' (in 'store name' store)", + $result + ); + } +} diff --git a/dev/tests/unit/testsuite/Magento/GoogleShopping/Model/MassOperationsTest.php b/dev/tests/unit/testsuite/Magento/GoogleShopping/Model/MassOperationsTest.php index 839a228c4ac51..fd30bf370848c 100644 --- a/dev/tests/unit/testsuite/Magento/GoogleShopping/Model/MassOperationsTest.php +++ b/dev/tests/unit/testsuite/Magento/GoogleShopping/Model/MassOperationsTest.php @@ -23,7 +23,7 @@ class MassOperationsTest extends \PHPUnit_Framework_TestCase protected $itemFactory; /** @var \PHPUnit_Framework_MockObject_MockObject */ - protected $productFactory; + protected $productRepository; /** @var \Magento\Framework\Notification\NotifierInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $notificationInterface; @@ -40,19 +40,29 @@ class MassOperationsTest extends \PHPUnit_Framework_TestCase /** @var \Magento\GoogleShopping\Helper\Category|\PHPUnit_Framework_MockObject_MockObject */ protected $googleShoppingCategoryHelper; + /** @var \Magento\GoogleShopping\Model\Flag|\PHPUnit_Framework_MockObject_MockObject */ + protected $flag; + protected function setUp() { $this->collectionFactory = $this->getMockBuilder( 'Magento\GoogleShopping\Model\Resource\Item\CollectionFactory' )->disableOriginalConstructor()->setMethods(['create'])->getMock(); - $this->itemFactory = $this->getMock('Magento\GoogleShopping\Model\ItemFactory', [], [], '', false); - $this->productFactory = $this->getMock('Magento\Catalog\Model\ProductFactory', [], [], '', false); + $this->itemFactory = $this->getMock('Magento\GoogleShopping\Model\ItemFactory', ['create'], [], '', false); + $this->productRepository = $this->getMock( + '\Magento\Catalog\Api\ProductRepositoryInterface', + ['save', 'get', 'delete', 'getById', 'deleteById', 'getList'], + [], + '', + false + ); $this->notificationInterface = $this->getMock('Magento\Framework\Notification\NotifierInterface'); $this->storeManagerInterface = $this->getMock('Magento\Store\Model\StoreManagerInterface'); $this->logger = $this->getMock('Psr\Log\LoggerInterface'); $this->googleShoppingHelper = $this->getMock('Magento\GoogleShopping\Helper\Data', [], [], '', false); $this->googleShoppingCategoryHelper = $this->getMock('Magento\GoogleShopping\Helper\Category'); + $this->flag = $this->getMock('Magento\GoogleShopping\Model\Flag', [], [], '', false); $this->objectManagerHelper = new ObjectManagerHelper($this); $this->massOperations = $this->objectManagerHelper->getObject( @@ -60,7 +70,7 @@ protected function setUp() [ 'collectionFactory' => $this->collectionFactory, 'itemFactory' => $this->itemFactory, - 'productFactory' => $this->productFactory, + 'productRepository' => $this->productRepository, 'notifier' => $this->notificationInterface, 'storeManager' => $this->storeManagerInterface, 'logger' => $this->logger, @@ -70,6 +80,56 @@ protected function setUp() ); } + public function testAddProducts() + { + $products = ['1','2']; + $product = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false); + $this->productRepository->expects($this->exactly(2))->method('getById')->will($this->returnValue($product)); + $googleShoppingItem = $this->getMock('\Magento\GoogleShopping\Model\Item', [], [], '', false); + $googleShoppingItem->expects($this->exactly(2))->method('insertItem')->will($this->returnSelf()); + $this->itemFactory->expects($this->exactly(2))->method('create')->will($this->returnValue($googleShoppingItem)); + $this->flag->expects($this->any())->method('isExpired')->will($this->returnValue(false)); + $this->massOperations->setFlag($this->flag); + $this->assertEquals($this->massOperations->addProducts($products, 1), $this->massOperations); + } + + public function testAddProductsExpiredFlag() + { + $products = ['1','2']; + $this->flag->expects($this->exactly(2))->method('isExpired')->will($this->returnValue(true)); + $this->massOperations->setFlag($this->flag); + $this->massOperations->addProducts($products, 1); + } + + /** + * @dataProvider dataAddProductsExceptions + * @param string $exception + */ + public function testAddProductsExceptions($exception) + { + $products = ['1']; + $this->flag->expects($this->any())->method('isExpired')->will($this->returnValue(false)); + $product = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false); + $this->productRepository->expects($this->once())->method('getById')->will($this->returnValue($product)); + $this->itemFactory->expects($this->once())->method('create')->will($this->throwException(new $exception)); + $this->massOperations->setFlag($this->flag); + $this->massOperations->addProducts($products, 1); + } + + /** + * @return array + */ + public function dataAddProductsExceptions() + { + return [ + ['\Magento\Framework\Exception\NoSuchEntityException'], + ['\Zend_Gdata_App_Exception'], + ['\Zend_Db_Statement_Exception'], + ['\Magento\Framework\Model\Exception'], + ['\Exception'] + ]; + } + public function testSynchronizeItems() { $collection = $this->getMockBuilder('Magento\GoogleShopping\Model\Resource\Item\Collection') diff --git a/dev/tests/unit/testsuite/Magento/GroupedImportExport/Model/Import/Product/Type/Grouped/LinksTest.php b/dev/tests/unit/testsuite/Magento/GroupedImportExport/Model/Import/Product/Type/Grouped/LinksTest.php new file mode 100644 index 0000000000000..321e974ccb02f --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/GroupedImportExport/Model/Import/Product/Type/Grouped/LinksTest.php @@ -0,0 +1,169 @@ +link = $this->getMock('Magento\Catalog\Model\Resource\Product\Link', [], [], '', false); + $this->connection = $this->getMock('Magento\Framework\DB\Adapter\Pdo\Mysql', [], [], '', false); + $this->resource = $this->getMock('Magento\Framework\App\Resource', [], [], '', false); + $this->resource->expects($this->once())->method('getConnection')->with('write')->will( + $this->returnValue($this->connection) + ); + + $this->import = $this->getMock('Magento\ImportExport\Model\Import', [], [], '', false); + $this->importFactory = $this->getMock('Magento\ImportExport\Model\ImportFactory', ['create'], [], '', false); + $this->importFactory->expects($this->any())->method('create')->will($this->returnValue($this->import)); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->links = $this->objectManagerHelper->getObject( + 'Magento\GroupedImportExport\Model\Import\Product\Type\Grouped\Links', + [ + 'productLink' => $this->link, + 'resource' => $this->resource, + 'importFactory' => $this->importFactory + ] + ); + } + + public function linksDataProvider() + { + return [ + [ + 'linksData' => [ + 'product_ids' => [1, 2], + 'relation' => [], + 'attr_product_ids' => [] + ] + ] + ]; + } + + /** + * @param array $linksData + * + * @dataProvider linksDataProvider + */ + public function testSaveLinksDataNoProductsAttrs($linksData) + { + $this->processBehaviorGetter('append'); + $attributes = $this->attributesDataProvider(); + $this->processAttributeGetter($attributes[2]['dbAttributes']); + $this->connection->expects($this->exactly(2))->method('insertOnDuplicate'); + $this->links->saveLinksData($linksData); + } + + /** + * @param array $linksData + * + * @dataProvider linksDataProvider + */ + public function testSaveLinksDataWithProductsAttrs($linksData) + { + $linksData['attr_product_ids'] = [12 => true, 16 => true]; + $linksData['position'] = [4 => 6]; + $linksData['qty'] = [9 => 3]; + $this->processBehaviorGetter('append'); + $select = $this->getMock('Magento\Framework\DB\Select', [], [], '', false); + $this->connection->expects($this->any())->method('select')->will($this->returnValue($select)); + $select->expects($this->any())->method('from')->will($this->returnSelf()); + $select->expects($this->any())->method('where')->will($this->returnSelf()); + $this->connection->expects($this->once())->method('fetchAll')->with($select)->will($this->returnValue([])); + $this->connection->expects($this->once())->method('fetchPairs')->with($select)->will( + $this->returnValue([]) + ); + $this->connection->expects($this->exactly(4))->method('insertOnDuplicate'); + $this->links->saveLinksData($linksData); + } + + public function attributesDataProvider() + { + return [ + [ + 'dbAttributes' => [], + 'returnedAttibutes' => null + ], + [ + 'dbAttributes' => [ + ['code' => 2, 'id' => 6, 'type' => 'sometable'] + ], + 'returnedAttibutes' => [ + 2 => ['id' => 6, 'table' => 'table_name'] + ] + ], + [ + 'dbAttributes' => [ + ['code' => 8, 'id' => 11, 'type' => 'sometable1'], + ['code' => 4, 'id' => 7, 'type' => 'sometable2'] + ], + 'returnedAttibutes' => [ + 4 => ['id' => 7, 'table' => 'table_name'], + 8 => ['id' => 11, 'table' => 'table_name'] + ] + ] + ]; + } + + protected function processAttributeGetter($dbAttributes) + { + $select = $this->getMock('Magento\Framework\DB\Select', [], [], '', false); + $this->connection->expects($this->once())->method('select')->will($this->returnValue($select)); + $select->expects($this->once())->method('from')->will($this->returnSelf()); + $select->expects($this->once())->method('where')->will($this->returnSelf()); + $this->connection->expects($this->once())->method('fetchAll')->with($select)->will( + $this->returnValue($dbAttributes) + ); + $this->link->expects($this->any())->method('getAttributeTypeTable')->will( + $this->returnValue('table_name') + ); + } + + /** + * @param array $dbAttributes + * @param array $returnedAttibutes + * + * @dataProvider attributesDataProvider + */ + public function testGetAttributes($dbAttributes, $returnedAttibutes) + { + $this->processAttributeGetter($dbAttributes); + $actualAttributes = $this->links->getAttributes(); + $this->assertEquals($returnedAttibutes, $actualAttributes); + } + + protected function processBehaviorGetter($behavior) + { + $dataSource = $this->getMock('Magento\ImportExport\Model\Resource\Import\Data', [], [], '', false); + $dataSource->expects($this->once())->method('getBehavior')->will($this->returnValue($behavior)); + $this->import->expects($this->once())->method('getDataSourceModel')->will($this->returnValue($dataSource)); + } +} diff --git a/dev/tests/unit/testsuite/Magento/GroupedImportExport/Model/Import/Product/Type/GroupedTest.php b/dev/tests/unit/testsuite/Magento/GroupedImportExport/Model/Import/Product/Type/GroupedTest.php new file mode 100644 index 0000000000000..70d2bcf83aa4c --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/GroupedImportExport/Model/Import/Product/Type/GroupedTest.php @@ -0,0 +1,139 @@ +setCollectionFactory = $this->getMock( + 'Magento\Eav\Model\Resource\Entity\Attribute\Set\CollectionFactory', + ['create'], + [], + '', + false + ); + $this->setCollection = $this->getMock( + 'Magento\Eav\Model\Resource\Entity\Attribute\Set\Collection', + ['setEntityTypeFilter'], + [], + '', + false + ); + $this->setCollectionFactory->expects($this->any())->method('create')->will( + $this->returnValue($this->setCollection) + ); + $this->setCollection->expects($this->any()) + ->method('setEntityTypeFilter') + ->will($this->returnValue([])); + + $this->attrCollectionFactory = $this->getMock( + 'Magento\Catalog\Model\Resource\Product\Attribute\CollectionFactory', + [], + [], + '', + false + ); + $this->entityModel = $this->getMock( + 'Magento\CatalogImportExport\Model\Import\Product', + ['getNewSku', 'getNextBunch', 'isRowAllowedToImport', 'getRowScope'], + [], + '', + false + ); + $this->params = [ + 0 => $this->entityModel, + 1 => 'grouped' + ]; + $this->links = $this->getMock( + 'Magento\GroupedImportExport\Model\Import\Product\Type\Grouped\Links', + [], + [], + '', + false + ); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->grouped = $this->objectManagerHelper->getObject( + 'Magento\GroupedImportExport\Model\Import\Product\Type\Grouped', + [ + 'attrSetColFac' => $this->setCollectionFactory, + 'prodAttrColFac' => $this->attrCollectionFactory, + 'params' => $this->params, + 'links' => $this->links + ] + ); + } + + public function testSaveData() + { + $associatedSku = 'sku_assoc'; + $productSku = 'productSku'; + $this->entityModel->expects($this->once())->method('getNewSku')->will($this->returnValue([ + $associatedSku => ['entity_id' => 1], + $productSku => ['entity_id' => 2] + ])); + $attributes = ['position' => ['id' => 0], 'qty' => ['id' => 0]]; + $this->links->expects($this->once())->method('getAttributes')->will($this->returnValue($attributes)); + + $bunch = [[ + '_associated_sku' => $associatedSku, + 'sku' => $productSku, + '_type' => 'grouped', + '_associated_default_qty' => 4, + '_associated_position' => 6 + ]]; + $this->entityModel->expects($this->at(0))->method('getNextBunch')->will($this->returnValue($bunch)); + $this->entityModel->expects($this->at(1))->method('getNextBunch')->will($this->returnValue($bunch)); + $this->entityModel->expects($this->any())->method('isRowAllowedToImport')->will($this->returnValue(true)); + $this->entityModel->expects($this->any())->method('getRowScope')->will($this->returnValue( + \Magento\CatalogImportExport\Model\Import\Product::SCOPE_DEFAULT + )); + + $this->links->expects($this->once())->method("saveLinksData"); + $this->grouped->saveData(); + } +} diff --git a/dev/tests/unit/testsuite/Magento/Review/Block/Adminhtml/Rating/Edit/Tab/FormTest.php b/dev/tests/unit/testsuite/Magento/Review/Block/Adminhtml/Rating/Edit/Tab/FormTest.php new file mode 100644 index 0000000000000..2c9df709f9ff0 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Review/Block/Adminhtml/Rating/Edit/Tab/FormTest.php @@ -0,0 +1,210 @@ +ratingOptionCollection = $this->getMock( + '\Magento\Review\Model\Resource\Rating\Option\Collection', + [], + [], + '', + false + ); + $this->element = $this->getMock( + '\Magento\Framework\Data\Form\Element\Text', + ['setValue', 'setIsChecked'], + [], + '', + false + ); + $this->session = $this->getMock( + '\Magento\Framework\Session\Generic', + ['getRatingData', 'setRatingData'], + [], + '', + false + ); + $this->rating = $this->getMock('\Magento\Review\Model\Rating', ['getId', 'getRatingCodes'], [], '', false); + $this->optionRating = $this->getMock('\Magento\Review\Model\Rating\Option', [], [], '', false); + $this->store = $this->getMock('\Magento\Store\Model\Store', [], [], '', false); + $this->form = $this->getMock('\Magento\Framework\Data\Form', [], [], '', false); + $this->directoryReadInterface = $this->getMock('\Magento\Framework\Filesystem\Directory\ReadInterface'); + $this->registry = $this->getMock('\Magento\Framework\Registry'); + $this->formFactory = $this->getMock('\Magento\Framework\Data\FormFactory', [], [], '', false); + $this->optionFactory = $this->getMock('\Magento\Review\Model\Rating\OptionFactory', ['create'], [], '', false); + $this->systemStore = $this->getMock('\Magento\Store\Model\System\Store', [], [], '', false); + $this->viewFileSystem = $this->getMock('\Magento\Framework\View\FileSystem', [], [], '', false); + $this->fileSystem = $this->getMock('\Magento\Framework\Filesystem', ['getDirectoryRead'], [], '', false); + + $this->rating->expects($this->any())->method('getId')->will($this->returnValue('1')); + $this->ratingOptionCollection->expects($this->any())->method('addRatingFilter')->will($this->returnSelf()); + $this->ratingOptionCollection->expects($this->any())->method('load')->will($this->returnSelf()); + $this->ratingOptionCollection->expects($this->any())->method('getItems') + ->will($this->returnValue([$this->optionRating])); + $this->optionRating->expects($this->any())->method('getResourceCollection') + ->will($this->returnValue($this->ratingOptionCollection)); + $this->store->expects($this->any())->method('getId')->will($this->returnValue('0')); + $this->store->expects($this->any())->method('getName')->will($this->returnValue('store_name')); + $this->element->expects($this->any())->method('setValue')->will($this->returnSelf()); + $this->element->expects($this->any())->method('setIsChecked')->will($this->returnSelf()); + $this->form->expects($this->any())->method('setForm')->will($this->returnSelf()); + $this->form->expects($this->any())->method('addFieldset')->will($this->returnSelf()); + $this->form->expects($this->any())->method('addField')->will($this->returnSelf()); + $this->form->expects($this->any())->method('setRenderer')->will($this->returnSelf()); + $this->optionFactory->expects($this->any())->method('create')->will($this->returnValue($this->optionRating)); + $this->systemStore->expects($this->any())->method('getStoreCollection') + ->will($this->returnValue(['0' => $this->store])); + $this->formFactory->expects($this->any())->method('create')->will($this->returnValue($this->form)); + $this->viewFileSystem->expects($this->any())->method('getTemplateFileName') + ->will($this->returnValue('template_file_name.html')); + $this->fileSystem->expects($this->any())->method('getDirectoryRead') + ->will($this->returnValue($this->directoryReadInterface)); + + $objectManagerHelper = new ObjectManagerHelper($this); + $this->block = $objectManagerHelper->getObject( + 'Magento\Review\Block\Adminhtml\Rating\Edit\Tab\Form', + [ + 'registry' => $this->registry, + 'formFactory' => $this->formFactory, + 'optionFactory' => $this->optionFactory, + 'systemStore' => $this->systemStore, + 'session' => $this->session, + 'viewFileSystem' => $this->viewFileSystem, + 'filesystem' => $this->fileSystem, + ] + ); + } + + public function testToHtmlSessionRatingData() + { + $this->registry->expects($this->any())->method('registry')->will($this->returnValue($this->rating)); + $this->form->expects($this->at(7))->method('getElement')->will($this->returnValue($this->element)); + $this->form->expects($this->at(13))->method('getElement')->will($this->returnValue($this->element)); + $this->form->expects($this->at(16))->method('getElement')->will($this->returnValue($this->element)); + $this->form->expects($this->at(17))->method('getElement')->will($this->returnValue($this->element)); + $this->form->expects($this->any())->method('getElement')->will($this->returnValue(false)); + $ratingCodes = ['rating_codes' => ['0' => 'rating_code']]; + $this->session->expects($this->any())->method('getRatingData')->will($this->returnValue($ratingCodes)); + $this->session->expects($this->any())->method('setRatingData')->will($this->returnSelf()); + $this->block->toHtml(); + } + + public function testToHtmlCoreRegistryRatingData() + { + $this->registry->expects($this->any())->method('registry')->will($this->returnValue($this->rating)); + $this->form->expects($this->at(7))->method('getElement')->will($this->returnValue($this->element)); + $this->form->expects($this->at(13))->method('getElement')->will($this->returnValue($this->element)); + $this->form->expects($this->at(16))->method('getElement')->will($this->returnValue($this->element)); + $this->form->expects($this->at(17))->method('getElement')->will($this->returnValue($this->element)); + $this->form->expects($this->any())->method('getElement')->will($this->returnValue(false)); + $this->session->expects($this->any())->method('getRatingData')->will($this->returnValue(false)); + $ratingCodes = ['rating_codes' => ['0' => 'rating_code']]; + $this->rating->expects($this->any())->method('getRatingCodes')->will($this->returnValue($ratingCodes)); + $this->block->toHtml(); + } + + public function testToHtmlWithoutRatingData() + { + $this->registry->expects($this->any())->method('registry')->will($this->returnValue(false)); + $this->systemStore->expects($this->any())->method('getStoreCollection') + ->will($this->returnValue(['0' => $this->store])); + $this->formFactory->expects($this->any())->method('create')->will($this->returnValue($this->form)); + $this->viewFileSystem->expects($this->any())->method('getTemplateFileName') + ->will($this->returnValue('template_file_name.html')); + $this->fileSystem->expects($this->any())->method('getDirectoryRead') + ->will($this->returnValue($this->directoryReadInterface)); + $this->block->toHtml(); + } +} diff --git a/dev/tests/unit/testsuite/Magento/Review/Controller/Product/PostTest.php b/dev/tests/unit/testsuite/Magento/Review/Controller/Product/PostTest.php new file mode 100644 index 0000000000000..4644157c0f9ee --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Review/Controller/Product/PostTest.php @@ -0,0 +1,288 @@ +redirect = $this->getMock('\Magento\Framework\App\Response\RedirectInterface'); + $this->request = $this->getMock('\Magento\Framework\App\Request\Http', ['getParam'], [], '', false); + $this->response = $this->getMock('\Magento\Framework\App\Response\Http', ['setRedirect'], [], '', false); + $this->formKeyValidator = $this->getMock( + '\Magento\Core\App\Action\FormKeyValidator', + ['validate'], + [], + '', + false + ); + $this->reviewSession = $this->getMock( + '\Magento\Framework\Session\Generic', + ['getFormData', 'getRedirectUrl'], + [], + '', + false + ); + $this->eventManager = $this->getMock('\Magento\Framework\Event\ManagerInterface'); + $this->productRepository = $this->getMock('\Magento\Catalog\Api\ProductRepositoryInterface'); + $this->coreRegistry = $this->getMock('\Magento\Framework\Registry'); + $this->review = $this->getMock( + '\Magento\Review\Model\Review', + ['setData', 'validate', 'setEntityId', 'getEntityIdByCode', 'setEntityPkValue', 'setStatusId', + 'setCustomerId', 'setStoreId', 'setStores', 'save', 'getId', 'aggregate'], + [], + '', + false, + false + ); + $reviewFactory = $this->getMock( + '\Magento\Review\Model\ReviewFactory', + ['create'], + [], + '', + false, + false + ); + $reviewFactory->expects($this->once())->method('create')->will($this->returnValue($this->review)); + $this->customerSession = $this->getMock( + '\Magento\Customer\Model\Session', + ['getCustomerId'], + [], + '', + false, + false + ); + $this->rating = $this->getMock( + '\Magento\Review\Model\Rating', + ['setRatingId', 'setReviewId', 'setCustomerId', 'addOptionVote'], + [], + '', + false, + false + ); + $ratingFactory = $this->getMock( + '\Magento\Review\Model\RatingFactory', + ['create'], + [], + '', + false, + false + ); + $ratingFactory->expects($this->once())->method('create')->will($this->returnValue($this->rating)); + $this->messageManager = $this->getMock('\Magento\Framework\Message\ManagerInterface'); + + $this->store = $this->getMock('\Magento\Store\Model\Store', ['getId'], [], '', false); + $storeManager = $this->getMockForAbstractClass('\Magento\Store\Model\StoreManagerInterface'); + $storeManager->expects($this->any())->method('getStore')->will($this->returnValue($this->store)); + $this->model = (new \Magento\TestFramework\Helper\ObjectManager($this)) + ->getObject( + '\Magento\Review\Controller\Product\Post', + [ + 'request' => $this->request, + 'response' => $this->response, + 'redirect' => $this->redirect, + 'formKeyValidator' => $this->formKeyValidator, + 'reviewSession' => $this->reviewSession, + 'eventManager' => $this->eventManager, + 'productRepository' => $this->productRepository, + 'coreRegistry' => $this->coreRegistry, + 'reviewFactory' => $reviewFactory, + 'customerSession' => $this->customerSession, + 'ratingFactory' => $ratingFactory, + 'storeManager' => $storeManager, + 'messageManager' => $this->messageManager, + ] + ); + } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testExecute() + { + $ratingsData = ['ratings' => [1 => 1]]; + $productId = 1; + $customerId = 1; + $storeId = 1; + $reviewId = 1; + $redirectUrl = 'url'; + $this->formKeyValidator->expects($this->any())->method('validate') + ->with($this->request) + ->will($this->returnValue(true)); + $this->reviewSession->expects($this->any())->method('getFormData') + ->with(true) + ->will($this->returnValue($ratingsData)); + $this->eventManager->expects($this->at(0))->method('dispatch') + ->with('review_controller_product_init_before', ['controller_action' => $this->model]) + ->will($this->returnSelf()); + $this->request->expects($this->at(0))->method('getParam') + ->with('category', false) + ->will($this->returnValue(false)); + $this->request->expects($this->at(1))->method('getParam') + ->with('id') + ->will($this->returnValue(1)); + $product = $this->getMock( + 'Magento\Catalog\Model\Product', + ['__wakeup', 'isVisibleInCatalog', 'isVisibleInSiteVisibility', 'getId'], + [], + '', + false + ); + $product->expects($this->once()) + ->method('isVisibleInCatalog') + ->will($this->returnValue(true)); + $product->expects($this->once()) + ->method('isVisibleInSiteVisibility') + ->will($this->returnValue(true)); + $this->productRepository->expects($this->any())->method('getById') + ->with(1) + ->will($this->returnValue($product)); + $this->coreRegistry->expects($this->at(0))->method('register') + ->with('current_product', $product) + ->will($this->returnSelf()); + $this->coreRegistry->expects($this->at(1))->method('register') + ->with('product', $product) + ->will($this->returnSelf()); + $this->eventManager->expects($this->at(1))->method('dispatch') + ->with('review_controller_product_init', ['product' => $product]) + ->will($this->returnSelf()); + $this->eventManager->expects($this->at(2))->method('dispatch') + ->with('review_controller_product_init_after', ['product' => $product, 'controller_action' => $this->model]) + ->will($this->returnSelf()); + $this->review->expects($this->once())->method('setData') + ->with($ratingsData) + ->will($this->returnSelf()); + $this->review->expects($this->once())->method('validate') + ->will($this->returnValue(true)); + $this->review->expects($this->once())->method('getEntityIdByCode') + ->with(\Magento\Review\Model\Review::ENTITY_PRODUCT_CODE) + ->will($this->returnValue(1)); + $this->review->expects($this->once())->method('setEntityId') + ->with(1) + ->will($this->returnSelf()); + $product->expects($this->exactly(2)) + ->method('getId') + ->will($this->returnValue($productId)); + $this->review->expects($this->once())->method('setEntityPkValue') + ->with($productId) + ->will($this->returnSelf()); + $this->review->expects($this->once())->method('setStatusId') + ->with(\Magento\Review\Model\Review::STATUS_PENDING) + ->will($this->returnSelf()); + $this->customerSession->expects($this->exactly(2))->method('getCustomerId') + ->will($this->returnValue($customerId)); + $this->review->expects($this->once())->method('setCustomerId')->with($customerId)->will($this->returnSelf()); + $this->store->expects($this->exactly(2))->method('getId') + ->will($this->returnValue($storeId)); + $this->review->expects($this->once())->method('setStoreId') + ->with($storeId) + ->will($this->returnSelf()); + $this->review->expects($this->once())->method('setStores') + ->with([$storeId]) + ->will($this->returnSelf()); + $this->review->expects($this->once())->method('save') + ->will($this->returnSelf()); + $this->rating->expects($this->once())->method('setRatingId') + ->with(1) + ->will($this->returnSelf()); + $this->review->expects($this->once())->method('getId') + ->will($this->returnValue($reviewId)); + $this->rating->expects($this->once())->method('setReviewId') + ->with($reviewId) + ->will($this->returnSelf()); + $this->rating->expects($this->once())->method('setCustomerId') + ->with($customerId) + ->will($this->returnSelf()); + $this->rating->expects($this->once())->method('addOptionVote') + ->with(1, $productId) + ->will($this->returnSelf()); + $this->review->expects($this->once())->method('aggregate') + ->will($this->returnSelf()); + $this->messageManager->expects($this->once())->method('addSuccess') + ->with('Your review has been accepted for moderation.') + ->will($this->returnSelf()); + $this->reviewSession->expects($this->once())->method('getRedirectUrl') + ->with(true) + ->will($this->returnValue($redirectUrl)); + $this->response->expects($this->once())->method('setRedirect') + ->with($redirectUrl) + ->will($this->returnSelf()); + $this->model->execute(); + } +} diff --git a/dev/tests/unit/testsuite/Magento/Review/Model/Resource/Review/Product/CollectionTest.php b/dev/tests/unit/testsuite/Magento/Review/Model/Resource/Review/Product/CollectionTest.php new file mode 100644 index 0000000000000..ce455c7886c99 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Review/Model/Resource/Review/Product/CollectionTest.php @@ -0,0 +1,179 @@ +getMock('\Magento\Eav\Model\Entity\Attribute\AbstractAttribute', null, [], '', false); + $eavConfig = $this->getMock('\Magento\Eav\Model\Config', ['getCollectionAttribute'], [], '', false); + $eavConfig->expects($this->any())->method('getCollectionAttribute')->will($this->returnValue($attribute)); + $this->dbSelect = $this->getMock('Magento\Framework\DB\Select', ['where', 'from', 'join'], [], '', false); + $this->dbSelect->expects($this->any())->method('from')->will($this->returnSelf()); + $this->dbSelect->expects($this->any())->method('join')->will($this->returnSelf()); + $this->readAdapter = $this->getMock( + 'Magento\Framework\DB\Adapter\Pdo\Mysql', + ['prepareSqlCondition', 'select', 'quoteInto'], + [], + '', + false + ); + $this->readAdapter->expects($this->once())->method('select')->will($this->returnValue($this->dbSelect)); + $entity = $this->getMock( + 'Magento\Catalog\Model\Resource\Product', + ['getReadConnection', 'getTable', 'getDefaultAttributes', 'getEntityTable', 'getEntityType', 'getType'], + [], + '', + false + ); + $entity->expects($this->once())->method('getReadConnection')->will($this->returnValue($this->readAdapter)); + $entity->expects($this->any())->method('getTable')->will($this->returnValue('table')); + $entity->expects($this->any())->method('getEntityTable')->will($this->returnValue('table')); + $entity->expects($this->any())->method('getDefaultAttributes')->will($this->returnValue([1 => 1])); + $entity->expects($this->any())->method('getType')->will($this->returnValue('type')); + $entity->expects($this->any())->method('getEntityType')->will($this->returnValue('type')); + $universalFactory = $this->getMock('\Magento\Framework\Validator\UniversalFactory', ['create'], [], '', false); + $universalFactory->expects($this->any())->method('create')->will($this->returnValue($entity)); + $store = $this->getMock('\Magento\Store\Model\Store', ['getId'], [], '', false); + $store->expects($this->any())->method('getId')->will($this->returnValue(1)); + $storeManager = $this->getMock('\Magento\Store\Model\StoreManagerInterface'); + $storeManager->expects($this->any())->method('getStore')->will($this->returnValue($store)); + $fetchStrategy = $this->getMock( + '\Magento\Framework\Data\Collection\Db\FetchStrategy\Query', + ['fetchAll'], + [], + '', + false + ); + $fetchStrategy->expects($this->any())->method('fetchAll')->will($this->returnValue([])); + $this->model = (new \Magento\TestFramework\Helper\ObjectManager($this)) + ->getObject( + '\Magento\Review\Model\Resource\Review\Product\Collection', + [ + 'universalFactory' => $universalFactory, + 'storeManager' => $storeManager, + 'eavConfig' => $eavConfig, + 'fetchStrategy' => $fetchStrategy + ] + ); + } + + /** + * @dataProvider addAttributeToFilterDataProvider + * @param $attribute + */ + public function testAddAttributeToFilter($attribute) + { + $conditionSqlQuery = 'sqlQuery'; + $condition = ['eq' => 'value']; + $this->readAdapter + ->expects($this->once()) + ->method('prepareSqlCondition') + ->with($attribute, $condition) + ->will($this->returnValue($conditionSqlQuery)); + $this->dbSelect + ->expects($this->once()) + ->method('where') + ->with($conditionSqlQuery) + ->will($this->returnSelf()); + $this->model->addAttributeToFilter($attribute, $condition); + } + + /** + * @return array + */ + public function addAttributeToFilterDataProvider() + { + return [ + ['rt.review_id'], + ['rt.created_at'], + ['rt.status_id'], + ['rdt.title'], + ['rdt.nickname'], + ['rdt.detail'], + + ]; + } + + public function testAddAttributeToFilterWithAttributeStore() + { + $storeId = 1; + $this->readAdapter + ->expects($this->at(0)) + ->method('quoteInto') + ->with('rt.review_id=store.review_id AND store.store_id = ?', $storeId) + ->will($this->returnValue('sqlQuery')); + $this->model->addAttributeToFilter('stores', ['eq' => $storeId]); + $this->model->load(); + } + + /** + * @dataProvider addAttributeToFilterWithAttributeTypeDataProvider + * @param $condition + * @param $sqlConditionWith + * @param $sqlConditionWithSec + * @param $doubleConditionSqlQuery + */ + public function testAddAttributeToFilterWithAttributeType( + $condition, + $sqlConditionWith, + $sqlConditionWithSec, + $doubleConditionSqlQuery + ) { + $conditionSqlQuery = 'sqlQuery'; + $this->readAdapter + ->expects($this->at(0)) + ->method('prepareSqlCondition') + ->with('rdt.customer_id', $sqlConditionWith) + ->will($this->returnValue($conditionSqlQuery)); + if ($sqlConditionWithSec) { + $this->readAdapter + ->expects($this->at(1)) + ->method('prepareSqlCondition') + ->with('rdt.store_id', $sqlConditionWithSec) + ->will($this->returnValue($conditionSqlQuery)); + } + $conditionSqlQuery = $doubleConditionSqlQuery + ? $conditionSqlQuery . ' AND ' . $conditionSqlQuery + : $conditionSqlQuery; + $this->dbSelect + ->expects($this->once()) + ->method('where') + ->with($conditionSqlQuery) + ->will($this->returnSelf()); + $this->model->addAttributeToFilter('type', $condition); + } + + /** + * @return array + */ + public function addAttributeToFilterWithAttributeTypeDataProvider() + { + $exprNull = new \Zend_Db_Expr('NULL'); + $defaultStore = \Magento\Store\Model\Store::DEFAULT_STORE_ID; + return [ + [1, ['is' => $exprNull], ['eq' => $defaultStore], true], + [2, ['gt' => 0], null, false], + [null, ['is' => $exprNull], ['neq' => $defaultStore], true] + ]; + } +}