Skip to content

Commit 49ef010

Browse files
authored
Merge branch '2.4-develop' into patch-3
2 parents 8f62de1 + 7bdafaa commit 49ef010

File tree

20 files changed

+999
-34
lines changed

20 files changed

+999
-34
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Model\Plugin\SpecialPricePluginForREST;
9+
10+
use Magento\Catalog\Model\Product\Price\SpecialPriceStorage;
11+
use Magento\Store\Model\StoreManagerInterface;
12+
13+
/**
14+
* Special price storage Plugin to handle website scope issue at the frontend (only for REST API calls)
15+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
16+
*/
17+
class SpecialPriceStoragePlugin
18+
{
19+
/**
20+
* Constructor
21+
*
22+
* @param StoreManagerInterface $storeManager
23+
*/
24+
public function __construct(
25+
private StoreManagerInterface $storeManager
26+
) {
27+
}
28+
29+
/**
30+
* Around update plugin for REST api fix
31+
*
32+
* @param SpecialPriceStorage $subject
33+
* @param callable $proceed
34+
* @param array $prices
35+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
36+
*/
37+
public function aroundUpdate(SpecialPriceStorage $subject, callable $proceed, array $prices)
38+
{
39+
$prices = $this->applyWebsitePrices($prices);
40+
return $proceed($prices);
41+
}
42+
43+
/**
44+
* Function to get website id from current store id and then find all stores and apply prices to them
45+
*
46+
* @param array $formattedPrices
47+
*/
48+
private function applyWebsitePrices(array $formattedPrices): array
49+
{
50+
$newPrices = [];
51+
52+
foreach ($formattedPrices as $price) {
53+
// Add the original price first
54+
$newPrices[] = $price;
55+
56+
if ($price->getStoreId() == \Magento\Store\Model\Store::DEFAULT_STORE_ID) {
57+
continue;
58+
}
59+
60+
$store = $this->storeManager->getStore($price->getStoreId());
61+
$website = $store->getWebsite();
62+
$storeIds = $website->getStoreIds();
63+
64+
// Unset origin store view to avoid duplication
65+
unset($storeIds[$price->getStoreId()]);
66+
67+
foreach ($storeIds as $storeId) {
68+
/** @var \Magento\Catalog\Model\Product\Price\SpecialPrice $cloned */
69+
$cloned = clone $price;
70+
$cloned->setStoreId((int) $storeId);
71+
$newPrices[] = $cloned;
72+
}
73+
}
74+
75+
return $newPrices;
76+
}
77+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Plugin;
9+
10+
use Magento\Catalog\Api\CategoryManagementInterface;
11+
use Magento\Catalog\Api\Data\CategoryTreeInterface;
12+
13+
/**
14+
* Performance optimizer plugin for CategoryManagement
15+
*/
16+
class CategoryManagementPerformanceOptimizer
17+
{
18+
private const DEFAULT_MAX_DEPTH = 3; // Limit depth to prevent timeouts
19+
20+
/**
21+
* Optimize getTree method with depth limits to prevent timeouts
22+
*
23+
* @param CategoryManagementInterface $subject
24+
* @param int|null $rootCategoryId
25+
* @param int|null $depth
26+
* @return array
27+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
28+
*/
29+
public function beforeGetTree(
30+
CategoryManagementInterface $subject,
31+
$rootCategoryId = null,
32+
$depth = null
33+
): array {
34+
// Limit depth to prevent performance issues
35+
$depth = $depth ?? self::DEFAULT_MAX_DEPTH;
36+
return [$rootCategoryId, $depth];
37+
}
38+
}

app/code/Magento/Catalog/etc/db_schema.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,12 @@
285285
<index referenceId="CATALOG_CATEGORY_ENTITY_PATH" indexType="btree">
286286
<column name="path"/>
287287
</index>
288+
<!-- Performance optimization index for efficient tree traversal -->
289+
<index referenceId="CATALOG_CATEGORY_ENTITY_PARENT_ID_LEVEL_POSITION" indexType="btree">
290+
<column name="parent_id"/>
291+
<column name="level"/>
292+
<column name="position"/>
293+
</index>
288294
</table>
289295
<table name="catalog_category_entity_datetime" resource="default" engine="innodb"
290296
comment="Catalog Category Datetime Attribute Backend Table">
@@ -401,6 +407,11 @@
401407
<index referenceId="CATALOG_CATEGORY_ENTITY_INT_STORE_ID" indexType="btree">
402408
<column name="store_id"/>
403409
</index>
410+
<!-- Performance optimization index for is_active attribute filtering -->
411+
<index referenceId="CATALOG_CATEGORY_ENTITY_INT_STORE_ID_VALUE" indexType="btree">
412+
<column name="store_id"/>
413+
<column name="value"/>
414+
</index>
404415
</table>
405416
<table name="catalog_category_entity_text" resource="default" engine="innodb"
406417
comment="Catalog Category Text Attribute Backend Table">
@@ -506,6 +517,12 @@
506517
<index referenceId="CATALOG_CATEGORY_PRODUCT_PRODUCT_ID" indexType="btree">
507518
<column name="product_id"/>
508519
</index>
520+
<!-- Performance optimization index for product count queries -->
521+
<index referenceId="CATALOG_CATEGORY_PRODUCT_CATEGORY_ID_PRODUCT_ID_POSITION" indexType="btree">
522+
<column name="category_id"/>
523+
<column name="product_id"/>
524+
<column name="position"/>
525+
</index>
509526
</table>
510527
<table name="catalog_category_product_index" resource="default" engine="innodb"
511528
comment="Catalog Category Product Index">

app/code/Magento/Catalog/etc/db_schema_whitelist.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@
157157
},
158158
"index": {
159159
"CATALOG_CATEGORY_ENTITY_LEVEL": true,
160-
"CATALOG_CATEGORY_ENTITY_PATH": true
160+
"CATALOG_CATEGORY_ENTITY_PATH": true,
161+
"CATALOG_CATEGORY_ENTITY_PARENT_ID_LEVEL_POSITION": true
161162
},
162163
"constraint": {
163164
"PRIMARY": true
@@ -216,7 +217,8 @@
216217
"index": {
217218
"CATALOG_CATEGORY_ENTITY_INT_ENTITY_ID": true,
218219
"CATALOG_CATEGORY_ENTITY_INT_ATTRIBUTE_ID": true,
219-
"CATALOG_CATEGORY_ENTITY_INT_STORE_ID": true
220+
"CATALOG_CATEGORY_ENTITY_INT_STORE_ID": true,
221+
"CATALOG_CATEGORY_ENTITY_INT_STORE_ID_VALUE": true
220222
},
221223
"constraint": {
222224
"PRIMARY": true,
@@ -276,7 +278,8 @@
276278
"position": true
277279
},
278280
"index": {
279-
"CATALOG_CATEGORY_PRODUCT_PRODUCT_ID": true
281+
"CATALOG_CATEGORY_PRODUCT_PRODUCT_ID": true,
282+
"CATALOG_CATEGORY_PRODUCT_CATEGORY_ID_PRODUCT_ID_POSITION": true
280283
},
281284
"constraint": {
282285
"PRIMARY": true,

app/code/Magento/Catalog/etc/webapi_rest/di.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,13 @@
4747
<type name="Magento\Catalog\Model\CategoryRepository">
4848
<plugin name="format_category_url_key_rest_api" type="Magento\Catalog\Plugin\Model\CategoryRepositoryPlugin" />
4949
</type>
50+
<type name="Magento\Catalog\Model\Product\Price\SpecialPriceStorage">
51+
<plugin name="vendor_special_price_rest_plugin"
52+
type="Magento\Catalog\Model\Plugin\SpecialPricePluginForREST\SpecialPriceStoragePlugin" />
53+
</type>
54+
<!-- Essential performance optimizations for category tree operations -->
55+
<type name="Magento\Catalog\Api\CategoryManagementInterface">
56+
<plugin name="categoryManagementPerformanceOptimizer"
57+
type="Magento\Catalog\Plugin\CategoryManagementPerformanceOptimizer" />
58+
</type>
5059
</config>

app/code/Magento/Indexer/etc/db_schema.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2018 Adobe
5+
* All Rights Reserved.
66
*/
77
-->
88
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -29,7 +29,7 @@
2929
<column xsi:type="varchar" name="mode" nullable="true" length="16" default="disabled" comment="View Mode"/>
3030
<column xsi:type="varchar" name="status" nullable="true" length="16" default="idle" comment="View Status"/>
3131
<column xsi:type="datetime" name="updated" on_update="false" nullable="true" comment="View updated time"/>
32-
<column xsi:type="int" name="version_id" unsigned="true" nullable="true" identity="false"
32+
<column xsi:type="bigint" name="version_id" unsigned="true" nullable="true" identity="false"
3333
comment="View Version ID"/>
3434
<constraint xsi:type="primary" referenceId="PRIMARY">
3535
<column name="state_id"/>
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All rights reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Ui\Plugin\Config\Backend;
9+
10+
use Magento\Config\Model\Config\Backend\Serialized\ArraySerialized;
11+
use Magento\Framework\App\RequestInterface;
12+
13+
/**
14+
* Plugin for ArraySerialized backend model
15+
* Automatically converts row1/row2/row3 format to numerically indexed arrays
16+
* Only works on design config edit page
17+
*/
18+
class ArraySerializedPlugin
19+
{
20+
private const DESIGN_CONFIG_EDIT_PAGE = '_design_config_edit';
21+
22+
/**
23+
* @param RequestInterface $request
24+
*/
25+
public function __construct(
26+
private readonly RequestInterface $request
27+
) {
28+
}
29+
30+
/**
31+
* Convert string keys to numeric keys. Only applies on design config edit page
32+
*
33+
* @param ArraySerialized $subject
34+
* @param ArraySerialized $result
35+
* @return ArraySerialized
36+
*/
37+
public function afterAfterLoad(ArraySerialized $subject, ArraySerialized $result)
38+
{
39+
// Only apply the conversion on design config edit page
40+
if (!$this->isDesignConfigEditPage()) {
41+
return $result;
42+
}
43+
44+
$value = $subject->getValue();
45+
if (!is_array($value)) {
46+
return $result;
47+
}
48+
49+
$keys = array_keys($value);
50+
// Check if keys are string-based (row1, row2, row3) instead of numeric
51+
if (empty($keys) || is_numeric($keys[0])) {
52+
return $result;
53+
}
54+
55+
// Convert to numerically indexed array
56+
$convertedValue = array_values($value);
57+
$subject->setValue($convertedValue);
58+
59+
return $result;
60+
}
61+
62+
/**
63+
* Check if we're on the design config edit page.
64+
*
65+
* @return bool
66+
*/
67+
private function isDesignConfigEditPage(): bool
68+
{
69+
return str_ends_with($this->request->getFullActionName(), self::DESIGN_CONFIG_EDIT_PAGE);
70+
}
71+
}

app/code/Magento/Ui/etc/adminhtml/di.xml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2016 Adobe
5+
* All rights reserved.
66
*/
77
-->
88
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
@@ -61,4 +61,9 @@
6161
</argument>
6262
</arguments>
6363
</type>
64+
65+
<!-- Plugin to automatically convert row1/row2/row3 format to numerically indexed arrays -->
66+
<type name="Magento\Config\Model\Config\Backend\Serialized\ArraySerialized">
67+
<plugin name="ui_array_serialized_plugin" type="Magento\Ui\Plugin\Config\Backend\ArraySerializedPlugin" />
68+
</type>
6469
</config>

0 commit comments

Comments
 (0)