Skip to content

Commit ced96c1

Browse files
authored
Merge pull request #3450 from magento-performance/MAGETWO-96118
[performance] MAGETWO-96118: Few optimizations on category & product pages
2 parents 8f6eeb8 + 0081bad commit ced96c1

File tree

11 files changed

+192
-101
lines changed

11 files changed

+192
-101
lines changed

app/code/Magento/Catalog/Model/Product/Gallery/ReadHandler.php

+15-34
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ public function __construct(
4747
}
4848

4949
/**
50+
* Execute read handler for catalog product gallery
51+
*
5052
* @param Product $entity
5153
* @param array $arguments
5254
* @return object
@@ -55,9 +57,6 @@ public function __construct(
5557
*/
5658
public function execute($entity, $arguments = [])
5759
{
58-
$value = [];
59-
$value['images'] = [];
60-
6160
$mediaEntries = $this->resourceModel->loadProductGalleryByAttributeId(
6261
$entity,
6362
$this->getAttribute()->getAttributeId()
@@ -72,47 +71,27 @@ public function execute($entity, $arguments = [])
7271
}
7372

7473
/**
74+
* Add media data to product
75+
*
7576
* @param Product $product
7677
* @param array $mediaEntries
7778
* @return void
7879
* @since 101.0.1
7980
*/
8081
public function addMediaDataToProduct(Product $product, array $mediaEntries)
8182
{
82-
$attrCode = $this->getAttribute()->getAttributeCode();
83-
$value = [];
84-
$value['images'] = [];
85-
$value['values'] = [];
86-
87-
foreach ($mediaEntries as $mediaEntry) {
88-
$mediaEntry = $this->substituteNullsWithDefaultValues($mediaEntry);
89-
$value['images'][$mediaEntry['value_id']] = $mediaEntry;
90-
}
91-
$product->setData($attrCode, $value);
92-
}
93-
94-
/**
95-
* @param array $rawData
96-
* @return array
97-
*/
98-
private function substituteNullsWithDefaultValues(array $rawData)
99-
{
100-
$processedData = [];
101-
foreach ($rawData as $key => $rawValue) {
102-
if (null !== $rawValue) {
103-
$processedValue = $rawValue;
104-
} elseif (isset($rawData[$key . '_default'])) {
105-
$processedValue = $rawData[$key . '_default'];
106-
} else {
107-
$processedValue = null;
108-
}
109-
$processedData[$key] = $processedValue;
110-
}
111-
112-
return $processedData;
83+
$product->setData(
84+
$this->getAttribute()->getAttributeCode(),
85+
[
86+
'images' => array_column($mediaEntries, null, 'value_id'),
87+
'values' => []
88+
]
89+
);
11390
}
11491

11592
/**
93+
* Get attribute
94+
*
11695
* @return \Magento\Catalog\Api\Data\ProductAttributeInterface
11796
* @since 101.0.0
11897
*/
@@ -126,6 +105,8 @@ public function getAttribute()
126105
}
127106

128107
/**
108+
* Find default value
109+
*
129110
* @param string $key
130111
* @param string[] &$image
131112
* @return string

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

+28-5
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ public function __construct(
4949
}
5050

5151
/**
52-
* {@inheritdoc}
52+
* @inheritdoc
53+
*
5354
* @since 101.0.0
5455
*/
5556
protected function _construct()
@@ -58,7 +59,8 @@ protected function _construct()
5859
}
5960

6061
/**
61-
* {@inheritdoc}
62+
* @inheritdoc
63+
*
6264
* @since 101.0.0
6365
*/
6466
public function getConnection()
@@ -67,6 +69,8 @@ public function getConnection()
6769
}
6870

