Skip to content

Commit c22caff

Browse files
committed
Merge branch '2.4.0-develop' of github.com:magento-engcom/magento2ce into async-opetation-status-issue
2 parents 92fab51 + 07b53eb commit c22caff

File tree

3,438 files changed

+3054
-224821
lines changed

Some content is hidden

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

3,438 files changed

+3054
-224821
lines changed

.php_cs.dist

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010

1111
$finder = PhpCsFixer\Finder::create()
1212
->name('*.phtml')
13-
->exclude('dev/tests/functional/generated')
14-
->exclude('dev/tests/functional/var')
15-
->exclude('dev/tests/functional/vendor')
1613
->exclude('dev/tests/integration/tmp')
1714
->exclude('dev/tests/integration/var')
1815
->exclude('lib/internal/Cm')

app/code/Magento/Backend/App/AbstractAction.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Magento\Framework\Data\Form\FormKey\Validator as FormKeyValidator;
1717
use Magento\Framework\Locale\ResolverInterface;
1818
use Magento\Framework\View\Element\AbstractBlock;
19+
use Magento\Framework\Encryption\Helper\Security;
1920

2021
/**
2122
* Generic backend controller
@@ -386,7 +387,7 @@ protected function _validateSecretKey()
386387
}
387388

388389
$secretKey = $this->getRequest()->getParam(UrlInterface::SECRET_KEY_PARAM_NAME, null);
389-
if (!$secretKey || $secretKey != $this->_backendUrl->getSecretKey()) {
390+
if (!$secretKey || !Security::compareStrings($secretKey, $this->_backendUrl->getSecretKey())) {
390391
return false;
391392
}
392393
return true;

app/code/Magento/Backend/Test/Mftf/Test/AdminLoginSuccessfulTest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<group value="login"/>
2121
</annotations>
2222

23+
2324
<actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/>
2425
<actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/>
2526
<actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/>

app/code/Magento/Captcha/Controller/Refresh/Index.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
namespace Magento\Captcha\Controller\Refresh;
99

1010
use Magento\Captcha\Helper\Data as CaptchaHelper;
11+
use Magento\Framework\App\Action\Action;
12+
use Magento\Framework\App\Action\Context;
1113
use Magento\Framework\App\Action\HttpPostActionInterface;
1214
use Magento\Framework\App\RequestInterface;
1315
use Magento\Framework\Controller\Result\JsonFactory as JsonResultFactory;
@@ -18,7 +20,7 @@
1820
* Refreshes captcha and returns JSON encoded URL to image (AJAX action)
1921
* Example: {'imgSrc': 'http://example.com/media/captcha/67842gh187612ngf8s.png'}
2022
*/
21-
class Index implements HttpPostActionInterface
23+
class Index extends Action implements HttpPostActionInterface
2224
{
2325
/**
2426
* @var CaptchaHelper
@@ -46,19 +48,22 @@ class Index implements HttpPostActionInterface
4648
private $jsonResultFactory;
4749

4850
/**
51+
* @param Context $context
4952
* @param RequestInterface $request
5053
* @param JsonResultFactory $jsonFactory
5154
* @param CaptchaHelper $captchaHelper
5255
* @param LayoutInterface $layout
5356
* @param JsonSerializer $serializer
5457
*/
5558
public function __construct(
59+
Context $context,
5660
RequestInterface $request,
5761
JsonResultFactory $jsonFactory,
5862
CaptchaHelper $captchaHelper,
5963
LayoutInterface $layout,
6064
JsonSerializer $serializer
6165
) {
66+
parent::__construct($context);
6267
$this->request = $request;
6368
$this->jsonResultFactory = $jsonFactory;
6469
$this->captchaHelper = $captchaHelper;

app/code/Magento/Captcha/Test/Unit/Controller/Refresh/IndexTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Magento\Captcha\Controller\Refresh\Index;
1111
use Magento\Captcha\Helper\Data as CaptchaHelper;
1212
use Magento\Captcha\Model\CaptchaInterface;
13+
use Magento\Framework\App\Action\Context;
1314
use Magento\Framework\App\RequestInterface;
1415
use Magento\Framework\Controller\Result\Json as ResultJson;
1516
use Magento\Framework\Controller\Result\JsonFactory as ResultJsonFactory;
@@ -45,6 +46,9 @@ class IndexTest extends TestCase
4546
/** @var MockObject|JsonSerializer */
4647
private $jsonSerializerMock;
4748

49+
/** @var MockObject|Context */
50+
private $contextMock;
51+
4852
/** @var Index */
4953
private $refreshAction;
5054

@@ -66,13 +70,16 @@ protected function setUp(): void
6670
$this->jsonSerializerMock = $this->createMock(JsonSerializer::class);
6771
$this->captchaHelperMock = $this->createMock(CaptchaHelper::class);
6872

73+
$this->contextMock = $this->createMock(Context::class);
74+
6975
$this->blockMock->method('setIsAjax')
7076
->willReturnSelf();
7177

7278
$this->layoutMock->method('createBlock')
7379
->willReturn($this->blockMock);
7480

7581
$this->refreshAction = new Index(
82+
$this->contextMock,
7683
$this->requestMock,
7784
$this->jsonResultFactoryMock,
7885
$this->captchaHelperMock,

app/code/Magento/CardinalCommerce/Model/JwtManagement.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace Magento\CardinalCommerce\Model;
99

1010
use Magento\Framework\Serialize\Serializer\Json;
11+
use Magento\Framework\Encryption\Helper\Security;
1112

1213
/**
1314
* JSON Web Token management.
@@ -62,7 +63,8 @@ public function decode(string $jwt, string $key): array
6263
$payload = $this->json->unserialize($payloadJson);
6364

6465
$signature = $this->urlSafeB64Decode($signatureB64);
65-
if ($signature !== $this->sign($headB64 . '.' . $payloadB64, $key, $header['alg'])) {
66+
67+
if (!Security::compareStrings($signature, $this->sign($headB64 . '.' . $payloadB64, $key, $header['alg']))) {
6668
throw new \InvalidArgumentException('JWT signature verification failed');
6769
}
6870

app/code/Magento/Catalog/Block/Product/ListProduct.php

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -353,18 +353,16 @@ public function getIdentities()
353353

354354
$category = $this->getLayer()->getCurrentCategory();
355355
if ($category) {
356-
$identities[] = Product::CACHE_PRODUCT_CATEGORY_TAG . '_' . $category->getId();
356+
$identities[] = [Product::CACHE_PRODUCT_CATEGORY_TAG . '_' . $category->getId()];
357357
}
358358

359359
//Check if category page shows only static block (No products)
360-
if ($category->getData('display_mode') == Category::DM_PAGE) {
361-
return $identities;
362-
}
363-
364-
foreach ($this->_getProductCollection() as $item) {
365-
// phpcs:ignore Magento2.Performance.ForeachArrayMerge
366-
$identities = array_merge($identities, $item->getIdentities());
360+
if ($category->getData('display_mode') != Category::DM_PAGE) {
361+
foreach ($this->_getProductCollection() as $item) {
362+
$identities[] = $item->getIdentities();
363+
}
367364
}
365+
$identities = array_merge(...$identities);
368366

369367
return $identities;
370368
}
@@ -377,7 +375,7 @@ public function getIdentities()
377375
*/
378376
public function getAddToCartPostParams(Product $product)
379377
{
380-
$url = $this->getAddToCartUrl($product);
378+
$url = $this->getAddToCartUrl($product, ['_escape' => false]);
381379
return [
382380
'action' => $url,
383381
'data' => [

app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Save.php

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@
77
namespace Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute;
88

99
use Magento\AsynchronousOperations\Api\Data\OperationInterface;
10+
use Magento\Catalog\Model\ProductFactory;
1011
use Magento\Catalog\Api\Data\ProductAttributeInterface;
1112
use Magento\Eav\Model\Config;
1213
use Magento\Framework\App\Action\HttpPostActionInterface;
1314
use Magento\Backend\App\Action;
1415
use Magento\Framework\App\ObjectManager;
16+
use Magento\Framework\Exception\LocalizedException;
1517
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
1618

1719
/**
18-
* Class used for saving mass updated products attributes.
20+
* Class responsible for saving product attributes.
1921
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
2022
*/
2123
class Save extends \Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute implements HttpPostActionInterface
@@ -60,6 +62,11 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Product\Action\Attribut
6062
*/
6163
private $eavConfig;
6264

65+
/**
66+
* @var ProductFactory
67+
*/
68+
private $productFactory;
69+
6370
/**
6471
* @param Action\Context $context
6572
* @param \Magento\Catalog\Helper\Product\Edit\Action\Attribute $attributeHelper
@@ -71,6 +78,7 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Product\Action\Attribut
7178
* @param int $bulkSize
7279
* @param TimezoneInterface $timezone
7380
* @param Config $eavConfig
81+
* @param ProductFactory $productFactory
7482
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
7583
*/
7684
public function __construct(
@@ -83,7 +91,8 @@ public function __construct(
8391
\Magento\Authorization\Model\UserContextInterface $userContext,
8492
int $bulkSize = 100,
8593
TimezoneInterface $timezone = null,
86-
Config $eavConfig = null
94+
Config $eavConfig = null,
95+
ProductFactory $productFactory = null
8796
) {
8897
parent::__construct($context, $attributeHelper);
8998
$this->bulkManagement = $bulkManagement;
@@ -96,6 +105,7 @@ public function __construct(
96105
->get(TimezoneInterface::class);
97106
$this->eavConfig = $eavConfig ?: ObjectManager::getInstance()
98107
->get(Config::class);
108+
$this->productFactory = $productFactory ?? ObjectManager::getInstance()->get(ProductFactory::class);
99109
}
100110

101111
/**
@@ -121,9 +131,10 @@ public function execute()
121131
$attributesData = $this->sanitizeProductAttributes($attributesData);
122132

123133
try {
134+
$this->validateProductAttributes($attributesData);
124135
$this->publish($attributesData, $websiteRemoveData, $websiteAddData, $storeId, $websiteId, $productIds);
125136
$this->messageManager->addSuccessMessage(__('Message is added to queue'));
126-
} catch (\Magento\Framework\Exception\LocalizedException $e) {
137+
} catch (LocalizedException $e) {
127138
$this->messageManager->addErrorMessage($e->getMessage());
128139
} catch (\Exception $e) {
129140
$this->messageManager->addExceptionMessage(
@@ -152,10 +163,12 @@ private function sanitizeProductAttributes($attributesData)
152163
}
153164

154165
$attribute = $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $attributeCode);
166+
155167
if (!$attribute->getAttributeId()) {
156168
unset($attributesData[$attributeCode]);
157169
continue;
158170
}
171+
159172
if ($attribute->getBackendType() === 'datetime') {
160173
if (!empty($value)) {
161174
$filterInput = new \Zend_Filter_LocalizedToNormalized(['date_format' => $dateFormat]);
@@ -183,6 +196,25 @@ private function sanitizeProductAttributes($attributesData)
183196
return $attributesData;
184197
}
185198

199+
/**
200+
* Validate product attributes data.
201+
*
202+
* @param array $attributesData
203+
*
204+
* @return void
205+
* @throws LocalizedException
206+
*/
207+
private function validateProductAttributes(array $attributesData): void
208+
{
209+
$product = $this->productFactory->create();
210+
$product->setData($attributesData);
211+
212+
foreach (array_keys($attributesData) as $attributeCode) {
213+
$attribute = $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $attributeCode);
214+
$attribute->getBackend()->validate($product);
215+
}
216+
}
217+
186218
/**
187219
* Schedule new bulk
188220
*
@@ -192,7 +224,7 @@ private function sanitizeProductAttributes($attributesData)
192224
* @param int $storeId
193225
* @param int $websiteId
194226
* @param array $productIds
195-
* @throws \Magento\Framework\Exception\LocalizedException
227+
* @throws LocalizedException
196228
*
197229
* @return void
198230
*/
@@ -246,7 +278,7 @@ private function publish(
246278
$this->userContext->getUserId()
247279
);
248280
if (!$result) {
249-
throw new \Magento\Framework\Exception\LocalizedException(
281+
throw new LocalizedException(
250282
__('Something went wrong while processing the request.')
251283
);
252284
}

app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ public function execute()
224224
return $this->returnResult('catalog/*/', [], ['error' => true]);
225225
}
226226
// entity type check
227-
if ($model->getEntityTypeId() != $this->_entityTypeId) {
227+
if ($model->getEntityTypeId() != $this->_entityTypeId || array_key_exists('backend_model', $data)) {
228228
$this->messageManager->addErrorMessage(__('We can\'t update the attribute.'));
229229
$this->_session->setAttributeData($data);
230230
return $this->returnResult('catalog/*/', [], ['error' => true]);
@@ -261,6 +261,8 @@ public function execute()
261261
unset($data['apply_to']);
262262
}
263263

264+
unset($data['entity_type_id']);
265+
264266
$model->addData($data);
265267

266268
if (!$attributeId) {
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Model\Product\Webapi\Rest;
9+
10+
use Magento\Framework\Webapi\Rest\Request\DeserializerInterface;
11+
use Magento\Framework\Webapi\Rest\Request\DeserializerFactory;
12+
use Magento\Framework\Webapi\Rest\Request;
13+
14+
/**
15+
* Class RequestTypeBasedDeserializer
16+
*
17+
* Used for deserialization rest request body.
18+
* Runs appropriate deserialization class object based on request body content type.
19+
*/
20+
class RequestTypeBasedDeserializer implements DeserializerInterface
21+
{
22+
/**
23+
* @var Request
24+
*/
25+
private $request;
26+
27+
/**
28+
* @var DeserializerFactory
29+
*/
30+
private $deserializeFactory;
31+
32+
/**
33+
* RequestTypeBasedDeserializer constructor.
34+
*
35+
* @param DeserializerFactory $deserializeFactory
36+
* @param Request $request
37+
*/
38+
public function __construct(
39+
DeserializerFactory $deserializeFactory,
40+
Request $request
41+
) {
42+
$this->deserializeFactory = $deserializeFactory;
43+
$this->request = $request;
44+
}
45+
46+
/**
47+
* @inheritdoc
48+
*
49+
* Parse request body into array of params with identifying request body content type
50+
* to use appropriate instance of deserializer class
51+
*
52+
* @param string $body Posted content from request
53+
* @return array|null Return NULL if content is invalid
54+
* @throws \Magento\Framework\Exception\InputException
55+
* @throws \Magento\Framework\Webapi\Exception
56+
*/
57+
public function deserialize($body)
58+
{
59+
$deserializer = $this->deserializeFactory->get($this->request->getContentType());
60+
return $deserializer->deserialize($body);
61+
}
62+
}

0 commit comments

Comments
 (0)