Skip to content

Commit 49e6eb0

Browse files
committed
Merge remote-tracking branch 'origin/2.4-develop' into MC-38518
2 parents f536f54 + f472536 commit 49e6eb0

File tree

128 files changed

+3620
-1347
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+3620
-1347
lines changed

app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper/AttributeFilter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ private function prepareDefaultData(array $attributeList, string $attributeCode,
8080
// For non-numeric types set the attributeValue to 'false' to trigger their removal from the db
8181
if ($attributeType === 'varchar' || $attributeType === 'text' || $attributeType === 'datetime') {
8282
$attribute->setIsRequired(false);
83-
$productData[$attributeCode] = false;
83+
$productData[$attributeCode] = $attribute->getDefaultValue() ?: false;
8484
} else {
8585
$productData[$attributeCode] = null;
8686
}

app/code/Magento/Catalog/Model/CategoryLinkManagement.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
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;
89

910
/**
10-
* Class CategoryLinkManagement
11+
* Represents Category Product Link Management class
1112
*/
1213
class CategoryLinkManagement implements \Magento\Catalog\Api\CategoryLinkManagementInterface
1314
{
@@ -56,7 +57,7 @@ public function __construct(
5657
}
5758

5859
/**
59-
* {@inheritdoc}
60+
* @inheritdoc
6061
*/
6162
public function getAssignedProducts($categoryId)
6263
{
@@ -65,6 +66,7 @@ public function getAssignedProducts($categoryId)
6566
/** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $products */
6667
$products = $category->getProductCollection();
6768
$products->addFieldToSelect('position');
69+
$products->groupByAttribute($products->getProductEntityMetadata()->getIdentifierField());
6870

6971
/** @var \Magento\Catalog\Api\Data\CategoryProductLinkInterface[] $links */
7072
$links = [];

app/code/Magento/Catalog/Model/Indexer/Product/Price/Action/Rows.php

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,82 @@
55
*/
66
namespace Magento\Catalog\Model\Indexer\Product\Price\Action;
77

8+
use Magento\Directory\Model\CurrencyFactory;
9+
use Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory;
10+
use Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer;
11+
use Magento\Catalog\Model\Product\Type;
12+
use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice;
13+
use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\Factory;
14+
use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\TierPrice;
15+
use Magento\Framework\App\Config\ScopeConfigInterface;
16+
use Magento\Framework\Stdlib\DateTime;
17+
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
18+
use Magento\Store\Model\StoreManagerInterface;
19+
820
/**
921
* Class Rows reindex action for mass actions
1022
*
23+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects) to preserve compatibility with parent class
1124
*/
1225
class Rows extends \Magento\Catalog\Model\Indexer\Product\Price\AbstractAction
1326
{
27+
/**
28+
* Default batch size
29+
*/
30+
private const BATCH_SIZE = 100;
31+
32+
/**
33+
* @var int
34+
*/
35+
private $batchSize;
36+
37+
/**
38+
* @param ScopeConfigInterface $config
39+
* @param StoreManagerInterface $storeManager
40+
* @param CurrencyFactory $currencyFactory
41+
* @param TimezoneInterface $localeDate
42+
* @param DateTime $dateTime
43+
* @param Type $catalogProductType
44+
* @param Factory $indexerPriceFactory
45+
* @param DefaultPrice $defaultIndexerResource
46+
* @param TierPrice|null $tierPriceIndexResource
47+
* @param DimensionCollectionFactory|null $dimensionCollectionFactory
48+
* @param TableMaintainer|null $tableMaintainer
49+
* @param int|null $batchSize
50+
* @SuppressWarnings(PHPMD.NPathComplexity) Added to backward compatibility with abstract class
51+
* @SuppressWarnings(PHPMD.CyclomaticComplexity) Added to backward compatibility with abstract class
52+
* @SuppressWarnings(PHPMD.ExcessiveParameterList) Added to backward compatibility with abstract class
53+
*/
54+
public function __construct(
55+
ScopeConfigInterface $config,
56+
StoreManagerInterface $storeManager,
57+
CurrencyFactory $currencyFactory,
58+
TimezoneInterface $localeDate,
59+
DateTime $dateTime,
60+
Type $catalogProductType,
61+
Factory $indexerPriceFactory,
62+
DefaultPrice $defaultIndexerResource,
63+
TierPrice $tierPriceIndexResource = null,
64+
DimensionCollectionFactory $dimensionCollectionFactory = null,
65+
TableMaintainer $tableMaintainer = null,
66+
?int $batchSize = null
67+
) {
68+
parent::__construct(
69+
$config,
70+
$storeManager,
71+
$currencyFactory,
72+
$localeDate,
73+
$dateTime,
74+
$catalogProductType,
75+
$indexerPriceFactory,
76+
$defaultIndexerResource,
77+
$tierPriceIndexResource,
78+
$dimensionCollectionFactory,
79+
$tableMaintainer
80+
);
81+
$this->batchSize = $batchSize ?? self::BATCH_SIZE;
82+
}
83+
1484
/**
1585
* Execute Rows reindex
1686
*
@@ -24,10 +94,28 @@ public function execute($ids)
2494
if (empty($ids)) {
2595
throw new \Magento\Framework\Exception\InputException(__('Bad value was supplied.'));
2696
}
27-
try {
28-
$this->_reindexRows($ids);
29-
} catch (\Exception $e) {
30-
throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage()), $e);
97+
$currentBatch = [];
98+
$i = 0;
99+
100+
foreach ($ids as $id) {
101+
$currentBatch[] = $id;
102+
if (++$i === $this->batchSize) {
103+
try {
104+
$this->_reindexRows($currentBatch);
105+
} catch (\Exception $e) {
106+
throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage()), $e);
107+
}
108+
$i = 0;
109+
$currentBatch = [];
110+
}
111+
}
112+
113+
if (!empty($currentBatch)) {
114+
try {
115+
$this->_reindexRows($currentBatch);
116+
} catch (\Exception $e) {
117+
throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage()), $e);
118+
}
31119
}
32120
}
33121
}

app/code/Magento/Catalog/Model/Product/Authorization.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ public function authorizeSavingOf(ProductInterface $product): void
159159
if (!$savedProduct->getSku()) {
160160
throw NoSuchEntityException::singleField('id', $product->getId());
161161
}
162-
$oldData = $product->getOrigData();
162+
$oldData = $savedProduct->getData();
163163
}
164164
}
165165
if ($this->hasProductChanged($product, $oldData)) {

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
namespace Magento\Catalog\Model\ResourceModel;
1515

16-
use Magento\Catalog\Api\Data\ProductInterface;
16+
use Magento\Catalog\Api\Data\CategoryInterface;
1717
use Magento\Catalog\Model\Indexer\Category\Product\Processor;
1818
use Magento\Catalog\Setup\CategorySetup;
1919
use Magento\Framework\App\ObjectManager;
@@ -1172,11 +1172,11 @@ public function getCategoryWithChildren(int $categoryId): array
11721172
return [];
11731173
}
11741174

1175-
$linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
1175+
$linkField = $this->metadataPool->getMetadata(CategoryInterface::class)->getLinkField();
11761176
$select = $connection->select()
11771177
->from(
11781178
['cce' => $this->getTable('catalog_category_entity')],
1179-
[$linkField, 'parent_id', 'path']
1179+
[$linkField, 'entity_id', 'parent_id', 'path']
11801180
)->join(
11811181
['cce_int' => $this->getTable('catalog_category_entity_int')],
11821182
'cce.' . $linkField . ' = cce_int.' . $linkField,

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace Magento\Catalog\Model\ResourceModel\Product;
99

10+
use Magento\Catalog\Api\Data\CategoryInterface;
1011
use Magento\Catalog\Api\Data\ProductInterface;
1112
use Magento\Catalog\Model\Indexer\Category\Product\TableMaintainer;
1213
use Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver;
@@ -2130,16 +2131,17 @@ private function getChildrenCategories(int $categoryId): array
21302131

21312132
$firstCategory = array_shift($categories);
21322133
if ($firstCategory['is_anchor'] == 1) {
2133-
$linkField = $this->getProductEntityMetadata()->getLinkField();
2134-
$anchorCategory[] = (int)$firstCategory[$linkField];
2134+
//category hierarchy can not be modified by staging updates
2135+
$entityField = $this->metadataPool->getMetadata(CategoryInterface::class)->getIdentifierField();
2136+
$anchorCategory[] = (int)$firstCategory[$entityField];
21352137
foreach ($categories as $category) {
21362138
if (in_array($category['parent_id'], $categoryIds)
21372139
&& in_array($category['parent_id'], $anchorCategory)) {
2138-
$categoryIds[] = (int)$category[$linkField];
2140+
$categoryIds[] = (int)$category[$entityField];
21392141
// Storefront approach is to treat non-anchor children of anchor category as anchors.
2140-
// Adding their's IDs to $anchorCategory for consistency.
2142+
// Adding theirs IDs to $anchorCategory for consistency.
21412143
if ($category['is_anchor'] == 1 || in_array($category['parent_id'], $anchorCategory)) {
2142-
$anchorCategory[] = (int)$category[$linkField];
2144+
$anchorCategory[] = (int)$category[$entityField];
21432145
}
21442146
}
21452147
}

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

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,38 @@
55
*/
66
namespace Magento\Catalog\Model\ResourceModel\Product;
77

8+
use Magento\Framework\App\ObjectManager;
9+
use Magento\Framework\Model\ResourceModel\Db\AbstractDb;
10+
use Magento\Framework\Model\ResourceModel\Db\Context;
11+
use Magento\Framework\EntityManager\MetadataPool;
12+
use Magento\Catalog\Api\Data\ProductInterface;
13+
814
/**
915
* Catalog Product Relations Resource model
1016
*
1117
* @author Magento Core Team <[email protected]>
1218
*/
13-
class Relation extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
19+
class Relation extends AbstractDb
1420
{
21+
/**
22+
* @var MetadataPool
23+
*/
24+
private $metadataPool;
25+
26+
/**
27+
* @param Context $context
28+
* @param string $connectionName
29+
* @param MetadataPool $metadataPool
30+
*/
31+
public function __construct(
32+
Context $context,
33+
$connectionName = null,
34+
MetadataPool $metadataPool = null
35+
) {
36+
parent::__construct($context, $connectionName);
37+
$this->metadataPool = $metadataPool ?: ObjectManager::getInstance()->get(MetadataPool::class);
38+
}
39+
1540
/**
1641
* Initialize resource model and define main table
1742
*
@@ -109,4 +134,27 @@ public function removeRelations($parentId, $childIds)
109134
}
110135
return $this;
111136
}
137+
138+
/**
139+
* Finds parent relations by given children ids.
140+
*
141+
* @param array $childrenIds Child products entity ids.
142+
* @return array Parent products entity ids.
143+
*/
144+
public function getRelationsByChildren(array $childrenIds): array
145+
{
146+
$connection = $this->getConnection();
147+
$linkField = $this->metadataPool->getMetadata(ProductInterface::class)
148+
->getLinkField();
149+
$select = $connection->select()
150+
->from(
151+
['cpe' => $this->getTable('catalog_product_entity')],
152+
'entity_id'
153+
)->join(
154+
['relation' => $this->getTable('catalog_product_relation')],
155+
'relation.parent_id = cpe.' . $linkField
156+
)->where('relation.child_id IN(?)', $childrenIds);
157+
158+
return $connection->fetchCol($select);
159+
}
112160
}

app/code/Magento/Catalog/Test/Unit/Model/CategoryLinkManagementTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Magento\Catalog\Model\CategoryRepository;
1616
use Magento\Catalog\Model\ResourceModel\Product;
1717
use Magento\Catalog\Model\ResourceModel\Product\Collection;
18+
use Magento\Framework\DataObject;
1819
use Magento\Framework\Indexer\IndexerRegistry;
1920
use PHPUnit\Framework\MockObject\MockObject;
2021
use PHPUnit\Framework\TestCase;
@@ -85,7 +86,11 @@ public function testGetAssignedProducts()
8586
$categoryMock->expects($this->once())->method('getProductCollection')->willReturn($productsMock);
8687
$categoryMock->expects($this->once())->method('getId')->willReturn($categoryId);
8788
$productsMock->expects($this->once())->method('addFieldToSelect')->with('position')->willReturnSelf();
89+
$productsMock->expects($this->once())->method('groupByAttribute')->with('entity_id')->willReturnSelf();
8890
$productsMock->expects($this->once())->method('getItems')->willReturn($items);
91+
$productsMock->expects($this->once())
92+
->method('getProductEntityMetadata')
93+
->willReturn(new DataObject(['identifier_field' => 'entity_id']));
8994
$this->productLinkFactoryMock->expects($this->once())->method('create')->willReturn($categoryProductLinkMock);
9095
$categoryProductLinkMock->expects($this->once())
9196
->method('setSku')

0 commit comments

Comments
 (0)