6971
/**
72+
* Load data from table by valueId
73+
*
7074
* @param string $tableNameAlias
7175
* @param array $ids
7276
* @param int|null $storeId
@@ -111,6 +115,8 @@ public function loadDataFromTableByValueId(
111115
}
112116

113117
/**
118+
* Load product gallery by attributeId
119+
*
114120
* @param \Magento\Catalog\Model\Product $product
115121
* @param int $attributeId
116122
* @return array
@@ -132,6 +138,8 @@ public function loadProductGalleryByAttributeId($product, $attributeId)
132138
}
133139

134140
/**
141+
* Create base load select
142+
*
135143
* @param int $entityId
136144
* @param int $storeId
137145
* @param int $attributeId
@@ -151,6 +159,8 @@ protected function createBaseLoadSelect($entityId, $storeId, $attributeId)
151159
}
152160

153161
/**
162+
* Create batch base select
163+
*
154164
* @param int $storeId
155165
* @param int $attributeId
156166
* @return \Magento\Framework\DB\Select
@@ -190,7 +200,7 @@ public function createBatchBaseSelect($storeId, $attributeId)
190200
'value.' . $linkField . ' = entity.' . $linkField,
191201
]
192202
),
193-
['label', 'position', 'disabled']
203+
[]
194204
)->joinLeft(
195205
['default_value' => $this->getTable(self::GALLERY_VALUE_TABLE)],
196206
implode(
@@ -201,8 +211,15 @@ public function createBatchBaseSelect($storeId, $attributeId)
201211
'default_value.' . $linkField . ' = entity.' . $linkField,
202212
]
203213
),
204-
['label_default' => 'label', 'position_default' => 'position', 'disabled_default' => 'disabled']
205-
)->where(
214+
[]
215+
)->columns([
216+
'label' => $this->getConnection()->getIfNullSql('`value`.`label`', '`default_value`.`label`'),
217+
'position' => $this->getConnection()->getIfNullSql('`value`.`position`', '`default_value`.`position`'),
218+
'disabled' => $this->getConnection()->getIfNullSql('`value`.`disabled`', '`default_value`.`disabled`'),
219+
'label_default' => 'default_value.label',
220+
'position_default' => 'default_value.position',
221+
'disabled_default' => 'default_value.disabled'
222+
])->where(
206223
$mainTableAlias . '.attribute_id = ?',
207224
$attributeId
208225
)->where(
@@ -240,6 +257,8 @@ protected function removeDuplicates(&$result)
240257
}
241258

242259
/**
260+
* Get main table alias
261+
*
243262
* @return string
244263
* @since 101.0.0
245264
*/
@@ -249,6 +268,8 @@ public function getMainTableAlias()
249268
}
250269

251270
/**
271+
* Bind value to entity
272+
*
252273
* @param int $valueId
253274
* @param int $entityId
254275
* @return int
@@ -266,6 +287,8 @@ public function bindValueToEntity($valueId, $entityId)
266287
}
267288

268289
/**
290+
* Save data row
291+
*
269292
* @param string $table
270293
* @param array $data
271294
* @param array $fields

app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/GalleryTest.php

+38-10
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,9 @@ public function testBindValueToEntityRecordExists()
281281
$this->resource->bindValueToEntity($valueId, $entityId);
282282
}
283283

284+
/**
285+
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
286+
*/
284287
public function testLoadGallery()
285288
{
286289
$productId = 5;
@@ -329,7 +332,8 @@ public function testLoadGallery()
329332
'main.value_id = entity.value_id',
330333
['entity_id']
331334
)->willReturnSelf();
332-
$this->product->expects($this->at(0))->method('getData')->with('entity_id')->willReturn($productId);
335+
$this->product->expects($this->at(0))->method('getData')
336+
->with('entity_id')->willReturn($productId);
333337
$this->product->expects($this->at(1))->method('getStoreId')->will($this->returnValue($storeId));
334338
$this->connection->expects($this->exactly(2))->method('quoteInto')->withConsecutive(
335339
['value.store_id = ?'],
@@ -338,26 +342,50 @@ public function testLoadGallery()
338342
'value.store_id = ' . $storeId,
339343
'default_value.store_id = ' . 0
340344
);
345+
$this->connection->expects($this->any())->method('getIfNullSql')->will(
346+
$this->returnValueMap([
347+
[
348+
'`value`.`label`',
349+
'`default_value`.`label`',
350+
'IFNULL(`value`.`label`, `default_value`.`label`)'
351+
],
352+
[
353+
'`value`.`position`',
354+
'`default_value`.`position`',
355+
'IFNULL(`value`.`position`, `default_value`.`position`)'
356+
],
357+
[
358+
'`value`.`disabled`',
359+
'`default_value`.`disabled`',
360+
'IFNULL(`value`.`disabled`, `default_value`.`disabled`)'
361+
]
362+
])
363+
);
341364
$this->select->expects($this->at(2))->method('joinLeft')->with(
342365
['value' => $getTableReturnValue],
343366
$quoteInfoReturnValue,
344-
[
345-
'label',
346-
'position',
347-
'disabled'
348-
]
367+
[]
349368
)->willReturnSelf();
350369
$this->select->expects($this->at(3))->method('joinLeft')->with(
351370
['default_value' => $getTableReturnValue],
352371
$quoteDefaultInfoReturnValue,
353-
['label_default' => 'label', 'position_default' => 'position', 'disabled_default' => 'disabled']
372+
[]
354373
)->willReturnSelf();
355-
$this->select->expects($this->at(4))->method('where')->with(
374+
$this->select->expects($this->at(4))->method('columns')->with([
375+
'label' => 'IFNULL(`value`.`label`, `default_value`.`label`)',
376+
'position' => 'IFNULL(`value`.`position`, `default_value`.`position`)',
377+
'disabled' => 'IFNULL(`value`.`disabled`, `default_value`.`disabled`)',
378+
'label_default' => 'default_value.label',
379+
'position_default' => 'default_value.position',
380+
'disabled_default' => 'default_value.disabled'
381+
])->willReturnSelf();
382+
$this->select->expects($this->at(5))->method('where')->with(
356383
'main.attribute_id = ?',
357384
$attributeId
358385
)->willReturnSelf();
359-
$this->select->expects($this->at(5))->method('where')->with('main.disabled = 0')->willReturnSelf();
360-
$this->select->expects($this->at(7))->method('where')
386+
$this->select->expects($this->at(6))->method('where')
387+
->with('main.disabled = 0')->willReturnSelf();
388+
$this->select->expects($this->at(8))->method('where')
361389
->with('entity.entity_id = ?', $productId)
362390
->willReturnSelf();
363391
$this->select->expects($this->once())->method('order')

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

+5
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,11 @@
835835
<index referenceId="CATALOG_PRODUCT_ENTITY_MEDIA_GALLERY_VALUE_VALUE_ID" indexType="btree">
836836
<column name="value_id"/>
837837
</index>
838+
<index referenceId="CAT_PRD_ENTT_MDA_GLR_VAL_ENTT_ID_VAL_ID_STORE_ID" indexType="btree">
839+
<column name="entity_id"/>
840+
<column name="value_id"/>
841+
<column name="store_id"/>
842+
</index>
838843
</table>
839844
<table name="catalog_product_option" resource="default" engine="innodb" comment="Catalog Product Option Table">
840845
<column xsi:type="int" name="option_id" padding="10" unsigned="true" nullable="false" identity="true"

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,8 @@
484484
"index": {
485485
"CATALOG_PRODUCT_ENTITY_MEDIA_GALLERY_VALUE_STORE_ID": true,
486486
"CATALOG_PRODUCT_ENTITY_MEDIA_GALLERY_VALUE_ENTITY_ID": true,
487-
"CATALOG_PRODUCT_ENTITY_MEDIA_GALLERY_VALUE_VALUE_ID": true
487+
"CATALOG_PRODUCT_ENTITY_MEDIA_GALLERY_VALUE_VALUE_ID": true,
488+
"CAT_PRD_ENTT_MDA_GLR_VAL_ENTT_ID_VAL_ID_STORE_ID": true
488489
},
489490
"constraint": {
490491
"PRIMARY": true,
@@ -1121,4 +1122,4 @@
11211122
"CATALOG_PRODUCT_FRONTEND_ACTION_CUSTOMER_ID_PRODUCT_ID_TYPE_ID": true
11221123
}
11231124
}
1124-
}
1125+
}

