Skip to content

Commit 688dbf3

Browse files
MAGETWO-67010: [Performance] Swatches real server side optimization
1 parent b67cf43 commit 688dbf3

File tree

4 files changed

+142
-62
lines changed

4 files changed

+142
-62
lines changed

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
use Magento\ConfigurableProduct\Model\ConfigurableAttributeData;
1111
use Magento\Customer\Helper\Session\CurrentCustomer;
12+
use Magento\Framework\App\ObjectManager;
1213
use Magento\Framework\Pricing\PriceCurrencyInterface;
1314

1415
/**
@@ -59,6 +60,11 @@ class Configurable extends \Magento\Catalog\Block\Product\View\AbstractView
5960
*/
6061
protected $configurableAttributeData;
6162

63+
/**
64+
* @var \Magento\Swatches\Model\Product\Variations\Media
65+
*/
66+
private $variationsMedia;
67+
6268
/**
6369
* @param \Magento\Catalog\Block\Product\Context $context
6470
* @param \Magento\Framework\Stdlib\ArrayUtils $arrayUtils
@@ -69,6 +75,7 @@ class Configurable extends \Magento\Catalog\Block\Product\View\AbstractView
6975
* @param PriceCurrencyInterface $priceCurrency
7076
* @param ConfigurableAttributeData $configurableAttributeData
7177
* @param array $data
78+
* @param \Magento\Swatches\Model\Product\Variations\Media $variationsMedia
7279
*/
7380
public function __construct(
7481
\Magento\Catalog\Block\Product\Context $context,
@@ -79,14 +86,18 @@ public function __construct(
7986
CurrentCustomer $currentCustomer,
8087
PriceCurrencyInterface $priceCurrency,
8188
ConfigurableAttributeData $configurableAttributeData,
82-
array $data = []
89+
array $data = [],
90+
\Magento\Swatches\Model\Product\Variations\Media $variationsMedia = null
8391
) {
8492
$this->priceCurrency = $priceCurrency;
8593
$this->helper = $helper;
8694
$this->jsonEncoder = $jsonEncoder;
8795
$this->catalogProduct = $catalogProduct;
8896
$this->currentCustomer = $currentCustomer;
8997
$this->configurableAttributeData = $configurableAttributeData;
98+
$this->variationsMedia = $variationsMedia
99+
?: ObjectManager::getInstance()->get(\Magento\Swatches\Model\Product\Variations\Media::class);
100+
90101
parent::__construct(
91102
$context,
92103
$arrayUtils,
@@ -220,6 +231,15 @@ public function getJsonConfig()
220231
$config['defaultValues'] = $attributesData['defaultValues'];
221232
}
222233

234+
// Is there any better way to check that we are on layered navigation search result page?
235+
if (!empty($this->getRequest()->getQuery()->toArray())) {
236+
$config['preSelectedGallery'] = $this->variationsMedia->getProductVariationWithMedia(
237+
$currentProduct,
238+
[],
239+
$this->getRequest()->getQuery()->toArray()
240+
);
241+
}
242+
223243
$config = array_merge($config, $this->_getAdditionalConfig());
224244

225245
return $this->jsonEncoder->encode($config);

app/code/Magento/Swatches/Controller/Ajax/Media.php

Lines changed: 13 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -8,35 +8,34 @@
88

99
use Magento\Framework\App\Action\Context;
1010
use Magento\Framework\Controller\ResultFactory;
11-
use Magento\Catalog\Model\Product;
1211

1312
/**
1413
* Class Media
1514
*/
1615
class Media extends \Magento\Framework\App\Action\Action
1716
{
1817
/**
19-
* @var \Magento\Swatches\Helper\Data
18+
* @var \Magento\Catalog\Model\Product Factory
2019
*/
21-
protected $swatchHelper;
20+
protected $productModelFactory;
2221

2322
/**
24-
* @var \Magento\Catalog\Model\ProductFactory
23+
* @var \Magento\Swatches\Model\Product\Variations\Media
2524
*/
26-
protected $productModelFactory;
25+
private $variationsMedia;
2726

2827
/**
2928
* @param Context $context
30-
* @param \Magento\Swatches\Helper\Data $swatchHelper
3129
* @param \Magento\Catalog\Model\ProductFactory $productModelFactory
30+
* @param \Magento\Swatches\Model\Product\Variations\Media $variationsMedia
3231
*/
3332
public function __construct(
3433
Context $context,
35-
\Magento\Swatches\Helper\Data $swatchHelper,
36-
\Magento\Catalog\Model\ProductFactory $productModelFactory
34+
\Magento\Catalog\Model\ProductFactory $productModelFactory,
35+
\Magento\Swatches\Model\Product\Variations\Media $variationsMedia
3736
) {
38-
$this->swatchHelper = $swatchHelper;
3937
$this->productModelFactory = $productModelFactory;
38+
$this->variationsMedia = $variationsMedia;
4039

4140
parent::__construct($context);
4241
}
@@ -52,60 +51,16 @@ public function execute()
5251
{
5352
$productMedia = [];
5453
if ($productId = (int)$this->getRequest()->getParam('product_id')) {
55-
$currentConfigurable = $this->productModelFactory->create()->load($productId);
56-
$attributes = (array)$this->getRequest()->getParam('attributes');
57-
if (!empty($attributes)) {
58-
$product = $this->getProductVariationWithMedia($currentConfigurable, $attributes);
59-
}
60-
if ((empty($product) || (!$product->getImage() || $product->getImage() == 'no_selection'))
61-
&& isset($currentConfigurable)
62-
) {
63-
$product = $currentConfigurable;
64-
}
65-
$productMedia = $this->swatchHelper->getProductMediaGallery($product);
54+
$productMedia = $this->variationsMedia->getProductVariationWithMedia(
55+
$this->productModelFactory->create()->load($productId),
56+
(array)$this->getRequest()->getParam('attributes'),
57+
(array)$this->getRequest()->getParam('additional')
58+
);
6659
}
6760

6861
/** @var \Magento\Framework\Controller\Result\Json $resultJson */
6962
$resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON);
7063
$resultJson->setData($productMedia);
7164
return $resultJson;
7265
}
73-
74-
protected function getProductVariationWithMedia(Product $currentConfigurable, array $attributes)
75-
{
76-
$product = null;
77-
$layeredAttributes = [];
78-
$configurableAttributes = $this->swatchHelper->getAttributesFromConfigurable($currentConfigurable);
79-
if ($configurableAttributes) {
80-
$layeredAttributes = $this->getLayeredAttributesIfExists($configurableAttributes);
81-
}
82-
$resultAttributes = array_merge($layeredAttributes, $attributes);
83-
84-
$product = $this->swatchHelper->loadVariationByFallback($currentConfigurable, $resultAttributes);
85-
if (!$product || (!$product->getImage() || $product->getImage() == 'no_selection')) {
86-
$product = $this->swatchHelper->loadFirstVariationWithSwatchImage($currentConfigurable, $resultAttributes);
87-
}
88-
if (!$product) {
89-
$product = $this->swatchHelper->loadFirstVariationWithImage($currentConfigurable, $resultAttributes);
90-
}
91-
return $product;
92-
}
93-
94-
/**
95-
* @param array $configurableAttributes
96-
* @return array
97-
*/
98-
protected function getLayeredAttributesIfExists(array $configurableAttributes)
99-
{
100-
$layeredAttributes = [];
101-
102-
foreach ($configurableAttributes as $attribute) {
103-
if ($urlAdditional = (array)$this->getRequest()->getParam('additional')) {
104-
if (array_key_exists($attribute['attribute_code'], $urlAdditional)) {
105-
$layeredAttributes[$attribute['attribute_code']] = $urlAdditional[$attribute['attribute_code']];
106-
}
107-
}
108-
}
109-
return $layeredAttributes;
110-
}
11166
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Swatches\Model\Product\Variations;
7+
8+
use Magento\Catalog\Model\Product;
9+
10+
class Media {
11+
12+
/**
13+
* @var \Magento\Swatches\Helper\Data
14+
*/
15+
private $swatchHelper;
16+
17+
/**
18+
* @param \Magento\Swatches\Helper\Data $swatchHelper
19+
*/
20+
public function __construct(
21+
\Magento\Swatches\Helper\Data $swatchHelper
22+
) {
23+
$this->swatchHelper = $swatchHelper;
24+
}
25+
26+
public function getProductVariationWithMedia(
27+
Product $configurable,
28+
array $attributes = [],
29+
array $additionalAttributes = []
30+
) {
31+
if (!empty($attributes) || !empty($additionalAttributes)) {
32+
$product = $this->getProduct($configurable, $attributes, $additionalAttributes);
33+
}
34+
35+
if (empty($product) || (!$product->getImage() || $product->getImage() === 'no_selection')) {
36+
$product = $configurable;
37+
}
38+
39+
return $this->swatchHelper->getProductMediaGallery($product);
40+
}
41+
42+
private function getProduct(Product $configurable, array $attributes = [], array $additionalAttributes = [])
43+
{
44+
$product = null;
45+
$layeredAttributes = [];
46+
$configurableAttributes = $this->swatchHelper->getAttributesFromConfigurable($configurable);
47+
if ($configurableAttributes) {
48+
$layeredAttributes = $this->getLayeredAttributesIfExists($configurableAttributes, $additionalAttributes);
49+
}
50+
$resultAttributes = array_merge($layeredAttributes, $attributes);
51+
52+
$product = $this->swatchHelper->loadVariationByFallback($configurable, $resultAttributes);
53+
if (!$product || (!$product->getImage() || $product->getImage() == 'no_selection')) {
54+
$product = $this->swatchHelper->loadFirstVariationWithSwatchImage($configurable, $resultAttributes);
55+
}
56+
if (!$product) {
57+
$product = $this->swatchHelper->loadFirstVariationWithImage($configurable, $resultAttributes);
58+
}
59+
return $product;
60+
}
61+
62+
private function getLayeredAttributesIfExists(array $configurableAttributes, array $additionalAttributes)
63+
{
64+
$layeredAttributes = [];
65+
66+
$commonAttributeCodes = array_intersect(
67+
array_column($configurableAttributes, 'attribute_code'),
68+
array_keys($additionalAttributes)
69+
);
70+
71+
foreach ($commonAttributeCodes as $attributeCode) {
72+
$layeredAttributes[$attributeCode] = $additionalAttributes[$attributeCode];
73+
}
74+
75+
return $layeredAttributes;
76+
}
77+
}

app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -282,10 +282,15 @@ define([
282282
* @private
283283
*/
284284
_init: function () {
285+
// creates debounced variant of _LoadProductMedia()
286+
// to use it in events handlers instead of _LoadProductMedia()
287+
this._debouncedLoadProductMedia = _.debounce(this._LoadProductMedia.bind(this), 1000);
288+
285289
if (this.options.jsonConfig !== '' && this.options.jsonSwatchConfig !== '') {
286290
// store unsorted attributes
287291
this.options.jsonConfig.mappedAttributes = _.clone(this.options.jsonConfig.attributes);
288292
this._sortAttributes();
293+
this._setPreSelectedGallery();
289294
this._RenderControls();
290295
$(this.element).trigger('swatch.initialized');
291296
} else {
@@ -678,7 +683,7 @@ define([
678683
$widget._UpdatePrice();
679684
}
680685

681-
$widget._LoadProductMedia();
686+
this._debouncedLoadProductMedia();
682687
$input.trigger('change');
683688
},
684689

@@ -736,7 +741,7 @@ define([
736741

737742
$widget._Rebuild();
738743
$widget._UpdatePrice();
739-
$widget._LoadProductMedia();
744+
this._debouncedLoadProductMedia();
740745
$input.trigger('change');
741746
},
742747

@@ -961,12 +966,13 @@ define([
961966
mediaCacheKey = JSON.stringify(mediaCallData);
962967

963968
if (mediaCacheKey in $widget.options.mediaCache) {
969+
$widget._XhrKiller();
964970
mediaSuccessCallback($widget.options.mediaCache[mediaCacheKey]);
965971
} else {
966972
mediaCallData.isAjax = true;
967973
$widget._XhrKiller();
968974
$widget._EnableProductMediaLoader($this);
969-
$widget.xhr = $.post(
975+
$widget.xhr = $.get(
970976
$widget.options.mediaCallback,
971977
mediaCallData,
972978
mediaSuccessCallback,
@@ -1200,6 +1206,28 @@ define([
12001206
var galleryObject = element.data('gallery');
12011207

12021208
this.options.mediaGalleryInitial = galleryObject.returnCurrentImages();
1209+
},
1210+
1211+
/**
1212+
* Sets mediaCache for cases when jsonConfig contains preSelectedGallery on layered navigation result pages
1213+
*
1214+
* @private
1215+
*/
1216+
_setPreSelectedGallery: function () {
1217+
if (this.options.jsonConfig.preSelectedGallery) {
1218+
var productData = this._determineProductData(),
1219+
mediaCallData,
1220+
mediaCacheKey;
1221+
1222+
mediaCallData = {
1223+
'product_id': productData.productId,
1224+
'attributes': $.parseQuery(),
1225+
'additional': $.parseQuery()
1226+
};
1227+
1228+
mediaCacheKey = JSON.stringify(mediaCallData);
1229+
this.options.mediaCache[mediaCacheKey] = this.options.jsonConfig.preSelectedGallery;
1230+
}
12031231
}
12041232
});
12051233

0 commit comments

Comments
 (0)