281 lines
9.4 KiB
PHP
281 lines
9.4 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace Esun\Homepage\Block;
|
|
|
|
use Esun\Catalog\Model\Product\CardPriceResolver;
|
|
use Magento\Catalog\Block\Product\AbstractProduct;
|
|
use Magento\Catalog\Block\Product\Context;
|
|
use Magento\Catalog\Model\Product;
|
|
use Magento\Catalog\Model\Product\Visibility;
|
|
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
|
|
use Magento\Customer\Model\Context as CustomerContext;
|
|
use Magento\Framework\App\Http\Context as HttpContext;
|
|
use Magento\Framework\DataObject\IdentityInterface;
|
|
use Magento\Framework\Pricing\PriceCurrencyInterface;
|
|
use Magento\Framework\UrlInterface;
|
|
use Magento\Store\Model\ScopeInterface;
|
|
use Magento\Swatches\Helper\Data as SwatchHelper;
|
|
use Magento\Swatches\Helper\Media as SwatchMediaHelper;
|
|
use Magento\Swatches\Model\Swatch;
|
|
|
|
class Resin extends AbstractProduct implements IdentityInterface
|
|
{
|
|
private const XML_PATH = 'esun_homepage/resin/';
|
|
private const BACKGROUND_MEDIA_PATH = 'esun/homepage/resin/';
|
|
|
|
/**
|
|
* @var Product[]|null
|
|
*/
|
|
private ?array $products = null;
|
|
|
|
/**
|
|
* @var array<int, array<int, array<string, int|string>>>
|
|
*/
|
|
private array $colorSwatches = [];
|
|
|
|
public function __construct(
|
|
Context $context,
|
|
private readonly CollectionFactory $productCollectionFactory,
|
|
private readonly Visibility $productVisibility,
|
|
private readonly PriceCurrencyInterface $priceCurrency,
|
|
private readonly HttpContext $httpContext,
|
|
private readonly SwatchHelper $swatchHelper,
|
|
private readonly SwatchMediaHelper $swatchMediaHelper,
|
|
private readonly CardPriceResolver $cardPriceResolver,
|
|
array $data = []
|
|
) {
|
|
parent::__construct($context, $data);
|
|
}
|
|
|
|
/**
|
|
* @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 getBackgroundImageUrl(): string
|
|
{
|
|
$image = ltrim(trim((string) $this->getConfig('background_image')), '/');
|
|
if ($image === '') {
|
|
return '';
|
|
}
|
|
|
|
return $this->_storeManager->getStore()->getBaseUrl(UrlInterface::URL_TYPE_MEDIA)
|
|
. self::BACKGROUND_MEDIA_PATH
|
|
. $image;
|
|
}
|
|
|
|
public function getExploreAllUrl(): string
|
|
{
|
|
return trim((string) $this->getConfig('explore_all_url'));
|
|
}
|
|
|
|
public function getShortDescription(Product $product): string
|
|
{
|
|
return trim((string) preg_replace(
|
|
'/\s+/u',
|
|
' ',
|
|
strip_tags((string) $product->getData('short_description'))
|
|
));
|
|
}
|
|
|
|
/**
|
|
* @return array<int, array<string, int|string>>
|
|
*/
|
|
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),
|
|
'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_RESIN',
|
|
(int) $this->_storeManager->getStore()->getId(),
|
|
(int) $this->httpContext->getValue(CustomerContext::CONTEXT_GROUP),
|
|
sha1(implode('|', $this->getConfiguredSkus())),
|
|
sha1($this->getBackgroundImageUrl()),
|
|
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()
|
|
);
|
|
}
|
|
}
|