Skip to content

Commit ed54c48

Browse files
committed
Merge branch '2.4-develop' of https://github.com/magento-gl/magento2ce into L3_Arrows_PR_20220217
2 parents 516d810 + 15cf009 commit ed54c48

File tree

45 files changed

+1624
-163
lines changed

Some content is hidden

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

45 files changed

+1624
-163
lines changed

app/code/Magento/Catalog/Model/Attribute/ScopeOverriddenValue.php

Lines changed: 68 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
namespace Magento\Catalog\Model\Attribute;
88

9+
use Magento\Catalog\Model\AbstractModel;
10+
use Magento\Framework\DataObject;
911
use Magento\Framework\EntityManager\MetadataPool;
1012
use Magento\Eav\Api\AttributeRepositoryInterface as AttributeRepository;
1113
use Magento\Framework\Api\SearchCriteriaBuilder;
@@ -15,7 +17,6 @@
1517
use Magento\Framework\App\ResourceConnection;
1618

1719
/**
18-
* Class ScopeOverriddenValue
1920
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
2021
*/
2122
class ScopeOverriddenValue
@@ -76,7 +77,7 @@ public function __construct(
7677
* Whether attribute value is overridden in specific store
7778
*
7879
* @param string $entityType
79-
* @param \Magento\Catalog\Model\AbstractModel $entity
80+
* @param AbstractModel $entity
8081
* @param string $attributeCode
8182
* @param int|string $storeId
8283
* @return bool
@@ -86,39 +87,41 @@ public function containsValue($entityType, $entity, $attributeCode, $storeId)
8687
if ((int)$storeId === Store::DEFAULT_STORE_ID) {
8788
return false;
8889
}
89-
if (!isset($this->attributesValues[$storeId])) {
90+
$values = $this->getAttributesValues($entityType, $entity);
91+
92+
if (!isset($values[$storeId])) {
9093
$this->initAttributeValues($entityType, $entity, (int)$storeId);
94+
$values = $this->getAttributesValues($entityType, $entity);
9195
}
9296

93-
return isset($this->attributesValues[$storeId])
94-
&& array_key_exists($attributeCode, $this->attributesValues[$storeId]);
97+
return isset($values[$storeId]) && array_key_exists($attributeCode, $values[$storeId]);
9598
}
9699

97100
/**
98101
* Get attribute default values
99102
*
100103
* @param string $entityType
101-
* @param \Magento\Catalog\Model\AbstractModel $entity
104+
* @param AbstractModel $entity
102105
* @return array
103106
*
104107
* @deprecated 101.0.0
105108
*/
106109
public function getDefaultValues($entityType, $entity)
107110
{
108-
if ($this->attributesValues === null) {
111+
$values = $this->getAttributesValues($entityType, $entity);
112+
if (!isset($values[Store::DEFAULT_STORE_ID])) {
109113
$this->initAttributeValues($entityType, $entity, (int)$entity->getStoreId());
114+
$values = $this->getAttributesValues($entityType, $entity);
110115
}
111116

112-
return isset($this->attributesValues[Store::DEFAULT_STORE_ID])
113-
? $this->attributesValues[Store::DEFAULT_STORE_ID]
114-
: [];
117+
return $values[Store::DEFAULT_STORE_ID] ?? [];
115118
}
116119

117120
/**
118121
* Init attribute values.
119122
*
120123
* @param string $entityType
121-
* @param \Magento\Catalog\Model\AbstractModel $entity
124+
* @param AbstractModel $entity
122125
* @param int $storeId
123126
* @throws \Magento\Framework\Exception\LocalizedException
124127
* @return void
@@ -129,6 +132,7 @@ private function initAttributeValues($entityType, $entity, $storeId)
129132
/** @var \Magento\Eav\Model\Entity\Attribute\AbstractAttribute $attribute */
130133
$attributeTables = [];
131134
if ($metadata->getEavEntityType()) {
135+
$entityId = $entity->getData($metadata->getLinkField());
132136
foreach ($this->getAttributes($entityType) as $attribute) {
133137
if (!$attribute->isStatic()) {
134138
$attributeTables[$attribute->getBackend()->getTable()][] = $attribute->getAttributeId();
@@ -147,7 +151,7 @@ private function initAttributeValues($entityType, $entity, $storeId)
147151
'a.attribute_id = t.attribute_id',
148152
['attribute_code' => 'a.attribute_code']
149153
)
150-
->where($metadata->getLinkField() . ' = ?', $entity->getData($metadata->getLinkField()))
154+
->where($metadata->getLinkField() . ' = ?', $entityId)
151155
->where('t.attribute_id IN (?)', $attributeCodes)
152156
->where('t.store_id IN (?)', $storeIds);
153157
$selects[] = $select;
@@ -158,9 +162,12 @@ private function initAttributeValues($entityType, $entity, $storeId)
158162
\Magento\Framework\DB\Select::SQL_UNION_ALL
159163
);
160164
$attributes = $metadata->getEntityConnection()->fetchAll((string)$unionSelect);
165+
$values = array_fill_keys($storeIds, []);
161166
foreach ($attributes as $attribute) {
162-
$this->attributesValues[$attribute['store_id']][$attribute['attribute_code']] = $attribute['value'];
167+
$values[$attribute['store_id']][$attribute['attribute_code']] = $attribute['value'];
163168
}
169+
$values += $this->getAttributesValues($entityType, $entity);
170+
$this->setAttributesValues($entityType, $entity, $values);
164171
}
165172
}
166173

@@ -187,4 +194,52 @@ private function getAttributes($entityType)
187194
);
188195
return $searchResult->getItems();
189196
}
197+
198+
/**
199+
* Clear entity attributes values cache
200+
*
201+
* @param string $entityType
202+
* @param DataObject $entity
203+
* @return void
204+
* @throws \Exception
205+
*/
206+
public function clearAttributesValues(string $entityType, DataObject $entity): void
207+
{
208+
if (isset($this->attributesValues[$entityType])) {
209+
$metadata = $this->metadataPool->getMetadata($entityType);
210+
$entityId = $entity->getData($metadata->getLinkField());
211+
unset($this->attributesValues[$entityType][$entityId]);
212+
}
213+
}
214+
215+
/**
216+
* Get entity attributes values from cache
217+
*
218+
* @param string $entityType
219+
* @param DataObject $entity
220+
* @return array
221+
* @throws \Exception
222+
*/
223+
private function getAttributesValues(string $entityType, DataObject $entity): array
224+
{
225+
$metadata = $this->metadataPool->getMetadata($entityType);
226+
$entityId = $entity->getData($metadata->getLinkField());
227+
return $this->attributesValues[$entityType][$entityId] ?? [];
228+
}
229+
230+
/**
231+
* Set entity attributes values into cache
232+
*
233+
* @param string $entityType
234+
* @param DataObject $entity
235+
* @param array $values
236+
* @return void
237+
* @throws \Exception
238+
*/
239+
private function setAttributesValues(string $entityType, DataObject $entity, array $values): void
240+
{
241+
$metadata = $this->metadataPool->getMetadata($entityType);
242+
$entityId = $entity->getData($metadata->getLinkField());
243+
$this->attributesValues[$entityType][$entityId] = $values;
244+
}
190245
}

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

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
*/
66
namespace Magento\Catalog\Model\ResourceModel;
77

