Skip to content

Commit

Permalink
Merge pull request #989 from magento-dragons/perf-pr-swatches
Browse files Browse the repository at this point in the history
[Dragons][Performance] Swatches
  • Loading branch information
Yaroslav Onischenko authored Apr 3, 2017
2 parents ae331f5 + 3e3f7fc commit 436d046
Show file tree
Hide file tree
Showing 29 changed files with 1,238 additions and 92 deletions.
37 changes: 32 additions & 5 deletions app/code/Magento/Swatches/Block/Product/Renderer/Configurable.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
use Magento\Swatches\Helper\Data as SwatchData;
use Magento\Swatches\Helper\Media;
use Magento\Swatches\Model\Swatch;
use Magento\Framework\App\ObjectManager;
use Magento\Swatches\Model\SwatchAttributesProvider;

/**
* Swatch renderer block
Expand Down Expand Up @@ -60,10 +62,17 @@ class Configurable extends \Magento\ConfigurableProduct\Block\Product\View\Type\
/**
* Indicate if product has one or more Swatch attributes
*
* @deprecated unused
*
* @var boolean
*/
protected $isProductHasSwatchAttribute;

/**
* @var SwatchAttributesProvider
*/
private $swatchAttributesProvider;

/**
* @param Context $context
* @param ArrayUtils $arrayUtils
Expand All @@ -76,6 +85,7 @@ class Configurable extends \Magento\ConfigurableProduct\Block\Product\View\Type\
* @param SwatchData $swatchHelper
* @param Media $swatchMediaHelper
* @param array $data other data
* @param SwatchAttributesProvider $swatchAttributesProvider
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
Expand All @@ -89,11 +99,13 @@ public function __construct(
ConfigurableAttributeData $configurableAttributeData,
SwatchData $swatchHelper,
Media $swatchMediaHelper,
array $data = []
array $data = [],
SwatchAttributesProvider $swatchAttributesProvider = null
) {
$this->swatchHelper = $swatchHelper;
$this->swatchMediaHelper = $swatchMediaHelper;

$this->swatchAttributesProvider = $swatchAttributesProvider
?: ObjectManager::getInstance()->get(SwatchAttributesProvider::class);
parent::__construct(
$context,
$arrayUtils,
Expand Down Expand Up @@ -201,6 +213,8 @@ protected function getSwatchAttributesData()
}

/**
* @deprecated Method isProductHasSwatchAttribute() is used instead of this.
*
* @codeCoverageIgnore
* @return void
*/
Expand All @@ -209,6 +223,17 @@ protected function initIsProductHasSwatchAttribute()
$this->isProductHasSwatchAttribute = $this->swatchHelper->isProductHasSwatch($this->getProduct());
}

/**
* Check that product has at least one swatch attribute
*
* @return bool
*/
protected function isProductHasSwatchAttribute()
{
$swatchAttributes = $this->swatchAttributesProvider->provide($this->getProduct());
return count($swatchAttributes) > 0;
}

/**
* Add Swatch Data for attribute
*
Expand Down Expand Up @@ -371,7 +396,6 @@ protected function getConfigurableOptionsIds(array $attributeData)
*/
public function toHtml()
{
$this->initIsProductHasSwatchAttribute();
$this->setTemplate(
$this->getRendererTemplate()
);
Expand All @@ -391,12 +415,15 @@ protected function _toHtml()
}

