Skip to content

Commit 47cc6f6

Browse files
author
Valeriy Nayda
committed
MAGETWO-65099: [Performance] Optimize validation of swatches attributes
1 parent 13ec629 commit 47cc6f6

File tree

13 files changed

+696
-62
lines changed

13 files changed

+696
-62
lines changed

app/code/Magento/Swatches/Block/Product/Renderer/Configurable.php

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
use Magento\Swatches\Helper\Data as SwatchData;
1919
use Magento\Swatches\Helper\Media;
2020
use Magento\Swatches\Model\Swatch;
21+
use Magento\Framework\App\ObjectManager;
22+
use Magento\Swatches\Model\SwatchAttributesProvider;
2123

2224
/**
2325
* Swatch renderer block
@@ -60,10 +62,17 @@ class Configurable extends \Magento\ConfigurableProduct\Block\Product\View\Type\
6062
/**
6163
* Indicate if product has one or more Swatch attributes
6264
*
65+
* @deprecated unused
66+
*
6367
* @var boolean
6468
*/
6569
protected $isProductHasSwatchAttribute;
6670

71+
/**
72+
* @var SwatchAttributesProvider
73+
*/
74+
private $swatchAttributesProvider;
75+
6776
/**
6877
* @param Context $context
6978
* @param ArrayUtils $arrayUtils
@@ -76,6 +85,7 @@ class Configurable extends \Magento\ConfigurableProduct\Block\Product\View\Type\
7685
* @param SwatchData $swatchHelper
7786
* @param Media $swatchMediaHelper
7887
* @param array $data other data
88+
* @param SwatchAttributesProvider $swatchAttributesProvider
7989
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
8090
*/
8191
public function __construct(
@@ -89,11 +99,13 @@ public function __construct(
8999
ConfigurableAttributeData $configurableAttributeData,
90100
SwatchData $swatchHelper,
91101
Media $swatchMediaHelper,
92-
array $data = []
102+
array $data = [],
103+
SwatchAttributesProvider $swatchAttributesProvider = null
93104
) {
94105
$this->swatchHelper = $swatchHelper;
95106
$this->swatchMediaHelper = $swatchMediaHelper;
96-
107+
$this->swatchAttributesProvider = $swatchAttributesProvider
108+
?: ObjectManager::getInstance()->get(SwatchAttributesProvider::class);
97109
parent::__construct(
98110
$context,
99111
$arrayUtils,
@@ -201,6 +213,8 @@ protected function getSwatchAttributesData()
201213
}
202214

203215
/**
216+
* @deprecated Method isProductHasSwatchAttribute() is used instead of this.
217+
*
204218
* @codeCoverageIgnore
205219
* @return void
206220
*/
@@ -209,6 +223,15 @@ protected function initIsProductHasSwatchAttribute()
209223
$this->isProductHasSwatchAttribute = $this->swatchHelper->isProductHasSwatch($this->getProduct());
210224
}
211225

226+
/**
227+
* @return bool
228+
*/
229+
protected function isProductHasSwatchAttribute()
230+
{
231+
$swatchAttributes = $this->swatchAttributesProvider->provide($this->getProduct());
232+
return count($swatchAttributes) > 0;
233+
}
234+
212235
/**
213236
* Add Swatch Data for attribute
214237
*
@@ -371,7 +394,6 @@ protected function getConfigurableOptionsIds(array $attributeData)
371394
*/
372395
public function toHtml()
373396
{
374-
$this->initIsProductHasSwatchAttribute();
375397
$this->setTemplate(
376398
$this->getRendererTemplate()
377399
);
@@ -396,7 +418,7 @@ protected function _toHtml()
396418
*/
397419
protected function getRendererTemplate()
398420
{
399-
return $this->isProductHasSwatchAttribute ?
421+
return $this->isProductHasSwatchAttribute() ?
400422
self::SWATCH_RENDERER_TEMPLATE : self::CONFIGURABLE_RENDERER_TEMPLATE;
401423
}
402424

app/code/Magento/Swatches/Block/Product/Renderer/Listing/Configurable.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77

88
/**
99
* Swatch renderer block in Category page
10-
*
11-
* @codeCoverageIgnore
12-
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1310
*/
1411
class Configurable extends \Magento\Swatches\Block\Product\Renderer\Configurable
1512
{
@@ -27,7 +24,7 @@ protected function getRendererTemplate()
2724
protected function getHtmlOutput()
2825
{
2926
$output = '';
30-
if ($this->isProductHasSwatchAttribute) {
27+
if ($this->isProductHasSwatchAttribute()) {
3128
$output = parent::getHtmlOutput();
3229
}
3330

app/code/Magento/Swatches/Helper/Data.php

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Magento\Store\Model\StoreManagerInterface;
1919
use Magento\Swatches\Model\ResourceModel\Swatch\CollectionFactory as SwatchCollectionFactory;
2020
use Magento\Swatches\Model\Swatch;
21+
use Magento\Swatches\Model\SwatchAttributesProvider;
2122

2223
/**
2324
* Class Helper Data
@@ -70,6 +71,11 @@ class Data
7071
*/
7172
private $metadataPool;
7273

74+
/**
75+
* @var SwatchAttributesProvider
76+
*/
77+
private $swatchAttributesProvider;
78+
7379
/**
7480
* Data key which should populated to Attribute entity from "additional_data" field
7581
*
@@ -95,21 +101,25 @@ class Data
95101
* @param SwatchCollectionFactory $swatchCollectionFactory
96102
* @param Image $imageHelper
97103
* @param Json|null $serializer
104+
* @param SwatchAttributesProvider $swatchAttributesProvider
98105
*/
99106
public function __construct(
100107
CollectionFactory $productCollectionFactory,
101108
ProductRepositoryInterface $productRepository,
102109
StoreManagerInterface $storeManager,
103110
SwatchCollectionFactory $swatchCollectionFactory,
104111
Image $imageHelper,
105-
Json $serializer = null
112+
Json $serializer = null,
113+
SwatchAttributesProvider $swatchAttributesProvider = null
106114
) {
107115
$this->productCollectionFactory = $productCollectionFactory;
108116
$this->productRepository = $productRepository;
109117
$this->storeManager = $storeManager;
110118
$this->swatchCollectionFactory = $swatchCollectionFactory;
111119
$this->imageHelper = $imageHelper;
112120
$this->serializer = $serializer ?: ObjectManager::getInstance()->create(Json::class);
121+
$this->swatchAttributesProvider = $swatchAttributesProvider
122+
?: ObjectManager::getInstance()->get(SwatchAttributesProvider::class);
113123
}
114124

115125
/**
@@ -358,14 +368,8 @@ private function getAllSizeImages(ModelProduct $product, $imageFile)
358368
*/
359369
private function getSwatchAttributes(Product $product)
360370
{
361-
$attributes = $this->getAttributesFromConfigurable($product);
362-
$result = [];
363-
foreach ($attributes as $attribute) {
364-
if ($this->isSwatchAttribute($attribute)) {
365-
$result[] = $attribute;
366-
}
367-
}
368-
return $result;
371+
$swatchAttributes = $this->swatchAttributesProvider->provide($product);
372+
return $swatchAttributes;
369373
}
370374

371375
/**
@@ -470,7 +474,8 @@ private function addFallbackOptions(array $fallbackValues, array $swatches)
470474
*/
471475
public function isProductHasSwatch(Product $product)
472476
{
473-
return sizeof($this->getSwatchAttributes($product));
477+
$swatchAttributes = $this->getSwatchAttributes($product);
478+
return count($swatchAttributes) > 0;
474479
}
475480

476481
/**
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
<?php
2+
/**
3+
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Swatches\Model;
7+
8+
use Magento\Framework\App\CacheInterface;
9+
use Magento\Framework\App\ResourceConnection;
10+
use Magento\Framework\DB\Select;
11+
12+
/**
13+
* Class SwatchAttributeCodes for getting codes of swatch attributes.
14+
*/
15+
class SwatchAttributeCodes
16+
{
17+
/**
18+
* @var string
19+
*/
20+
private $cacheKey;
21+
22+
/**
23+
* @var CacheInterface
24+
*/
25+
private $cache;
26+
27+
/**
28+
* @var ResourceConnection
29+
*/
30+
private $resourceConnection;
31+
32+
/**
33+
* Key is attribute_id, value is attribute_code
34+
*
35+
* @var array
36+
*/
37+
private $swatchAttributeCodes;
38+
39+
/**
40+
* @var array
41+
*/
42+
private $cacheTags;
43+
44+
/**
45+
* SwatchAttributeList constructor.
46+
*
47+
* @param CacheInterface $cache
48+
* @param ResourceConnection $resourceConnection
49+
* @param string $cacheKey
50+
* @param array $cacheTags
51+
*/
52+
public function __construct(
53+
CacheInterface $cache,
54+
ResourceConnection $resourceConnection,
55+
$cacheKey,
56+
array $cacheTags
57+
) {
58+
$this->cache = $cache;
59+
$this->resourceConnection = $resourceConnection;
60+
$this->cacheKey = $cacheKey;
61+
$this->cacheTags = $cacheTags;
62+
}
63+
64+
/**
65+
* Returns list of known swatch attribute codes. Check cache and database.
66+
* Key is attribute_id, value is attribute_code
67+
*
68+
* @return array
69+
*/
70+
public function getCodes()
71+
{
72+
if ($this->swatchAttributeCodes === null) {
73+
$swatchAttributeCodesCache = $this->cache->load($this->cacheKey);
74+
if (false === $swatchAttributeCodesCache) {
75+
$swatchAttributeCodes = $this->loadSwatchAttributeCodes();
76+
$this->cache->save(json_encode($swatchAttributeCodes), $this->cacheKey, $this->cacheTags);
77+
} else {
78+
$swatchAttributeCodes = json_decode($swatchAttributeCodesCache, true);
79+
}
80+
$this->swatchAttributeCodes = $swatchAttributeCodes;
81+
}
82+
83+
return $this->swatchAttributeCodes;
84+
}
85+
86+
/**
87+
* Returns list of known swatch attributes.
88+
*
89+
* @return array
90+
*/
91+
private function loadSwatchAttributeCodes()
92+
{
93+
$select = $this->resourceConnection->getConnection()->select()
94+
->from(
95+
['a' => $this->resourceConnection->getTableName('eav_attribute')],
96+
[
97+
'attribute_id' => 'a.attribute_id',
98+
'attribute_code' => 'a.attribute_code',
99+
]
100+
)->where(
101+
'a.attribute_id IN (?)',
102+
new \Zend_Db_Expr(sprintf('(%s)', $this->getAttributeIdsSelect()))
103+
);
104+
$result = $this->resourceConnection->getConnection()->fetchPairs($select);
105+
return $result;
106+
}
107+
108+
/**
109+
* Returns Select for attributes Ids.
110+
*
111+
* @return Select
112+
*/
113+
private function getAttributeIdsSelect()
114+
{
115+
return $this->resourceConnection->getConnection()->select()
116+
->from(
117+
['o' => $this->resourceConnection->getTableName('eav_attribute_option')],
118+
['attribute_id' => 'o.attribute_id']
119+
)->join(
120+
['s' => $this->resourceConnection->getTableName('eav_attribute_option_swatch')],
121+
'o.option_id = s.option_id',
122+
[]
123+
);
124+
}
125+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
/**
3+
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Swatches\Model;
7+
8+
use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
9+
use Magento\Catalog\Model\Product;
10+
use Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute;
11+
12+
/**
13+
* Provide list of swatch attributes for product.
14+
*/
15+
class SwatchAttributesProvider
16+
{
17+
/**
18+
* @var Configurable
19+
*/
20+
private $typeConfigurable;
21+
22+
/**
23+
* @var SwatchAttributeCodes
24+
*/
25+
private $swatchAttributeCodes;
26+
27+
/**
28+
* Key is productId, value is list of attributes
29+
* @var Attribute[]
30+
*/
31+
private $attributesPerProduct;
32+
33+
/**
34+
* @param Configurable $typeConfigurable
35+
* @param SwatchAttributeCodes $swatchAttributeCodes
36+
*/
37+
public function __construct(
38+
Configurable $typeConfigurable,
39+
SwatchAttributeCodes $swatchAttributeCodes
40+
) {
41+
$this->typeConfigurable = $typeConfigurable;
42+
$this->swatchAttributeCodes = $swatchAttributeCodes;
43+
}
44+
45+
/**
46+
* Provide list of swatch attributes for product. If product is not configurable return empty array
47+
* Key is productId, value is list of attributes
48+
*
49+
* @param Product $product
50+
* @return Attribute[]
51+
*/
52+
public function provide(Product $product)
53+
{
54+
if ($product->getTypeId() !== Configurable::TYPE_CODE) {
55+
return [];
56+
}
57+
if (!isset($this->attributesPerProduct[$product->getId()])) {
58+
$configurableAttributes = $this->typeConfigurable->getConfigurableAttributes($product);
59+
$swatchAttributeCodeMap = $this->swatchAttributeCodes->getCodes();
60+
61+
$swatchAttributes = [];
62+
foreach ($configurableAttributes as $configurableAttribute) {
63+
if (array_key_exists($configurableAttribute->getAttributeId(), $swatchAttributeCodeMap)) {
64+
$swatchAttributes[$configurableAttribute->getAttributeId()]
65+
= $configurableAttribute->getProductAttribute();
66+
}
67+
}
68+
$this->attributesPerProduct[$product->getId()] = $swatchAttributes;
69+
}
70+
return $this->attributesPerProduct[$product->getId()];
71+
}
72+
}

0 commit comments

Comments
 (0)