Skip to content

Commit 62bb081

Browse files
Merge branch '2.4.0-develop' into MC-29736
# Conflicts: # app/code/Magento/Ui/Controller/Index/Render.php
2 parents e8ecc49 + e4da7ad commit 62bb081

File tree

40 files changed

+1177
-235
lines changed

40 files changed

+1177
-235
lines changed

app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminDeleteRoleActionGroup.xml

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,32 @@
1010
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
1111
<actionGroup name="AdminDeleteRoleActionGroup">
1212
<annotations>
13-
<description>Deletes a User Role that contains the text 'Role'. PLEASE NOTE: The Action Group values are Hardcoded.</description>
13+
<description>Deletes a User Role.</description>
1414
</annotations>
1515
<arguments>
1616
<argument name="role" defaultValue=""/>
1717
</arguments>
1818

19-
<click stepKey="clickOnRole" selector="{{AdminDeleteRoleSection.theRole}}"/>
19+
<click stepKey="clickResetFilterButtonBefore" selector="{{AdminRoleGridSection.resetButton}}"/>
20+
<waitForPageLoad stepKey="waitForRolesGridFilterResetBefore" time="10"/>
21+
<fillField stepKey="TypeRoleFilter" selector="{{AdminRoleGridSection.roleNameFilterTextField}}" userInput="{{role.name}}"/>
22+
<waitForElementVisible stepKey="waitForFilterSearchButtonBefore" selector="{{AdminRoleGridSection.searchButton}}" time="10"/>
23+
<click stepKey="clickFilterSearchButton" selector="{{AdminRoleGridSection.searchButton}}"/>
24+
<waitForPageLoad stepKey="waitForUserRoleFilter" time="10"/>
25+
<waitForElementVisible stepKey="waitForRoleInRoleGrid" selector="{{AdminDeleteRoleSection.role(role.name)}}" time="10"/>
26+
<click stepKey="clickOnRole" selector="{{AdminDeleteRoleSection.role(role.name)}}"/>
27+
<waitForPageLoad stepKey="waitForRolePageToLoad" time="10"/>
2028
<fillField stepKey="TypeCurrentPassword" selector="{{AdminDeleteRoleSection.current_pass}}" userInput="{{_ENV.MAGENTO_ADMIN_PASSWORD}}"/>
29+
<waitForElementVisible stepKey="waitForDeleteRoleButton" selector="{{AdminDeleteRoleSection.delete}}" time="10"/>
2130
<click stepKey="clickToDeleteRole" selector="{{AdminDeleteRoleSection.delete}}"/>
22-
<waitForAjaxLoad stepKey="waitForDeleteConfirmationPopup" time="5"/>
31+
<waitForPageLoad stepKey="waitForDeleteConfirmationPopup" time="5"/>
32+
<waitForElementVisible stepKey="waitForConfirmButton" selector="{{AdminDeleteRoleSection.confirm}}" time="10"/>
2333
<click stepKey="clickToConfirm" selector="{{AdminDeleteRoleSection.confirm}}"/>
2434
<waitForPageLoad stepKey="waitForPageLoad" time="10"/>
2535
<see stepKey="seeSuccessMessage" userInput="You deleted the role."/>
36+
<waitForPageLoad stepKey="waitForRolesGridLoad" />
37+
<waitForElementVisible stepKey="waitForResetFilterButtonAfter" selector="{{AdminRoleGridSection.resetButton}}" time="10"/>
38+
<click stepKey="clickResetFilterButtonAfter" selector="{{AdminRoleGridSection.resetButton}}"/>
39+
<waitForPageLoad stepKey="waitForRolesGridFilterResetAfter" time="10"/>
2640
</actionGroup>
2741
</actionGroups>

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 & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -346,17 +346,16 @@ public function getIdentities()
346346

347347
$category = $this->getLayer()->getCurrentCategory();
348348
if ($category) {
349-
$identities[] = Product::CACHE_PRODUCT_CATEGORY_TAG . '_' . $category->getId();
349+
$identities[] = [Product::CACHE_PRODUCT_CATEGORY_TAG . '_' . $category->getId()];
350350
}
351351

