>> */ private array $colorSwatches = []; public function __construct( Context $context, private readonly CollectionFactory $productCollectionFactory, private readonly Visibility $productVisibility, private readonly SwatchHelper $swatchHelper, private readonly SwatchMediaHelper $swatchMediaHelper, private readonly PriceCurrencyInterface $priceCurrency, private readonly HttpContext $httpContext, private readonly CardPriceResolver $cardPriceResolver, array $data = [] ) { parent::__construct($context, $data); } public function getSubtitle(): string { return trim((string) $this->getConfig('subtitle')); } public function getExploreAllUrl(): string { return trim((string) $this->getConfig('explore_all_url')); } /** * @return Product[] */ public function getProducts(): array { if ($this->products !== null) { return $this->products; } $skus = $this->getConfiguredSkus(); if (!$skus) { return $this->products = []; } $collection = $this->productCollectionFactory->create(); $collection->setStoreId((int) $this->_storeManager->getStore()->getId()); $this->_addProductAttributesAndPrices($collection); $collection->addAttributeToSelect(['short_description']); $collection->addStoreFilter(); $collection->addAttributeToFilter('sku', ['in' => $skus]); $collection->addAttributeToFilter( 'visibility', ['in' => $this->productVisibility->getVisibleInSiteIds()] ); $collection->addAttributeToFilter( 'status', Product\Attribute\Source\Status::STATUS_ENABLED ); $productsBySku = []; foreach ($collection as $product) { $productsBySku[strtolower((string) $product->getSku())] = $product; } $this->products = []; foreach ($skus as $sku) { $key = strtolower($sku); if (isset($productsBySku[$key])) { $this->products[] = $productsBySku[$key]; } } return $this->products; } public function getShortDescription(Product $product): string { $description = html_entity_decode( strip_tags((string) $product->getData('short_description')), ENT_QUOTES | ENT_HTML5 ); return trim((string) preg_replace('/\s+/u', ' ', $description)); } /** * @return array> */ public function getColorSwatches(Product $product): array { $productId = (int) $product->getId(); if (isset($this->colorSwatches[$productId])) { return $this->colorSwatches[$productId]; } if ($product->getTypeId() !== 'configurable') { return $this->colorSwatches[$productId] = []; } $colorAttribute = null; foreach ($product->getTypeInstance()->getConfigurableAttributes($product) as $attribute) { if ($attribute->getProductAttribute()->getAttributeCode() === 'color') { $colorAttribute = $attribute->getProductAttribute(); $colorAttribute->setStoreId((int) $this->_storeManager->getStore()->getId()); break; } } if ($colorAttribute === null) { return $this->colorSwatches[$productId] = []; } $childIdsByGroup = $product->getTypeInstance()->getChildrenIds($productId); $childIds = array_values(array_unique(array_map( 'intval', array_merge(...array_values($childIdsByGroup ?: [[]])) ))); if (!$childIds) { return $this->colorSwatches[$productId] = []; } $childCollection = $this->productCollectionFactory->create(); $childCollection->setStoreId((int) $this->_storeManager->getStore()->getId()); $childCollection->addIdFilter($childIds); $childCollection->addAttributeToSelect(['color', 'sku', 'image', 'small_image', 'thumbnail']); $childCollection->addAttributeToFilter( 'status', Product\Attribute\Source\Status::STATUS_ENABLED ); $childCollection->setOrder('entity_id', 'ASC'); $childrenByOption = []; foreach ($childCollection as $childProduct) { $optionId = (int) $childProduct->getData('color'); if ($optionId > 0 && !isset($childrenByOption[$optionId])) { $childrenByOption[$optionId] = $childProduct; } } if (!$childrenByOption) { return $this->colorSwatches[$productId] = []; } $swatchData = $this->swatchHelper->getSwatchesByOptionsId(array_keys($childrenByOption)); $result = []; foreach ($childrenByOption as $optionId => $childProduct) { $swatch = $swatchData[$optionId] ?? []; $type = (int) ($swatch['type'] ?? Swatch::SWATCH_TYPE_EMPTY); $value = (string) ($swatch['value'] ?? ''); $result[] = [ 'id' => $optionId, 'sku' => (string) $childProduct->getSku(), 'label' => (string) $colorAttribute->getSource()->getOptionText($optionId), 'type' => $type, 'value' => $value, 'product_image' => $this->getProductImageUrl($childProduct, 'category_page_grid'), 'product_image_large' => $this->getProductImageUrl($childProduct, 'product_page_image_large'), 'image' => $type === Swatch::SWATCH_TYPE_VISUAL_IMAGE && $value !== '' ? $this->swatchMediaHelper->getSwatchAttributeImage( Swatch::SWATCH_IMAGE_NAME, $value ) : '', ]; } return $this->colorSwatches[$productId] = $result; } public function getProductImageUrl(Product $product, string $imageId = 'category_page_grid'): string { return (string) $this->getImage($product, $imageId)->getImageUrl(); } public function getFormattedFinalPrice(Product $product): string { return $this->formatPrice($this->getFinalPriceValue($product)); } public function getFormattedRegularPrice(Product $product): string { return $this->formatPrice($this->getRegularPriceValue($product)); } public function hasRegularPrice(Product $product): bool { return $this->getRegularPriceValue($product) > $this->getFinalPriceValue($product); } public function getCacheKeyInfo(): array { return [ 'ESUN_HOMEPAGE_HOT_SALE_FILAMENT', (int) $this->_storeManager->getStore()->getId(), (string) $this->httpContext->getValue(\Magento\Customer\Model\Context::CONTEXT_GROUP), sha1(implode('|', $this->getConfiguredSkus())), sha1($this->getSubtitle()), sha1($this->getExploreAllUrl()), ]; } public function getIdentities(): array { $identities = []; foreach ($this->getProducts() as $product) { $identities = array_merge($identities, $product->getIdentities()); } return array_values(array_unique($identities)); } private function getConfiguredSkus(): array { $value = (string) $this->getConfig('skus'); $skus = preg_split('/[\s,;]+/', $value, -1, PREG_SPLIT_NO_EMPTY) ?: []; return array_values(array_unique(array_map('trim', $skus))); } private function getConfig(string $field): mixed { return $this->_scopeConfig->getValue( self::XML_PATH . $field, ScopeInterface::SCOPE_STORE ); } private function getFinalPriceValue(Product $product): float { return $this->cardPriceResolver->getFinalPrice($product); } private function getRegularPriceValue(Product $product): float { return $this->cardPriceResolver->getRegularPrice($product); } private function formatPrice(float $price): string { return $this->priceCurrency->format( $price, false, PriceCurrencyInterface::DEFAULT_PRECISION, $this->_storeManager->getStore() ); } }