From 35161d98fa72352ddd18de9c773cf02ff240a8e0 Mon Sep 17 00:00:00 2001 From: Pierre LE MAGUER Date: Fri, 24 Sep 2021 16:06:59 +0200 Subject: [PATCH 1/2] [Autocomplete] Optimize thumbnail request --- .../Autocomplete/Product/ThumbnailHelper.php | 185 +++++++++++++----- 1 file changed, 139 insertions(+), 46 deletions(-) diff --git a/src/module-elasticsuite-instant-search/Model/Autocomplete/Product/ThumbnailHelper.php b/src/module-elasticsuite-instant-search/Model/Autocomplete/Product/ThumbnailHelper.php index 8677fbee9..1294790a6 100644 --- a/src/module-elasticsuite-instant-search/Model/Autocomplete/Product/ThumbnailHelper.php +++ b/src/module-elasticsuite-instant-search/Model/Autocomplete/Product/ThumbnailHelper.php @@ -7,19 +7,25 @@ * @category Smile * @package Smile\ElasticsuiteInstantSearch * @author Romain Ruaud - * @copyright 2021 Smile - * @license Licensed to Smile-SA. All rights reserved. No warranty, explicit or implicit, provided. - * Unauthorized copying of this file, via any medium, is strictly prohibited. + * @copyright 2020 Smile + * @license Open Software License ("OSL") v. 3.0 */ namespace Smile\ElasticsuiteInstantSearch\Model\Autocomplete\Product; -use Magento\Catalog\Api\Data\ProductInterface; -use Magento\Catalog\Helper\Image as ImageHelper; -use Magento\Catalog\Helper\ImageFactory as ImageHelperFactory; -use Magento\Framework\ObjectManagerInterface; use Magento\Catalog\Api\ProductRepositoryInterfaceFactory; -use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Helper\Image; +use Magento\Catalog\Model\Product\Image\ParamsBuilder; +use Magento\Catalog\Model\ResourceModel\Product; +use Magento\Catalog\Model\View\Asset\PlaceholderFactory; +use Magento\Framework\App\Area; +use Magento\Framework\App\CacheInterface; +use Magento\Catalog\Model\View\Asset\Image as AssertImage; +use Magento\Catalog\Model\View\Asset\ImageFactory as AssertImageFactory; +use Magento\Framework\Serialize\SerializerInterface; +use Magento\Framework\View\Asset\Repository as AssetRepository; +use Magento\Framework\View\ConfigInterface; +use Magento\Framework\View\DesignInterface; use Magento\Store\Model\StoreManagerInterface; use Magento\Store\Model\StoreManagerInterfaceFactory; @@ -33,65 +39,146 @@ class ThumbnailHelper { /** - * @var ImageHelperFactory + * @var AssertImageFactory */ - private $imageHelperFactory; + private $assertImageFactory; /** - * @var ProductRepositoryInterfaceFactory + * @var DesignInterface */ - private $productRepositoryFactory; + private $design; + + /** + * @var ConfigInterface + */ + private $viewConfig; /** * @var StoreManagerInterfaceFactory */ - private $storeManager; + private $storeManagerFactory; + + /** + * @var ParamsBuilder + */ + private $paramsBuilder; + + /** + * @var Product + */ + private $productResource; + + /** + * @var PlaceholderFactory + */ + private $placeholderFactory; + + /** + * @var AssetRepository + */ + private $assetRepository; + + /** + * @var CacheInterface + */ + private $cache; + + /** + * @var SerializerInterface + */ + private $serializer; /** - * Constructor. + * Constructor * - * @param ImageHelperFactory $imageHelperFactory Catalog product image helper. - * @param ProductRepositoryInterfaceFactory $productRepositoryFactory Product Repository - * @param StoreManagerInterfaceFactory $storeManagerFactory Store Manager + * @param DesignInterface $design Design + * @param StoreManagerInterfaceFactory $storeManagerFactory Store Manager factory + * @param ConfigInterface $viewConfig View config + * @param ParamsBuilder $paramsBuilder Params builder + * @param Product $productResource Product Resource + * @param AssetRepository $assetRepository Asset Repository + * @param PlaceholderFactory $placeholderFactory Placeholder Factory + * @param AssertImageFactory $assertImageFactory + * @param CacheInterface $cache + * @param SerializerInterface $serializer */ public function __construct( - ImageHelperFactory $imageHelperFactory, - ProductRepositoryInterfaceFactory $productRepositoryFactory, - StoreManagerInterfaceFactory $storeManagerFactory + DesignInterface $design, + StoreManagerInterfaceFactory $storeManagerFactory, + ConfigInterface $viewConfig, + ParamsBuilder $paramsBuilder, + Product $productResource, + AssetRepository $assetRepository, + PlaceholderFactory $placeholderFactory, + AssertImageFactory $assertImageFactory, + CacheInterface $cache, + SerializerInterface $serializer ) { - $this->imageHelperFactory = $imageHelperFactory; - $this->productRepositoryFactory = $productRepositoryFactory; - $this->storeManagerFactory = $storeManagerFactory; + $this->design = $design; + $this->storeManagerFactory = $storeManagerFactory; + $this->viewConfig = $viewConfig; + $this->paramsBuilder = $paramsBuilder; + $this->productResource = $productResource; + $this->placeholderFactory = $placeholderFactory; + $this->assetRepository = $assetRepository; + $this->assertImageFactory = $assertImageFactory; + $this->cache = $cache; + $this->serializer = $serializer; } /** * Get resized image URL. * - * @param int $productId Product Id - * @param string $imageId The image name - * + * @param int $productId Product Id + * @param string $imageId The image name * @return string */ - public function getImageUrl($productId, $imageId = ItemFactory::AUTOCOMPLETE_IMAGE_ID) + public function getImageUrl($productId, $imageId = ItemFactory::AUTOCOMPLETE_IMAGE_ID): string { - try { - $product = $this->getProductRepository()->getById($productId, false, $this->getStoreManager()->getStore()->getId()); - } catch (\Magento\Framework\Exception\NoSuchEntityException $exception) { - return ''; + $storeId = (int) $this->getStoreManager()->getStore()->getId(); + $mediaData = $this->getMediaData($imageId, $storeId); + $imageType = $mediaData['image_type'] ?? 'thumbnail'; + $productImage = $this->productResource->getAttributeRawValue($productId, $imageType, $storeId); + /** @var AssertImage $imageAsset */ + $imageAsset = $this->assertImageFactory->create( + [ + 'miscParams' => $mediaData, + 'filePath' => trim($productImage, '/'), + ] + ); + if ($productImage) { + return $imageAsset->getUrl(); } - $helper = $this->getImageHelper(); - $helper->init($product, $imageId); - - return $helper->getUrl(); + return $this->getPlaceholder($imageType); } /** - * @return ProductRepositoryInterface + * Get media data from view configuration. + * + * @param string $imageId Image id + * @param int $storeId Store id + * @return array */ - private function getProductRepository() + protected function getMediaData($imageId, $storeId) { - return $this->productRepositoryFactory->create(); + $cacheKey = 'instant_search_media_data_thumbnail' . $storeId . '-' . $imageId; + $mediaData = $this->cache->load($cacheKey); + if ($mediaData === false) { + $currentTheme = $this->design->getDesignTheme(); + $config = $this->viewConfig->getViewConfig( + [ + 'area' => Area::AREA_FRONTEND, + 'themeModel' => $currentTheme, + ] + ); + $mediaAttributes = $config->getMediaAttributes('Magento_Catalog', Image::MEDIA_TYPE_CONFIG_NODE, $imageId); + $mediaData = $this->paramsBuilder->build($mediaAttributes, (int) $storeId); + $this->cache->save($this->serializer->serialize($mediaData), $cacheKey); + return $mediaData; + } else { + return $this->serializer->unserialize($mediaData); + } } /** @@ -99,18 +186,24 @@ private function getProductRepository() */ private function getStoreManager() { - if (null === $this->storeManager) { - $this->storeManager = $this->storeManagerFactory->create(); - } - - return $this->storeManager; + return $this->storeManagerFactory->create(); } /** - * @return ImageHelper + * Get placeholder. + * + * @param string $imageType Image type + * @return string */ - private function getImageHelper() + private function getPlaceholder(string $imageType): string { - return $this->imageHelperFactory->create(); + $imageAsset = $this->placeholderFactory->create(['type' => $imageType]); + + // check if placeholder defined in config + if ($imageAsset->getFilePath()) { + return $imageAsset->getUrl(); + } + + return $this->assetRepository->getUrl("Magento_Catalog::images/product/placeholder/{$imageType}.jpg"); } } From e03f40e1390bdf1fd637103ae1a7b8a520a1d053 Mon Sep 17 00:00:00 2001 From: Romain Ruaud Date: Tue, 5 Oct 2021 11:10:07 +0200 Subject: [PATCH 2/2] Code cleaning --- .../Autocomplete/Product/ThumbnailHelper.php | 85 ++++++++++--------- 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/src/module-elasticsuite-instant-search/Model/Autocomplete/Product/ThumbnailHelper.php b/src/module-elasticsuite-instant-search/Model/Autocomplete/Product/ThumbnailHelper.php index 1294790a6..09c487047 100644 --- a/src/module-elasticsuite-instant-search/Model/Autocomplete/Product/ThumbnailHelper.php +++ b/src/module-elasticsuite-instant-search/Model/Autocomplete/Product/ThumbnailHelper.php @@ -13,15 +13,14 @@ namespace Smile\ElasticsuiteInstantSearch\Model\Autocomplete\Product; -use Magento\Catalog\Api\ProductRepositoryInterfaceFactory; use Magento\Catalog\Helper\Image; use Magento\Catalog\Model\Product\Image\ParamsBuilder; use Magento\Catalog\Model\ResourceModel\Product; +use Magento\Catalog\Model\View\Asset\Image as AssetImage; +use Magento\Catalog\Model\View\Asset\ImageFactory as AssetImageFactory; use Magento\Catalog\Model\View\Asset\PlaceholderFactory; use Magento\Framework\App\Area; use Magento\Framework\App\CacheInterface; -use Magento\Catalog\Model\View\Asset\Image as AssertImage; -use Magento\Catalog\Model\View\Asset\ImageFactory as AssertImageFactory; use Magento\Framework\Serialize\SerializerInterface; use Magento\Framework\View\Asset\Repository as AssetRepository; use Magento\Framework\View\ConfigInterface; @@ -32,6 +31,8 @@ /** * Thumbnail helper for instant search. * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * * @category Smile * @package Smile\ElasticsuiteInstantSearch * @author Romain Ruaud @@ -39,9 +40,9 @@ class ThumbnailHelper { /** - * @var AssertImageFactory + * @var AsserImageFactory */ - private $assertImageFactory; + private $assetImageFactory; /** * @var DesignInterface @@ -91,28 +92,30 @@ class ThumbnailHelper /** * Constructor * - * @param DesignInterface $design Design + * @SuppressWarnings(PHPMD.ExcessiveParameterList) + * + * @param DesignInterface $design Design * @param StoreManagerInterfaceFactory $storeManagerFactory Store Manager factory - * @param ConfigInterface $viewConfig View config - * @param ParamsBuilder $paramsBuilder Params builder - * @param Product $productResource Product Resource - * @param AssetRepository $assetRepository Asset Repository - * @param PlaceholderFactory $placeholderFactory Placeholder Factory - * @param AssertImageFactory $assertImageFactory - * @param CacheInterface $cache - * @param SerializerInterface $serializer + * @param ConfigInterface $viewConfig View config + * @param ParamsBuilder $paramsBuilder Params builder + * @param Product $productResource Product Resource + * @param AssetRepository $assetRepository Asset Repository + * @param PlaceholderFactory $placeholderFactory Placeholder Factory + * @param AssetImageFactory $assetImageFactory Asset Image Factory + * @param CacheInterface $cache Cache + * @param SerializerInterface $serializer Serializer */ public function __construct( - DesignInterface $design, + DesignInterface $design, StoreManagerInterfaceFactory $storeManagerFactory, - ConfigInterface $viewConfig, - ParamsBuilder $paramsBuilder, - Product $productResource, - AssetRepository $assetRepository, - PlaceholderFactory $placeholderFactory, - AssertImageFactory $assertImageFactory, - CacheInterface $cache, - SerializerInterface $serializer + ConfigInterface $viewConfig, + ParamsBuilder $paramsBuilder, + Product $productResource, + AssetRepository $assetRepository, + PlaceholderFactory $placeholderFactory, + AssetImageFactory $assetImageFactory, + CacheInterface $cache, + SerializerInterface $serializer ) { $this->design = $design; $this->storeManagerFactory = $storeManagerFactory; @@ -121,7 +124,7 @@ public function __construct( $this->productResource = $productResource; $this->placeholderFactory = $placeholderFactory; $this->assetRepository = $assetRepository; - $this->assertImageFactory = $assertImageFactory; + $this->assetImageFactory = $assetImageFactory; $this->cache = $cache; $this->serializer = $serializer; } @@ -129,21 +132,22 @@ public function __construct( /** * Get resized image URL. * - * @param int $productId Product Id - * @param string $imageId The image name + * @param int $productId Product Id + * @param string $imageId The image name + * * @return string */ public function getImageUrl($productId, $imageId = ItemFactory::AUTOCOMPLETE_IMAGE_ID): string { - $storeId = (int) $this->getStoreManager()->getStore()->getId(); - $mediaData = $this->getMediaData($imageId, $storeId); - $imageType = $mediaData['image_type'] ?? 'thumbnail'; + $storeId = (int) $this->getStoreManager()->getStore()->getId(); + $mediaData = $this->getMediaData($imageId, $storeId); + $imageType = $mediaData['image_type'] ?? 'thumbnail'; $productImage = $this->productResource->getAttributeRawValue($productId, $imageType, $storeId); - /** @var AssertImage $imageAsset */ - $imageAsset = $this->assertImageFactory->create( + /** @var AssetImage $imageAsset */ + $imageAsset = $this->assetImageFactory->create( [ 'miscParams' => $mediaData, - 'filePath' => trim($productImage, '/'), + 'filePath' => trim($productImage, '/'), ] ); if ($productImage) { @@ -156,25 +160,29 @@ public function getImageUrl($productId, $imageId = ItemFactory::AUTOCOMPLETE_IMA /** * Get media data from view configuration. * + * @SuppressWarnings(PHPMD.ElseExpression) + * * @param string $imageId Image id * @param int $storeId Store id + * * @return array */ protected function getMediaData($imageId, $storeId) { - $cacheKey = 'instant_search_media_data_thumbnail' . $storeId . '-' . $imageId; + $cacheKey = 'instant_search_media_data_thumbnail' . $storeId . '-' . $imageId; $mediaData = $this->cache->load($cacheKey); if ($mediaData === false) { - $currentTheme = $this->design->getDesignTheme(); - $config = $this->viewConfig->getViewConfig( + $currentTheme = $this->design->getDesignTheme(); + $config = $this->viewConfig->getViewConfig( [ - 'area' => Area::AREA_FRONTEND, + 'area' => Area::AREA_FRONTEND, 'themeModel' => $currentTheme, ] ); $mediaAttributes = $config->getMediaAttributes('Magento_Catalog', Image::MEDIA_TYPE_CONFIG_NODE, $imageId); - $mediaData = $this->paramsBuilder->build($mediaAttributes, (int) $storeId); + $mediaData = $this->paramsBuilder->build($mediaAttributes, (int) $storeId); $this->cache->save($this->serializer->serialize($mediaData), $cacheKey); + return $mediaData; } else { return $this->serializer->unserialize($mediaData); @@ -193,13 +201,14 @@ private function getStoreManager() * Get placeholder. * * @param string $imageType Image type + * * @return string */ private function getPlaceholder(string $imageType): string { $imageAsset = $this->placeholderFactory->create(['type' => $imageType]); - // check if placeholder defined in config + // Check if placeholder defined in config. if ($imageAsset->getFilePath()) { return $imageAsset->getUrl(); }