Skip to content

Commit 2b3ad2e

Browse files
Merge pull request #8523 from magento-l3/PR_06_SEP_2023
L3 Bugfix delivery
2 parents ea257d6 + 16922f5 commit 2b3ad2e

File tree

13 files changed

+324
-102
lines changed

13 files changed

+324
-102
lines changed

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,15 +311,14 @@ private function reindexByBatchWithDimensions(
311311
if (!empty($entityIds)) {
312312
$this->dimensionTableMaintainer->createMainTmpTable($dimensions);
313313
$temporaryTable = $this->dimensionTableMaintainer->getMainTmpTable($dimensions);
314-
$this->_emptyTable($temporaryTable);
315-
316314
$priceIndexer->executeByDimensions($dimensions, \SplFixedArray::fromArray($entityIds, false));
317315

318316
// Sync data from temp table to index table
319317
$this->_insertFromTable(
320318
$temporaryTable,
321319
$this->dimensionTableMaintainer->getMainReplicaTable($dimensions)
322320
);
321+
$this->_defaultIndexerResource->getConnection()->dropTable($temporaryTable);
323322
}
324323
}
325324

@@ -354,7 +353,6 @@ private function reindexBatch(PriceInterface $priceIndexer, Select $batch): void
354353
if (!empty($entityIds)) {
355354
// Temporary table will created if not exists
356355
$idxTableName = $this->_defaultIndexerResource->getIdxTable();
357-
$this->_emptyTable($idxTableName);
358356

359357
if ($priceIndexer->getIsComposite()) {
360358
$this->_copyRelationIndexData($entityIds);
@@ -489,6 +487,7 @@ private function moveDataFromReplicaTableToReplicaTables(array $dimensions): voi
489487
* Retrieves the index table that should be used
490488
*
491489
* @deprecated 102.0.6
490+
* @see only used in another deprecated method: _copyRelationIndexData
492491
*/
493492
protected function getIndexTargetTable(): string
494493
{

app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/CustomOptionPriceModifier.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,8 @@ public function modifyPrice(IndexTableStructure $priceTable, array $entityIds =
122122
$query = $select->crossUpdateFromSelect(['i' => $finalPriceTable]);
123123
$connection->query($query);
124124

125-
$connection->delete($coaTable);
126-
$connection->delete($copTable);
125+
$connection->dropTemporaryTable($coaTable);
126+
$connection->dropTemporaryTable($copTable);
127127
}
128128

129129
/**

app/code/Magento/Catalog/Test/Fixture/Attribute.php

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

88
namespace Magento\Catalog\Test\Fixture;
99

10-
use Magento\Catalog\Api\Data\ProductAttributeInterface;
1110
use Magento\Catalog\Api\ProductAttributeManagementInterface;
1211
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
1312
use Magento\Catalog\Model\Product;
@@ -96,6 +95,11 @@ class Attribute implements RevertibleDataFixtureInterface
9695
*/
9796
private ResourceModelAttribute $resourceModelAttribute;
9897

98+
/**
99+
* @var ProductAttributeRepositoryInterface
100+
*/
101+
private ProductAttributeRepositoryInterface $productAttributeRepository;
102+
99103
/**
100104
* @param ServiceFactory $serviceFactory
101105
* @param ProcessorInterface $dataProcessor
@@ -104,6 +108,7 @@ class Attribute implements RevertibleDataFixtureInterface
104108
* @param AttributeFactory $attributeFactory
105109
* @param DataMerger $dataMerger
106110
* @param ResourceModelAttribute $resourceModelAttribute
111+
* @param ProductAttributeRepositoryInterface $productAttributeRepository
107112
*/
108113
public function __construct(
109114
ServiceFactory $serviceFactory,
@@ -112,7 +117,8 @@ public function __construct(
112117
ProductAttributeManagementInterface $productAttributeManagement,
113118
AttributeFactory $attributeFactory,
114119
DataMerger $dataMerger,
115-
ResourceModelAttribute $resourceModelAttribute
120+
ResourceModelAttribute $resourceModelAttribute,
121+
ProductAttributeRepositoryInterface $productAttributeRepository
116122
) {
117123
$this->serviceFactory = $serviceFactory;
118124
$this->dataProcessor = $dataProcessor;
@@ -121,6 +127,7 @@ public function __construct(
121127
$this->attributeFactory = $attributeFactory;
122128
$this->dataMerger = $dataMerger;
123129
$this->resourceModelAttribute = $resourceModelAttribute;
130+
$this->productAttributeRepository = $productAttributeRepository;
124131
}
125132

126133
/**
@@ -134,16 +141,11 @@ public function apply(array $data = []): ?DataObject
134141
return $this->applyAttributeWithAdditionalData($data);
135142
}
136143

137-
$service = $this->serviceFactory->create(ProductAttributeRepositoryInterface::class, 'save');
138-
139-
/**
140-
* @var ProductAttributeInterface $attribute
141-
*/
142-
$attribute = $service->execute(
143-
[
144-
'attribute' => $this->prepareData(array_diff_key($data, self::DEFAULT_ATTRIBUTE_SET_DATA))
145-
]
144+
$attribute = $this->attributeFactory->createAttribute(
145+
EavAttribute::class,
146+
$this->prepareData(array_diff_key($data, self::DEFAULT_ATTRIBUTE_SET_DATA))
146147
);
148+
$attribute = $this->productAttributeRepository->save($attribute);
147149

148150
$attributeSetData = $this->prepareAttributeSetData(
149151
array_intersect_key($data, self::DEFAULT_ATTRIBUTE_SET_DATA)
@@ -201,6 +203,7 @@ private function applyAttributeWithAdditionalData(array $data = []): ?DataObject
201203
private function prepareData(array $data): array
202204
{
203205
$data = array_merge(self::DEFAULT_DATA, $data);
206+
$data['frontend_label'] ??= $data['default_frontend_label'];
204207

205208
return $this->dataProcessor->process($this, $data);
206209
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
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\Unit\Model\Indexer\Product\Price;
9+
10+
use Magento\Catalog\Helper\Data;
11+
use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\CustomOptionPriceModifier;
12+
use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\IndexTableStructure;
13+
use Magento\Framework\App\ResourceConnection;
14+
use Magento\Framework\DB\Adapter\AdapterInterface;
15+
use Magento\Framework\DB\Select;
16+
use Magento\Framework\DB\Sql\ColumnValueExpressionFactory;
17+
use Magento\Framework\EntityManager\EntityMetadataInterface;
18+
use Magento\Framework\EntityManager\MetadataPool;
19+
use Magento\Framework\Indexer\Table\StrategyInterface;
20+
use PHPUnit\Framework\MockObject\MockObject;
21+
use PHPUnit\Framework\TestCase;
22+
23+
class CustomOptionPriceModifierTest extends TestCase
24+
{
25+
/**
26+
* @var ResourceConnection|MockObject
27+
*/
28+
private ResourceConnection $resource;
29+
30+
/**
31+
* @var MetadataPool|MockObject
32+
*/
33+
private MetadataPool $metadataPool;
34+
35+
/**
36+
* @var ColumnValueExpressionFactory|MockObject
37+
*/
38+
private ColumnValueExpressionFactory $columnValueExpressionFactory;
39+
40+
/**
41+
* @var Data|MockObject
42+
*/
43+
private Data $dataHelper;
44+
45+
/**
46+
* @var StrategyInterface|MockObject
47+
*/
48+
private StrategyInterface $tableStrategy;
49+
50+
/**
51+
* @var CustomOptionPriceModifier
52+
*/
53+
private CustomOptionPriceModifier $priceModifier;
54+
55+
/**
56+
* @return void
57+
*/
58+
protected function setUp(): void
59+
{
60+
$this->resource = $this->createMock(ResourceConnection::class);
61+
$this->metadataPool = $this->createMock(MetadataPool::class);
62+
$this->columnValueExpressionFactory = $this->createMock(ColumnValueExpressionFactory::class);
63+
$this->dataHelper = $this->createMock(Data::class);
64+
$this->tableStrategy = $this->createMock(StrategyInterface::class);
65+
$this->priceModifier = new CustomOptionPriceModifier(
66+
$this->resource,
67+
$this->metadataPool,
68+
$this->columnValueExpressionFactory,
69+
$this->dataHelper,
70+
$this->tableStrategy
71+
);
72+
73+
parent::setUp();
74+
}
75+
76+
/**
77+
* @return void
78+
* @throws \Exception
79+
*/
80+
public function testModifyPrice(): void
81+
{
82+
$priceTable = $this->createMock(IndexTableStructure::class);
83+
$priceTable->expects($this->exactly(2))->method('getTableName')->willReturn('temporary_table_name');
84+
85+
$select = $this->createMock(Select::class);
86+
$select->expects($this->any())->method('from')->willReturn($select);
87+
$select->expects($this->any())->method('join')->willReturn($select);
88+
$select->expects($this->any())->method('group')->willReturn($select);
89+
$select->expects($this->any())->method('columns')->willReturn($select);
90+
91+
$connection = $this->createMock(AdapterInterface::class);
92+
$connection->expects($this->exactly(2))->method('delete');
93+
$connection->expects($this->any())->method('select')->willReturn($select);
94+
$connection->expects($this->any())->method('fetchRow')->willReturn(['exists']);
95+
$connection->expects($this->exactly(4))->method('query');
96+
$connection->expects($this->exactly(2))->method('dropTemporaryTable');
97+
$this->resource->expects($this->any())->method('getConnection')->willReturn($connection);
98+
$this->resource->expects($this->any())->method('getTableName')->willReturn('table');
99+
$this->tableStrategy->expects($this->any())
100+
->method('getTableName')
101+
->willReturn('table_name');
102+
103+
$metadata = $this->createMock(EntityMetadataInterface::class);
104+
$this->metadataPool->expects($this->any())->method('getMetadata')->willReturn($metadata);
105+
$this->dataHelper->expects($this->once())->method('isPriceGlobal')->willReturn(true);
106+
107+
$this->priceModifier->modifyPrice($priceTable);
108+
}
109+
}

app/code/Magento/CatalogGraphQl/DataProvider/Product/LayeredNavigation/AttributeOptionProvider.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ public function getOptions(array $optionIds, ?int $storeId, array $attributeCode
6464
'attribute_code' => 'a.attribute_code',
6565
'attribute_label' => 'a.frontend_label',
6666
'attribute_type' => 'a.frontend_input',
67-
'position' => 'attribute_configuration.position'
67+
'position' => 'attribute_configuration.position',
68+
'is_filterable' => 'attribute_configuration.is_filterable',
6869
]
6970
)
7071
->joinLeft(
@@ -107,7 +108,7 @@ public function getOptions(array $optionIds, ?int $storeId, array $attributeCode
107108
'options.sort_order ' . Select::SQL_ASC
108109
);
109110

110-
$select->where('option_value.option_id IN (?)', $optionIds);
111+
$select->where('option_value.option_id IN (?) OR attribute_configuration.is_filterable = 2', $optionIds);
111112

112113
if (!empty($attributeCodes)) {
113114
$select->orWhere(
@@ -136,10 +137,10 @@ private function formatResult(Select $select): array
136137
$result[$option['attribute_code']] = [
137138
'attribute_id' => $option['attribute_id'],
138139
'attribute_code' => $option['attribute_code'],
139-
'attribute_label' => $option['attribute_store_label']
140-
? $option['attribute_store_label'] : $option['attribute_label'],
140+
'attribute_label' => $option['attribute_store_label'] ?: $option['attribute_label'],
141141
'attribute_type' => $option['attribute_type'],
142142
'position' => $option['position'],
143+
'is_filterable' => (int) $option['is_filterable'],
143144
'options' => [],
144145
];
145146
}

app/code/Magento/CatalogGraphQl/DataProvider/Product/LayeredNavigation/Builder/Attribute.php

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class Attribute implements LayerBuilderInterface
3232
*/
3333
private const CATEGORY_BUCKET = 'category_bucket';
3434

35+
private const ATTRIBUTE_OPTIONS_ONLY_WITH_RESULTS = 1;
36+
3537
/**
3638
* @var AttributeOptionProvider
3739
*/
@@ -91,23 +93,21 @@ public function build(AggregationInterface $aggregation, ?int $storeId): array
9193

9294
$result[$bucketName] = $this->layerFormatter->buildLayer(
9395
$attribute['attribute_label'] ?? $bucketName,
94-
\count($bucket->getValues()),
96+
0,
9597
$attribute['attribute_code'] ?? $bucketName,
9698
isset($attribute['position']) ? $attribute['position'] : null
9799
);
98-
99-
$options = $this->getSortedOptions(
100-
$bucket,
101-
isset($attribute['options']) ? $attribute['options'] : [],
102-
($attribute['attribute_type']) ? $attribute['attribute_type']: ''
103-
);
104-
foreach ($options as $option) {
105-
$result[$bucketName]['options'][] = $this->layerFormatter->buildItem(
106-
$option['label'],
107-
$option['value'],
108-
$option['count']
100+
$optionLabels = $attribute['attribute_type'] === 'boolean'
101+
? $this->YesNo->toArray()
102+
: $attribute['options'] ?? [];
103+
$result[$bucketName]['options'] = $this->getSortedOptions($bucket, $optionLabels);
104+
if (self::ATTRIBUTE_OPTIONS_ONLY_WITH_RESULTS === $attribute['is_filterable']) {
105+
$result[$bucketName]['options'] = array_filter(
106+
$result[$bucketName]['options'],
107+
fn ($option) => $option['count']
109108
);
110109
}
110+
$result[$bucketName]['count'] = count($result[$bucketName]['options']);
111111
}
112112

113113
return $result;
@@ -181,38 +181,24 @@ function (AggregationValueInterface $value) {
181181
*
182182
* @param BucketInterface $bucket
183183
* @param array $optionLabels
184-
* @param string $attributeType
185184
* @return array
186-
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
187185
*/
188-
private function getSortedOptions(BucketInterface $bucket, array $optionLabels, string $attributeType): array
186+
private function getSortedOptions(BucketInterface $bucket, array $optionLabels): array
189187
{
188+
$options = [];
190189
/**
191190
* Option labels array has been sorted
192191
*/
193-
$options = $optionLabels;
192+
foreach ($optionLabels as $optionId => $optionLabel) {
193+
$options[$optionId] = $this->layerFormatter->buildItem($optionLabel, $optionId, 0);
194+
}
194195
foreach ($bucket->getValues() as $value) {
195196
$metrics = $value->getMetrics();
196-
$optionValue = $metrics['value'];
197-
if (isset($optionLabels[$optionValue])) {
198-
$optionLabel = $optionLabels[$optionValue];
197+
$optionId = $metrics['value'];
198+
if (isset($options[$optionId])) {
199+
$options[$optionId]['count'] = $metrics['count'];
199200
} else {
200-
if ($attributeType === 'boolean') {
201-
$yesNoOptions = $this->YesNo->toArray();
202-
$optionLabel = $yesNoOptions[$optionValue];
203-
} else {
204-
$optionLabel = $optionValue;
205-
}
206-
}
207-
$options[$optionValue] = $metrics + ['label' => $optionLabel];
208-
}
209-
210-
/**
211-
* Delete options without bucket values
212-
*/
213-
foreach ($options as $optionId => $option) {
214-
if (!is_array($options[$optionId])) {
215-
unset($options[$optionId]);
201+
$options[$optionId] = $this->layerFormatter->buildItem($optionId, $optionId, $metrics['count']);
216202
}
217203
}
218204

app/code/Magento/Search/Model/ResourceModel/Query/Collection.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,9 @@ public function setPopularQueryFilter($storeIds = null)
150150

151151
$storeIds = $storeIds ?: $this->_storeManager->getStore()->getId();
152152
$this->addStoreFilter($storeIds);
153-
$this->getSelect()->where('num_results > 0');
153+
$this->getSelect()->where('main_table.num_results > 0');
154154

155-
$this->getSelect()->order(['popularity desc']);
155+
$this->getSelect()->order(['main_table.popularity desc']);
156156

157157
return $this;
158158
}
@@ -174,8 +174,8 @@ public function isTopSearchResult(string $term, int $storeId, int $maxCountCache
174174
$select->distinct(true);
175175
$select->from(['main_table' => $this->getTable('search_query')], ['query_text']);
176176
$select->where('main_table.store_id IN (?)', $storeId);
177-
$select->where('num_results > 0');
178-
$select->order(['popularity desc']);
177+
$select->where('main_table.num_results > 0');
178+
$select->order(['main_table.popularity desc']);
179179

180180
$select->limit($maxCountCacheableSearchTerms);
181181

@@ -208,7 +208,7 @@ public function setRecentQueryFilter()
208208
public function addStoreFilter($storeIds)
209209
{
210210
$condition = is_array($storeIds) ? 'main_table.store_id IN (?)' : 'main_table.store_id = ?';
211-
$this->getSelect()->where($condition, $storeIds);
211+
$this->getSelect()->where($condition, $storeIds, \Zend_Db::INT_TYPE);
212212

213213
return $this;
214214
}

0 commit comments

Comments
 (0)