352352
//Check if category page shows only static block (No products)
353-
if ($category->getData('display_mode') == Category::DM_PAGE) {
354-
return $identities;
355-
}
356-
357-
foreach ($this->_getProductCollection() as $item) {
358-
$identities = array_merge($identities, $item->getIdentities());
353+
if ($category->getData('display_mode') != Category::DM_PAGE) {
354+
foreach ($this->_getProductCollection() as $item) {
355+
$identities[] = $item->getIdentities();
356+
}
359357
}
358+
$identities = array_merge(...$identities);
360359

361360
return $identities;
362361
}
@@ -369,7 +368,7 @@ public function getIdentities()
369368
*/
370369
public function getAddToCartPostParams(Product $product)
371370
{
372-
$url = $this->getAddToCartUrl($product);
371+
$url = $this->getAddToCartUrl($product, ['_escape' => false]);
373372
return [
374373
'action' => $url,
375374
'data' => [

app/code/Magento/Catalog/Test/Unit/Block/Product/ListProductTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ public function testGetAddToCartPostParams()
217217
->will($this->returnValue(true));
218218
$this->cartHelperMock->expects($this->any())
219219
->method('getAddUrl')
220-
->with($this->equalTo($this->productMock), $this->equalTo([]))
220+
->with($this->equalTo($this->productMock), $this->equalTo(['_escape' => false]))
221221
->will($this->returnValue($url));
222222
$this->productMock->expects($this->once())
223223
->method('getEntityId')

app/code/Magento/Catalog/view/frontend/web/template/product/image_with_borders.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66
-->
77
<span class="product-image-container" data-bind="style: {width: width + 'px'}">
88
<span class="product-image-wrapper" data-bind="style: {'padding-bottom': height/width*100 + '%'}">
9-
<img class="product-image-photo" data-bind="attr: {src: src, alt: alt}, style: {width: width + 'px', height: height + 'px'}" />
9+
<img class="product-image-photo" data-bind="attr: {src: src, alt: alt}, style: {width: 'auto', height: 'auto'}" />
1010
</span>
1111
</span>
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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\CatalogSearch\Model\Search\FilterMapper;
9+
10+
use Magento\Catalog\Model\Product;
11+
use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver;
12+
use Magento\Eav\Model\Config as EavConfig;
13+
use Magento\Framework\DB\Select;
14+
use Magento\Framework\Search\Request\FilterInterface;
15+
16+
/**
17+
* Add stock status filter for each requested filter
18+
*/
19+
class CustomAttributeStockStatusFilter
20+
{
21+
/**
22+
* Suffix to append to filter name in order to generate stock status table alias for JOIN clause
23+
*/
24+
private const STOCK_STATUS_TABLE_ALIAS_SUFFIX = '_stock_index';
25+
/**
26+
* Attribute types to apply
27+
*/
28+
private const TARGET_ATTRIBUTE_TYPES = [
29+
'select',
30+
'multiselect'
31+
];
32+
/**
33+
* @var EavConfig
34+
*/
35+
private $eavConfig;
36+
/**
37+
* @var AliasResolver
38+
*/
39+
private $aliasResolver;
40+
/**
41+
* @var StockStatusQueryBuilder|null
42+
*/
43+
private $stockStatusQueryBuilder;
44+
45+
/**
46+
* @param EavConfig $eavConfig
47+
* @param AliasResolver $aliasResolver
48+
* @param StockStatusQueryBuilder $stockStatusQueryBuilder
49+
*/
50+
public function __construct(
51+
EavConfig $eavConfig,
52+
AliasResolver $aliasResolver,
53+
StockStatusQueryBuilder $stockStatusQueryBuilder
54+
) {
55+
$this->eavConfig = $eavConfig;
56+
$this->aliasResolver = $aliasResolver;
57+
$this->stockStatusQueryBuilder = $stockStatusQueryBuilder;
58+
}
59+
60+
/**
61+
* Apply stock status filter to provided filter
62+
*
63+
* @param Select $select
64+
* @param mixed $values
65+
* @param FilterInterface[] $filters
66+
* @return Select
67+
*/
68+
public function apply(Select $select, $values = null, FilterInterface ...$filters): Select
69+
{
70+
$select = clone $select;
71+
foreach ($filters as $filter) {
72+
if ($this->isApplicable($filter)) {
73+
$mainTableAlias = $this->aliasResolver->getAlias($filter);
74+
$stockTableAlias = $mainTableAlias . self::STOCK_STATUS_TABLE_ALIAS_SUFFIX;
75+
$select = $this->stockStatusQueryBuilder->apply(
76+
$select,
77+
$mainTableAlias,
78+
$stockTableAlias,
79+
'source_id',
80+
$values
81+
);
82+
}
83+
}
84+
return $select;
85+
}
86+
87+
/**
88+
* Check if stock status filter is applicable to provided filter
89+
*
90+
* @param FilterInterface $filter
91+
* @return bool
92+
*/
93+
private function isApplicable(FilterInterface $filter): bool
94+
{
95+
$attribute = $this->eavConfig->getAttribute(Product::ENTITY, $filter->getField());
96+
return $attribute
97+
&& $filter->getType() === FilterInterface::TYPE_TERM
98+
&& in_array($attribute->getFrontendInput(), self::TARGET_ATTRIBUTE_TYPES, true);
99+
}
100+
}

app/code/Magento/CatalogSearch/Model/Search/FilterMapper/FilterMapper.php

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@
99
use Magento\CatalogSearch\Model\Search\SelectContainer\SelectContainer;
1010
use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver;
1111
use Magento\CatalogInventory\Model\Stock;
12+
use Magento\Framework\App\ObjectManager;
1213

1314
/**
14-
* Class FilterMapper
1515
* This class applies filters to Select based on SelectContainer configuration
1616
*
17-
* @deprecated
17+
* @deprecated MySQL search engine is not recommended.
1818
* @see \Magento\ElasticSearch
19+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1920
*/
2021
class FilterMapper
2122
{
@@ -43,31 +44,38 @@ class FilterMapper
4344
* @var StockStatusFilter
4445
*/
4546
private $stockStatusFilter;
47+
/**
48+
* @var CustomAttributeStockStatusFilter
49+
*/
50+
private $customAttributeStockStatusFilter;
4651

4752
/**
4853
* @param AliasResolver $aliasResolver
4954
* @param CustomAttributeFilter $customAttributeFilter
5055
* @param FilterStrategyInterface $filterStrategy
5156
* @param VisibilityFilter $visibilityFilter
5257
* @param StockStatusFilter $stockStatusFilter
58+
* @param CustomAttributeStockStatusFilter|null $customAttributeStockStatusFilter
5359
*/
5460
public function __construct(
5561
AliasResolver $aliasResolver,
5662
CustomAttributeFilter $customAttributeFilter,
5763
FilterStrategyInterface $filterStrategy,
5864
VisibilityFilter $visibilityFilter,
59-
StockStatusFilter $stockStatusFilter
65+
StockStatusFilter $stockStatusFilter,
66+
?CustomAttributeStockStatusFilter $customAttributeStockStatusFilter = null
6067
) {
6168
$this->aliasResolver = $aliasResolver;
6269
$this->customAttributeFilter = $customAttributeFilter;
6370
$this->filterStrategy = $filterStrategy;
6471
$this->visibilityFilter = $visibilityFilter;
6572
$this->stockStatusFilter = $stockStatusFilter;
73+
$this->customAttributeStockStatusFilter = $customAttributeStockStatusFilter
74+
?? ObjectManager::getInstance()->get(CustomAttributeStockStatusFilter::class);
6675
}
6776

6877
/**
69-
* Applies filters to Select query in SelectContainer
70-
* based on SelectContainer configuration
78+
* Applies filters to Select query in SelectContainer based on SelectContainer configuration
7179
*
7280
* @param SelectContainer $selectContainer
7381
* @return SelectContainer
@@ -79,22 +87,22 @@ public function applyFilters(SelectContainer $selectContainer)
7987
{
8088
$select = $selectContainer->getSelect();
8189

82-
if ($selectContainer->hasCustomAttributesFilters()) {
83-
$select = $this->customAttributeFilter->apply($select, ...$selectContainer->getCustomAttributesFilters());
84-
}
85-
86-
$filterType = StockStatusFilter::FILTER_JUST_ENTITY;
87-
if ($selectContainer->hasCustomAttributesFilters()) {
88-
$filterType = StockStatusFilter::FILTER_ENTITY_AND_SUB_PRODUCTS;
89-
}
90-
9190
$select = $this->stockStatusFilter->apply(
9291
$select,
9392
Stock::STOCK_IN_STOCK,
94-
$filterType,
93+
StockStatusFilter::FILTER_JUST_ENTITY,
9594
$selectContainer->isShowOutOfStockEnabled()
9695
);
9796

97+
if ($selectContainer->hasCustomAttributesFilters()) {
98+
$select = $this->customAttributeFilter->apply($select, ...$selectContainer->getCustomAttributesFilters());
99+
$select = $this->customAttributeStockStatusFilter->apply(
100+
$select,
101+
$selectContainer->isShowOutOfStockEnabled() ? null : Stock::STOCK_IN_STOCK,
102+
...$selectContainer->getCustomAttributesFilters()
103+
);
104+
}
105+
98106
$appliedFilters = [];
99107

100108
if ($selectContainer->hasVisibilityFilter()) {

0 commit comments

Comments
 (0)