/**
* @codeCoverageIgnore
* Return renderer template
*
* Template for product with swatches is different from product without swatches
*
* @return string
*/
protected function getRendererTemplate()
{
return $this->isProductHasSwatchAttribute ?
return $this->isProductHasSwatchAttribute() ?
self::SWATCH_RENDERER_TEMPLATE : self::CONFIGURABLE_RENDERER_TEMPLATE;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@

/**
* Swatch renderer block in Category page
*
* @codeCoverageIgnore
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Configurable extends \Magento\Swatches\Block\Product\Renderer\Configurable
{
Expand All @@ -27,7 +24,7 @@ protected function getRendererTemplate()
protected function getHtmlOutput()
{
$output = '';
if ($this->isProductHasSwatchAttribute) {
if ($this->isProductHasSwatchAttribute()) {
$output = parent::getHtmlOutput();
}

Expand Down
25 changes: 15 additions & 10 deletions app/code/Magento/Swatches/Helper/Data.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Magento\Store\Model\StoreManagerInterface;
use Magento\Swatches\Model\ResourceModel\Swatch\CollectionFactory as SwatchCollectionFactory;
use Magento\Swatches\Model\Swatch;
use Magento\Swatches\Model\SwatchAttributesProvider;

/**
* Class Helper Data
Expand Down Expand Up @@ -70,6 +71,11 @@ class Data
*/
private $metadataPool;

/**
* @var SwatchAttributesProvider
*/
private $swatchAttributesProvider;

/**
* Data key which should populated to Attribute entity from "additional_data" field
*
Expand All @@ -95,21 +101,25 @@ class Data
* @param SwatchCollectionFactory $swatchCollectionFactory
* @param Image $imageHelper
* @param Json|null $serializer
* @param SwatchAttributesProvider $swatchAttributesProvider
*/
public function __construct(
CollectionFactory $productCollectionFactory,
ProductRepositoryInterface $productRepository,
StoreManagerInterface $storeManager,
SwatchCollectionFactory $swatchCollectionFactory,
Image $imageHelper,
Json $serializer = null
Json $serializer = null,
SwatchAttributesProvider $swatchAttributesProvider = null
) {
$this->productCollectionFactory = $productCollectionFactory;
$this->productRepository = $productRepository;
$this->storeManager = $storeManager;
$this->swatchCollectionFactory = $swatchCollectionFactory;
$this->imageHelper = $imageHelper;
$this->serializer = $serializer ?: ObjectManager::getInstance()->create(Json::class);
$this->swatchAttributesProvider = $swatchAttributesProvider
?: ObjectManager::getInstance()->get(SwatchAttributesProvider::class);
}

/**
Expand Down Expand Up @@ -358,14 +368,8 @@ private function getAllSizeImages(ModelProduct $product, $imageFile)
*/
private function getSwatchAttributes(Product $product)
{
$attributes = $this->getAttributesFromConfigurable($product);
$result = [];
foreach ($attributes as $attribute) {
if ($this->isSwatchAttribute($attribute)) {
$result[] = $attribute;
}
}
return $result;
$swatchAttributes = $this->swatchAttributesProvider->provide($product);
return $swatchAttributes;
}

/**
Expand Down Expand Up @@ -470,7 +474,8 @@ private function addFallbackOptions(array $fallbackValues, array $swatches)
*/
public function isProductHasSwatch(Product $product)
{
return sizeof($this->getSwatchAttributes($product));
$swatchAttributes = $this->getSwatchAttributes($product);
return count($swatchAttributes) > 0;
}

/**
Expand Down
129 changes: 129 additions & 0 deletions app/code/Magento/Swatches/Model/SwatchAttributeCodes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Swatches\Model;

use Magento\Framework\App\CacheInterface;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\DB\Select;

/**
* Class SwatchAttributeCodes for getting codes of swatch attributes.
*/
class SwatchAttributeCodes
{
/**
* @var string
*/
private $cacheKey;

/**
* @var CacheInterface
*/
private $cache;

/**
* @var ResourceConnection
*/
private $resourceConnection;

/**
* Key is attribute_id, value is attribute_code
*
* @var array
*/
private $swatchAttributeCodes;

/**
* @var array
*/
private $cacheTags;

/**
* SwatchAttributeList constructor.
*
* @param CacheInterface $cache
* @param ResourceConnection $resourceConnection
* @param string $cacheKey
* @param array $cacheTags
*/
public function __construct(
CacheInterface $cache,
ResourceConnection $resourceConnection,
$cacheKey,
array $cacheTags
) {
$this->cache = $cache;
$this->resourceConnection = $resourceConnection;
$this->cacheKey = $cacheKey;
$this->cacheTags = $cacheTags;
}

/**
* Returns list of known swatch attribute codes. Check cache and database.
* Key is attribute_id, value is attribute_code
*
* @return array
*/
public function getCodes()
{
if ($this->swatchAttributeCodes === null) {
$swatchAttributeCodesCache = $this->cache->load($this->cacheKey);
if (false === $swatchAttributeCodesCache) {
$swatchAttributeCodes = $this->getSwatchAttributeCodes();
$this->cache->save(json_encode($swatchAttributeCodes), $this->cacheKey, $this->cacheTags);
} else {
$swatchAttributeCodes = json_decode($swatchAttributeCodesCache, true);
}
$this->swatchAttributeCodes = $swatchAttributeCodes;
}

return $this->swatchAttributeCodes;
}

/**
* Returns list of known swatch attributes.
*
* Returns a map of id and code for all EAV attributes with swatches
*
* @return array
*/
private function getSwatchAttributeCodes()
{
$select = $this->resourceConnection->getConnection()->select()
->from(
['a' => $this->resourceConnection->getTableName('eav_attribute')],
[
'attribute_id' => 'a.attribute_id',
'attribute_code' => 'a.attribute_code',
]
)->where(
'a.attribute_id IN (?)',
new \Zend_Db_Expr($this->getAttributeIdsSelect())
);
$result = $this->resourceConnection->getConnection()->fetchPairs($select);
return $result;
}

/**
* Returns Select for attributes Ids.
*
* Builds a "Select" object which loads all EAV attributes that has "swatch" options
*
* @return Select
*/
private function getAttributeIdsSelect()
{
return $this->resourceConnection->getConnection()->select()
->from(
['o' => $this->resourceConnection->getTableName('eav_attribute_option')],
['attribute_id' => 'o.attribute_id']
)->join(
['s' => $this->resourceConnection->getTableName('eav_attribute_option_swatch')],
'o.option_id = s.option_id',
[]
);
}
}
72 changes: 72 additions & 0 deletions app/code/Magento/Swatches/Model/SwatchAttributesProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Swatches\Model;

use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
use Magento\Catalog\Model\Product;
use Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute;

/**
* Provide list of swatch attributes for product.
*/
class SwatchAttributesProvider
{
/**
* @var Configurable
*/
private $typeConfigurable;

/**
* @var SwatchAttributeCodes
*/
private $swatchAttributeCodes;

/**
* Key is productId, value is list of attributes
* @var Attribute[]
*/
private $attributesPerProduct;

/**
* @param Configurable $typeConfigurable
* @param SwatchAttributeCodes $swatchAttributeCodes
*/
public function __construct(
Configurable $typeConfigurable,
SwatchAttributeCodes $swatchAttributeCodes
) {
$this->typeConfigurable = $typeConfigurable;
$this->swatchAttributeCodes = $swatchAttributeCodes;
}

/**
* Provide list of swatch attributes for product. If product is not configurable return empty array
* Key is productId, value is list of attributes
*
* @param Product $product
* @return Attribute[]
*/
public function provide(Product $product)
{
if ($product->getTypeId() !== Configurable::TYPE_CODE) {
return [];
}
if (!isset($this->attributesPerProduct[$product->getId()])) {
$configurableAttributes = $this->typeConfigurable->getConfigurableAttributes($product);
$swatchAttributeCodeMap = $this->swatchAttributeCodes->getCodes();

$swatchAttributes = [];
foreach ($configurableAttributes as $configurableAttribute) {
if (array_key_exists($configurableAttribute->getAttributeId(), $swatchAttributeCodeMap)) {
$swatchAttributes[$configurableAttribute->getAttributeId()]
= $configurableAttribute->getProductAttribute();
}
}
$this->attributesPerProduct[$product->getId()] = $swatchAttributes;
}
return $this->attributesPerProduct[$product->getId()];
}
}
Loading

0 comments on commit 436d046

Please sign in to comment.