-
Notifications
You must be signed in to change notification settings - Fork 9.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4766 from magento-chaika/Chaika-2019-09-12-3
Chaika-2019-09-12-3
- Loading branch information
Showing
5 changed files
with
224 additions
and
88 deletions.
There are no files selected for viewing
190 changes: 190 additions & 0 deletions
190
app/code/Magento/ConfigurableProduct/Model/Plugin/Frontend/UsedProductsCache.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Magento\ConfigurableProduct\Model\Plugin\Frontend; | ||
|
||
use Magento\Catalog\Api\Data\ProductInterface; | ||
use Magento\Catalog\Api\Data\ProductInterfaceFactory; | ||
use Magento\Catalog\Model\Category; | ||
use Magento\Catalog\Model\Product; | ||
use Magento\ConfigurableProduct\Model\Product\Type\Configurable; | ||
use Magento\Customer\Model\Session; | ||
use Magento\Framework\Cache\FrontendInterface; | ||
use Magento\Framework\EntityManager\MetadataPool; | ||
use Magento\Framework\Serialize\SerializerInterface; | ||
|
||
/** | ||
* Cache of used products for configurable product | ||
* | ||
* @SuppressWarnings(PHPMD.CookieAndSessionMisuse) | ||
*/ | ||
class UsedProductsCache | ||
{ | ||
/** | ||
* @var MetadataPool | ||
*/ | ||
private $metadataPool; | ||
|
||
/** | ||
* @var FrontendInterface | ||
*/ | ||
private $cache; | ||
|
||
/** | ||
* @var SerializerInterface | ||
*/ | ||
private $serializer; | ||
|
||
/** | ||
* @var ProductInterfaceFactory | ||
*/ | ||
private $productFactory; | ||
|
||
/** | ||
* @var Session | ||
*/ | ||
private $customerSession; | ||
|
||
/** | ||
* @param MetadataPool $metadataPool | ||
* @param FrontendInterface $cache | ||
* @param SerializerInterface $serializer | ||
* @param ProductInterfaceFactory $productFactory | ||
* @param Session $customerSession | ||
*/ | ||
public function __construct( | ||
MetadataPool $metadataPool, | ||
FrontendInterface $cache, | ||
SerializerInterface $serializer, | ||
ProductInterfaceFactory $productFactory, | ||
Session $customerSession | ||
) { | ||
$this->metadataPool = $metadataPool; | ||
$this->cache = $cache; | ||
$this->serializer = $serializer; | ||
$this->productFactory = $productFactory; | ||
$this->customerSession = $customerSession; | ||
} | ||
|
||
/** | ||
* Retrieve used products for configurable product | ||
* | ||
* @param Configurable $subject | ||
* @param callable $proceed | ||
* @param Product $product | ||
* @param array|null $requiredAttributeIds | ||
* @return ProductInterface[] | ||
* @SuppressWarnings(PHPMD.UnusedFormalParameter) | ||
*/ | ||
public function aroundGetUsedProducts( | ||
Configurable $subject, | ||
callable $proceed, | ||
$product, | ||
$requiredAttributeIds = null | ||
) { | ||
$cacheKey = $this->getCacheKey($product, $requiredAttributeIds); | ||
$usedProducts = $this->readUsedProductsCacheData($cacheKey); | ||
if ($usedProducts === null) { | ||
$usedProducts = $proceed($product, $requiredAttributeIds); | ||
$this->saveUsedProductsCacheData($product, $usedProducts, $cacheKey); | ||
} | ||
|
||
return $usedProducts; | ||
} | ||
|
||
/** | ||
* Generate cache key for product | ||
* | ||
* @param Product $product | ||
* @param array|null $requiredAttributeIds | ||
* @return string | ||
*/ | ||
private function getCacheKey($product, $requiredAttributeIds = null): string | ||
{ | ||
$metadata = $this->metadataPool->getMetadata(ProductInterface::class); | ||
$keyParts = [ | ||
'getUsedProducts', | ||
$product->getData($metadata->getLinkField()), | ||
$product->getStoreId(), | ||
$this->customerSession->getCustomerGroupId(), | ||
]; | ||
if ($requiredAttributeIds !== null) { | ||
sort($requiredAttributeIds); | ||
$keyParts[] = implode('', $requiredAttributeIds); | ||
} | ||
$cacheKey = sha1(implode('_', $keyParts)); | ||
|
||
return $cacheKey; | ||
} | ||
|
||
/** | ||
* Read used products data from cache | ||
* | ||
* Looking for cache record stored under provided $cacheKey | ||
* In case data exists turns it into array of products | ||
* | ||
* @param string $cacheKey | ||
* @return ProductInterface[]|null | ||
*/ | ||
private function readUsedProductsCacheData(string $cacheKey): ?array | ||
{ | ||
$data = $this->cache->load($cacheKey); | ||
if (!$data) { | ||
return null; | ||
} | ||
|
||
$items = $this->serializer->unserialize($data); | ||
if (!$items) { | ||
return null; | ||
} | ||
|
||
$usedProducts = []; | ||
foreach ($items as $item) { | ||
/** @var Product $productItem */ | ||
$productItem = $this->productFactory->create(); | ||
$productItem->setData($item); | ||
$usedProducts[] = $productItem; | ||
} | ||
|
||
return $usedProducts; | ||
} | ||
|
||
/** | ||
* Save $subProducts to cache record identified with provided $cacheKey | ||
* | ||
* Cached data will be tagged with combined list of product tags and data specific tags i.e. 'price' etc. | ||
* | ||
* @param Product $product | ||
* @param ProductInterface[] $subProducts | ||
* @param string $cacheKey | ||
* @return bool | ||
*/ | ||
private function saveUsedProductsCacheData(Product $product, array $subProducts, string $cacheKey): bool | ||
{ | ||
$metadata = $this->metadataPool->getMetadata(ProductInterface::class); | ||
$data = $this->serializer->serialize( | ||
array_map( | ||
function ($item) { | ||
return $item->getData(); | ||
}, | ||
$subProducts | ||
) | ||
); | ||
$tags = array_merge( | ||
$product->getIdentities(), | ||
[ | ||
Category::CACHE_TAG, | ||
Product::CACHE_TAG, | ||
'price', | ||
Configurable::TYPE_CODE . '_' . $product->getData($metadata->getLinkField()), | ||
] | ||
); | ||
$result = $this->cache->save($data, $cacheKey, $tags); | ||
|
||
return (bool) $result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters