Skip to content

Commit 50a085d

Browse files
authored
Merge pull request magento#4802 from magento-epam/EPAM-PR-74
- fixed Category with invalid data loses new products assignment after validation - fixed Catalog product collection filters produce errors and cause inconsistent behavior - fixed Exported customer without modification can not be imported
2 parents 5860041 + 8d897fa commit 50a085d

File tree

7 files changed

+206
-21
lines changed

7 files changed

+206
-21
lines changed

app/code/Magento/Catalog/Model/ResourceModel/Category.php

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
*
1010
* @author Magento Core Team <[email protected]>
1111
*/
12+
declare(strict_types=1);
13+
1214
namespace Magento\Catalog\Model\ResourceModel;
1315

1416
use Magento\Catalog\Model\Indexer\Category\Product\Processor;
1517
use Magento\Framework\App\ObjectManager;
1618
use Magento\Framework\DataObject;
1719
use Magento\Framework\EntityManager\EntityManager;
18-
use Magento\Catalog\Model\Category as CategoryEntity;
20+
use Magento\Catalog\Setup\CategorySetup;
1921

2022
/**
2123
* Resource model for category entity
@@ -92,6 +94,7 @@ class Category extends AbstractResource
9294
* @var Processor
9395
*/
9496
private $indexerProcessor;
97+
9598
/**
9699
* Category constructor.
97100
* @param \Magento\Eav\Model\Entity\Context $context
@@ -275,7 +278,7 @@ protected function _beforeSave(\Magento\Framework\DataObject $object)
275278
if ($object->getPosition() === null) {
276279
$object->setPosition($this->_getMaxPosition($object->getPath()) + 1);
277280
}
278-
$path = explode('/', $object->getPath());
281+
$path = explode('/', (string)$object->getPath());
279282
$level = count($path) - ($object->getId() ? 1 : 0);
280283
$toUpdateChild = array_diff($path, [$object->getId()]);
281284

@@ -314,7 +317,7 @@ protected function _afterSave(\Magento\Framework\DataObject $object)
314317
/**
315318
* Add identifier for new category
316319
*/
317-
if (substr($object->getPath(), -1) == '/') {
320+
if (substr((string)$object->getPath(), -1) == '/') {
318321
$object->setPath($object->getPath() . $object->getId());
319322
$this->_savePath($object);
320323
}
@@ -352,7 +355,7 @@ protected function _getMaxPosition($path)
352355
{
353356
$connection = $this->getConnection();
354357
$positionField = $connection->quoteIdentifier('position');
355-
$level = count(explode('/', $path));
358+
$level = count(explode('/', (string)$path));
356359
$bind = ['c_level' => $level, 'c_path' => $path . '/%'];
357360
$select = $connection->select()->from(
358361
$this->getTable('catalog_category_entity'),
@@ -717,7 +720,7 @@ public function getCategories($parent, $recursionLevel = 0, $sorted = false, $as
717720
*/
718721
public function getParentCategories($category)
719722
{
720-
$pathIds = array_reverse(explode(',', $category->getPathInStore()));
723+
$pathIds = array_reverse(explode(',', (string)$category->getPathInStore()));
721724
/** @var \Magento\Catalog\Model\ResourceModel\Category\Collection $categories */
722725
$categories = $this->_categoryCollectionFactory->create();
723726
return $categories->setStore(
@@ -1134,4 +1137,44 @@ private function getAggregateCount()
11341137
}
11351138
return $this->aggregateCount;
11361139
}
1140+
1141+
/**
1142+
* Get category with children.
1143+
*
1144+
* @param int $categoryId
1145+
* @return array
1146+
*/
1147+
public function getCategoryWithChildren(int $categoryId): array
1148+
{
1149+
$connection = $this->getConnection();
1150+
1151+
$selectAttributeCode = $connection->select()
1152+
->from(
1153+
['eav_attribute' => $this->getTable('eav_attribute')],
1154+
['attribute_id']
1155+
)->where('entity_type_id = ?', CategorySetup::CATEGORY_ENTITY_TYPE_ID)
1156+
->where('attribute_code = ?', 'is_anchor')
1157+
->limit(1);
1158+
$isAnchorAttributeCode = $connection->fetchOne($selectAttributeCode);
1159+
if (empty($isAnchorAttributeCode) || (int)$isAnchorAttributeCode <= 0) {
1160+
return [];
1161+
}
1162+
1163+
$select = $connection->select()
1164+
->from(
1165+
['cce' => $this->getTable('catalog_category_entity')],
1166+
['entity_id', 'parent_id', 'path']
1167+
)->join(
1168+
['cce_int' => $this->getTable('catalog_category_entity_int')],
1169+
'cce.entity_id = cce_int.entity_id',
1170+
['is_anchor' => 'cce_int.value']
1171+
)->where(
1172+
'cce_int.attribute_id = ?',
1173+
$isAnchorAttributeCode
1174+
)->where(
1175+
"cce.path LIKE '%/{$categoryId}' OR cce.path LIKE '%/{$categoryId}/%'"
1176+
)->order('path');
1177+
1178+
return $connection->fetchAll($select);
1179+
}
11371180
}

app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
67

78
namespace Magento\Catalog\Model\ResourceModel\Product;
89

@@ -22,6 +23,7 @@
2223
use Magento\Framework\Indexer\DimensionFactory;
2324
use Magento\Store\Model\Indexer\WebsiteDimensionProvider;
2425
use Magento\Store\Model\Store;
26+
use Magento\Catalog\Model\ResourceModel\Category;
2527

2628
/**
2729
* Product collection
@@ -302,6 +304,11 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\Abstrac
302304
*/
303305
private $urlFinder;
304306

307+
/**
308+
* @var Category
309+
*/
310+
private $categoryResourceModel;
311+
305312
/**
306313
* Collection constructor
307314
*
@@ -330,6 +337,7 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\Abstrac
330337
* @param TableMaintainer|null $tableMaintainer
331338
* @param PriceTableResolver|null $priceTableResolver
332339
* @param DimensionFactory|null $dimensionFactory
340+
* @param Category|null $categoryResourceModel
333341
*
334342
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
335343
*/
@@ -358,7 +366,8 @@ public function __construct(
358366
MetadataPool $metadataPool = null,
359367
TableMaintainer $tableMaintainer = null,
360368
PriceTableResolver $priceTableResolver = null,
361-
DimensionFactory $dimensionFactory = null
369+
DimensionFactory $dimensionFactory = null,
370+
Category $categoryResourceModel = null
362371
) {
363372
$this->moduleManager = $moduleManager;
364373
$this->_catalogProductFlatState = $catalogProductFlatState;
@@ -392,6 +401,8 @@ public function __construct(
392401
$this->priceTableResolver = $priceTableResolver ?: ObjectManager::getInstance()->get(PriceTableResolver::class);
393402
$this->dimensionFactory = $dimensionFactory
394403
?: ObjectManager::getInstance()->get(DimensionFactory::class);
404+
$this->categoryResourceModel = $categoryResourceModel ?: ObjectManager::getInstance()
405+
->get(Category::class);
395406
}
396407

397408
/**
@@ -1673,7 +1684,11 @@ public function addFilterByRequiredOptions()
16731684
public function setVisibility($visibility)
16741685
{
16751686
$this->_productLimitationFilters['visibility'] = $visibility;
1676-
$this->_applyProductLimitations();
1687+
if ($this->getStoreId() == Store::DEFAULT_STORE_ID) {
1688+
$this->addAttributeToFilter('visibility', $visibility);
1689+
} else {
1690+
$this->_applyProductLimitations();
1691+
}
16771692

16781693
return $this;
16791694
}
@@ -2053,12 +2068,13 @@ protected function _applyProductLimitations()
20532068
protected function _applyZeroStoreProductLimitations()
20542069
{
20552070
$filters = $this->_productLimitationFilters;
2071+
$categories = $this->getChildrenCategories((int)$filters['category_id']);
20562072

20572073
$conditions = [
20582074
'cat_pro.product_id=e.entity_id',
20592075
$this->getConnection()->quoteInto(
2060-
'cat_pro.category_id=?',
2061-
$filters['category_id']
2076+
'cat_pro.category_id IN (?)',
2077+
$categories
20622078
),
20632079
];
20642080
$joinCond = join(' AND ', $conditions);
@@ -2079,6 +2095,39 @@ protected function _applyZeroStoreProductLimitations()
20792095
return $this;
20802096
}
20812097

2098+
/**
2099+
* Get children categories.
2100+
*
2101+
* @param int $categoryId
2102+
* @return array
2103+
*/
2104+
private function getChildrenCategories(int $categoryId): array
2105+
{
2106+
$categoryIds[] = $categoryId;
2107+
$anchorCategory = [];
2108+
2109+
$categories = $this->categoryResourceModel->getCategoryWithChildren($categoryId);
2110+
if (empty($categories)) {
2111+
return $categoryIds;
2112+
}
2113+
2114+
$firstCategory = array_shift($categories);
2115+
if ($firstCategory['is_anchor'] == 1) {
2116+
$anchorCategory[] = (int)$firstCategory['entity_id'];
2117+
foreach ($categories as $category) {
2118+
if (in_array($category['parent_id'], $categoryIds)
2119+
&& in_array($category['parent_id'], $anchorCategory)) {
2120+
$categoryIds[] = (int)$category['entity_id'];
2121+
if ($category['is_anchor'] == 1) {
2122+
$anchorCategory[] = (int)$category['entity_id'];
2123+
}
2124+
}
2125+
}
2126+
}
2127+
2128+
return $categoryIds;
2129+
}
2130+
20822131
/**
20832132
* Add category ids to loaded items
20842133
*

app/code/Magento/CustomerImportExport/Model/Import/Customer.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
7+
68
namespace Magento\CustomerImportExport\Model\Import;
79

810
use Magento\Customer\Api\Data\CustomerInterface;
@@ -21,7 +23,7 @@
2123
class Customer extends AbstractCustomer
2224
{
2325
/**
24-
* Attribute collection name
26+
* Collection name attribute
2527
*/
2628
const ATTRIBUTE_COLLECTION_NAME = \Magento\Customer\Model\ResourceModel\Attribute\Collection::class;
2729

@@ -519,8 +521,10 @@ protected function _importData()
519521
);
520522
} elseif ($this->getBehavior($rowData) == \Magento\ImportExport\Model\Import::BEHAVIOR_ADD_UPDATE) {
521523
$processedData = $this->_prepareDataForUpdate($rowData);
524+
// phpcs:disable Magento2.Performance.ForeachArrayMerge
522525
$entitiesToCreate = array_merge($entitiesToCreate, $processedData[self::ENTITIES_TO_CREATE_KEY]);
523526
$entitiesToUpdate = array_merge($entitiesToUpdate, $processedData[self::ENTITIES_TO_UPDATE_KEY]);
527+
// phpcs:enable
524528
foreach ($processedData[self::ATTRIBUTES_TO_SAVE_KEY] as $tableName => $customerAttributes) {
525529
if (!isset($attributesToSave[$tableName])) {
526530
$attributesToSave[$tableName] = [];
@@ -598,14 +602,18 @@ protected function _validateRowForUpdate(array $rowData, $rowNumber)
598602
$isFieldNotSetAndCustomerDoesNotExist =
599603
!isset($rowData[$attributeCode]) && !$this->_getCustomerId($email, $website);
600604
$isFieldSetAndTrimmedValueIsEmpty
601-
= isset($rowData[$attributeCode]) && '' === trim($rowData[$attributeCode]);
605+
= isset($rowData[$attributeCode]) && '' === trim((string)$rowData[$attributeCode]);
602606

603607
if ($isFieldRequired && ($isFieldNotSetAndCustomerDoesNotExist || $isFieldSetAndTrimmedValueIsEmpty)) {
604608
$this->addRowError(self::ERROR_VALUE_IS_REQUIRED, $rowNumber, $attributeCode);
605609
continue;
606610
}
607611

608-
if (isset($rowData[$attributeCode]) && strlen($rowData[$attributeCode])) {
612+
if (isset($rowData[$attributeCode]) && strlen((string)$rowData[$attributeCode])) {
613+
if ($attributeParams['type'] == 'select') {
614+
continue;
615+
}
616+
609617
$this->isAttributeValid(
610618
$attributeCode,
611619
$attributeParams,

0 commit comments

Comments
 (0)