8+
use Magento\Catalog\Api\Data\ProductInterface;
9+
use Magento\Catalog\Model\Attribute\ScopeOverriddenValue;
810
use Magento\Catalog\Model\ResourceModel\Product\Website\Link as ProductWebsiteLink;
911
use Magento\Eav\Api\AttributeManagementInterface;
1012
use Magento\Framework\App\ObjectManager;
@@ -40,15 +42,11 @@ class Product extends AbstractResource
4042
protected $_productCategoryTable;
4143

4244
/**
43-
* Catalog category
44-
*
4545
* @var Category
4646
*/
4747
protected $_catalogCategory;
4848

4949
/**
50-
* Category collection factory
51-
*
5250
* @var Category\CollectionFactory
5351
*/
5452
protected $_categoryCollectionFactory;
@@ -105,6 +103,11 @@ class Product extends AbstractResource
105103
*/
106104
private $mediaImageDeleteProcessor;
107105

106+
/**
107+
* @var ScopeOverriddenValue
108+
*/
109+
private $scopeOverriddenValue;
110+
108111
/**
109112
* @param \Magento\Eav\Model\Entity\Context $context
110113
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
@@ -120,6 +123,7 @@ class Product extends AbstractResource
120123
* @param UniqueValidationInterface|null $uniqueValidator
121124
* @param AttributeManagementInterface|null $eavAttributeManagement
122125
* @param MediaImageDeleteProcessor|null $mediaImageDeleteProcessor
126+
* @param ScopeOverriddenValue|null $scopeOverriddenValue
123127
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
124128
*/
125129
public function __construct(
@@ -136,7 +140,8 @@ public function __construct(
136140
TableMaintainer $tableMaintainer = null,
137141
UniqueValidationInterface $uniqueValidator = null,
138142
AttributeManagementInterface $eavAttributeManagement = null,
139-
?MediaImageDeleteProcessor $mediaImageDeleteProcessor = null
143+
?MediaImageDeleteProcessor $mediaImageDeleteProcessor = null,
144+
?ScopeOverriddenValue $scopeOverriddenValue = null
140145
) {
141146
$this->_categoryCollectionFactory = $categoryCollectionFactory;
142147
$this->_catalogCategory = $catalogCategory;
@@ -157,6 +162,8 @@ public function __construct(
157162
?? ObjectManager::getInstance()->get(AttributeManagementInterface::class);
158163
$this->mediaImageDeleteProcessor = $mediaImageDeleteProcessor
159164
?? ObjectManager::getInstance()->get(MediaImageDeleteProcessor::class);
165+
$this->scopeOverriddenValue = $scopeOverriddenValue
166+
?? ObjectManager::getInstance()->get(ScopeOverriddenValue::class);
160167
}
161168

162169
/**
@@ -316,6 +323,7 @@ protected function _afterSave(DataObject $product)
316323
{
317324
$this->removeNotInSetAttributeValues($product);
318325
$this->_saveWebsiteIds($product)->_saveCategories($product);
326+
$this->scopeOverriddenValue->clearAttributesValues(ProductInterface::class, $product);
319327
return parent::_afterSave($product);
320328
}
321329

app/code/Magento/Catalog/Pricing/Price/TierPrice.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class TierPrice extends AbstractPrice implements TierPriceInterface, BasePricePr
3333
/**
3434
* Price type tier
3535
*/
36-
const PRICE_CODE = 'tier_price';
36+
public const PRICE_CODE = 'tier_price';
3737

3838
/**
3939
* @var Session
@@ -176,10 +176,13 @@ public function getTierPriceList()
176176
function (&$priceData) {
177177
/* convert string value to float */
178178
$priceData['price_qty'] *= 1;
179-
if ($this->getConfigTaxDisplayType() === Config::DISPLAY_TYPE_BOTH) {
180-
$exclTaxPrice = $this->calculator->getAmount($priceData['price'], $this->product);
179+
$exclTaxPrice = $this->calculator->getAmount($priceData['price'], $this->product);
180+
if ($this->getConfigTaxDisplayType() === Config::DISPLAY_TYPE_EXCLUDING_TAX) {
181181
$priceData['excl_tax_price'] = $exclTaxPrice;
182182
}
183+
if ($this->getConfigTaxDisplayType() === Config::DISPLAY_TYPE_BOTH) {
184+
$priceData['incl_excl_tax_price'] = $exclTaxPrice;
185+
}
183186
$priceData['price'] = $this->applyAdjustment($priceData['price']);
184187
}
185188
);
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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\Test\Fixture;
9+
10+
use Magento\Framework\DataObject;
11+
12+
class MultiselectAttribute extends SelectAttribute
13+
{
14+
private const DEFAULT_DATA = [
15+
'frontend_input' => 'multiselect',
16+
];
17+
18+
/**
19+
* @inheritdoc
20+
*/
21+
public function apply(array $data = []): ?DataObject
22+
{
23+
$data = $this->prepareData($data);
24+
25+
return parent::apply($data);
26+
}
27+
28+
/**
29+
* Prepare attribute data
30+
*
31+
* @param array $data
32+
* @return array
33+
*/
34+
private function prepareData(array $data): array
35+
{
36+
$data = array_merge(self::DEFAULT_DATA, $data);
37+
38+
return $data;
39+
}
40+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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\Test\Fixture;
9+
10+
use Magento\Framework\DataObject;
11+
12+
class SelectAttribute extends Attribute
13+
{
14+
private const DEFAULT_DATA = [
15+
'frontend_input' => 'select',
16+
'options' => [
17+
[
18+
'label' => 'option_1',
19+
'sort_order' => 0,
20+
],
21+
[
22+
'label' => 'option_2',
23+
'sort_order' => 1,
24+
],
25+
],
26+
];
27+
28+
/**
29+
* {@inheritdoc}
30+
* @param array $data Parameters. Same format as \Magento\Catalog\Test\Fixture\Attribute::DEFAULT_DATA.
31+
* Additional fields:
32+
* - $data['options']: Array of options.
33+
* Option ID can be retrieved as follows:
34+
* <pre>
35+
* $attribute->getData('option_1')
36+
* </pre>
37+
*/
38+
public function apply(array $data = []): ?DataObject
39+
{
40+
$data = $this->prepareData($data);
41+
42+
$attribute = parent::apply($data);
43+
44+
// add options data to attribute data [option_label => option_id]
45+
$options = $attribute->getSource()->getAllOptions(false);
46+
$attribute->addData(array_column($options, 'value', 'label'));
47+
48+
return $attribute;
49+
}
50+
51+
/**
52+
* Prepare attribute data
53+
*
54+
* @param array $data
55+
* @return array
56+
*/
57+
private function prepareData(array $data): array
58+
{
59+
$data = array_merge(self::DEFAULT_DATA, $data);
60+
61+
$options = [];
62+
$sortOrder = 0;
63+
foreach ($data['options'] as $option) {
64+
$options[] = [
65+
'label' => is_array($option) ? $option['label'] : $option,
66+
'sort_order' => $sortOrder++,
67+
];
68+
}
69+
70+
$data['options'] = $options;
71+
72+
return $data;
73+
}
74+
}

app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,8 +341,13 @@ private function getTierPricesByProduct(ProductInterface $product): array
341341
];
342342

343343
if (isset($tierPrice['excl_tax_price'])) {
344-
$excludingTax = $tierPrice['excl_tax_price'];
345-
$tierPriceData['excl_tax_price'] = $this->localeFormat->getNumber($excludingTax->getBaseAmount());
344+
$exclTax = $tierPrice['excl_tax_price'];
345+
$tierPriceData['excl_tax_price'] = $this->localeFormat->getNumber($exclTax->getBaseAmount());
346+
}
347+
348+
if (isset($tierPrice['incl_excl_tax_price'])) {
349+
$inclExclTax = $tierPrice['incl_excl_tax_price'];
350+
$tierPriceData['incl_excl_tax_price'] = $this->localeFormat->getNumber($inclExclTax->getBaseAmount());
346351
}
347352
$tierPrices[] = $tierPriceData;
348353
}

app/code/Magento/ConfigurableProduct/Test/Mftf/Section/StorefrontProductInfoMainSection.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@
2424
<element name="attributeSelectByAttributeID" type="select" selector="//div[@class='fieldset']//div[//span[text()='{{attribute_code}}']]//select" parameterized="true"/>
2525
<element name="attributeOptionByAttributeID" type="select" selector="//div[@class='fieldset']//div[//span[text()='{{attribute_code}}']]//option[text()='{{optionName}}']" parameterized="true"/>
2626
<element name="tierPriceExcludingPrice" type="text" selector=".item [data-label='Excl. Tax']"/>
27+
<element name="tierPriceContainsExcludingTax" type="text" selector=".item .price"/>
2728
</section>
2829
</sections>

0 commit comments

Comments
 (0)