app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php

+36-8
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,10 @@ public function getConfigurableAttributes($product)
453453
['group' => 'CONFIGURABLE', 'method' => __METHOD__]
454454
);
455455
if (!$product->hasData($this->_configurableAttributes)) {
456+
// for new product do not load configurable attributes
457+
if (!$product->getId()) {
458+
return [];
459+
}
456460
$configurableAttributes = $this->getConfigurableAttributeCollection($product);
457461
$this->extensionAttributesJoinProcessor->process($configurableAttributes);
458462
$configurableAttributes->orderByPosition()->load();
@@ -1398,23 +1402,47 @@ private function getConfiguredUsedProductCollection(
13981402
$skipStockFilter = true
13991403
) {
14001404
$collection = $this->getUsedProductCollection($product);
1405+
14011406
if ($skipStockFilter) {
14021407
$collection->setFlag('has_stock_status_filter', true);
14031408
}
1409+
14041410
$collection
1405-
->addAttributeToSelect($this->getCatalogConfig()->getProductAttributes())
1411+
->addAttributeToSelect($this->getAttributesForCollection($product))
14061412
->addFilterByRequiredOptions()
14071413
->setStoreId($product->getStoreId());
14081414

1409-
$requiredAttributes = ['name', 'price', 'weight', 'image', 'thumbnail', 'status', 'media_gallery'];
1410-
foreach ($requiredAttributes as $attributeCode) {
1411-
$collection->addAttributeToSelect($attributeCode);
1412-
}
1413-
foreach ($this->getUsedProductAttributes($product) as $usedProductAttribute) {
1414-
$collection->addAttributeToSelect($usedProductAttribute->getAttributeCode());
1415-
}
14161415
$collection->addMediaGalleryData();
14171416
$collection->addTierPriceData();
1417+
14181418
return $collection;
14191419
}
1420+
1421+
/**
1422+
* @return array
1423+
*/
1424+
private function getAttributesForCollection(\Magento\Catalog\Model\Product $product)
1425+
{
1426+
$productAttributes = $this->getCatalogConfig()->getProductAttributes();
1427+
1428+
$requiredAttributes = [
1429+
'name',
1430+
'price',
1431+
'weight',
1432+
'image',
1433+
'thumbnail',
1434+
'status',
1435+
'visibility',
1436+
'media_gallery'
1437+
];
1438+
1439+
$usedAttributes = array_map(
1440+
function($attr) {
1441+
return $attr->getAttributeCode();
1442+
},
1443+
$this->getUsedProductAttributes($product)
1444+
);
1445+
1446+
return array_unique(array_merge($productAttributes, $requiredAttributes, $usedAttributes));
1447+
}
14201448
}

0 commit comments

Comments
 (0)