Files
esun3d/app/code/Esun/Homepage/Block/CreateAnything.php
T
2026-09-15 10:35:56 +08:00

211 lines
7.1 KiB
PHP

<?php
declare(strict_types=1);
namespace Esun\Homepage\Block;
use Esun\Catalog\Model\Product\CardPriceResolver;
use Esun\Video\Model\ResourceModel\Video\CollectionFactory as VideoCollectionFactory;
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 as ProductCollectionFactory;
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\Serialize\SerializerInterface;
use Magento\Framework\UrlInterface;
use Magento\Store\Model\ScopeInterface;
class CreateAnything extends AbstractProduct implements IdentityInterface
{
private const XML_PATH_ITEMS = 'esun_homepage/create_anything/items';
/**
* @var array<int, array<string, mixed>>|null
*/
private ?array $items = null;
public function __construct(
Context $context,
private readonly ProductCollectionFactory $productCollectionFactory,
private readonly VideoCollectionFactory $videoCollectionFactory,
private readonly Visibility $productVisibility,
private readonly PriceCurrencyInterface $priceCurrency,
private readonly SerializerInterface $serializer,
private readonly HttpContext $httpContext,
private readonly CardPriceResolver $cardPriceResolver,
array $data = []
) {
parent::__construct($context, $data);
}
/**
* @return array<int, array<string, mixed>>
*/
public function getItems(): array
{
if ($this->items !== null) {
return $this->items;
}
$configuredItems = $this->getConfiguredItems();
if (!$configuredItems) {
return $this->items = [];
}
$videoIds = [];
$skus = [];
foreach ($configuredItems as $item) {
$videoId = (int) ($item['video_id'] ?? 0);
$sku = trim((string) ($item['product_sku'] ?? ''));
if ($videoId > 0) {
$videoIds[$videoId] = $videoId;
}
if ($sku !== '') {
$skus[strtolower($sku)] = $sku;
}
}
$videosById = [];
if ($videoIds) {
$videoCollection = $this->videoCollectionFactory->create();
$videoCollection->addFieldToFilter('video_id', ['in' => array_values($videoIds)]);
$videoCollection->addFieldToFilter('status', 1);
foreach ($videoCollection as $video) {
$videosById[(int) $video->getId()] = $video;
}
}
$productsBySku = [];
if ($skus) {
$productCollection = $this->productCollectionFactory->create();
$productCollection->setStoreId((int) $this->_storeManager->getStore()->getId());
$this->_addProductAttributesAndPrices($productCollection);
$productCollection->addStoreFilter();
$productCollection->addAttributeToFilter('sku', ['in' => array_values($skus)]);
$productCollection->addAttributeToFilter(
'visibility',
['in' => $this->productVisibility->getVisibleInSiteIds()]
);
$productCollection->addAttributeToFilter(
'status',
Product\Attribute\Source\Status::STATUS_ENABLED
);
foreach ($productCollection as $product) {
$productsBySku[strtolower((string) $product->getSku())] = $product;
}
}
$mediaBaseUrl = $this->_storeManager->getStore()->getBaseUrl(UrlInterface::URL_TYPE_MEDIA);
$this->items = [];
foreach ($configuredItems as $item) {
$videoId = (int) ($item['video_id'] ?? 0);
$skuKey = strtolower(trim((string) ($item['product_sku'] ?? '')));
$video = $videosById[$videoId] ?? null;
$product = $productsBySku[$skuKey] ?? null;
if (!$video || !$product) {
continue;
}
$this->items[] = [
'title' => trim((string) ($item['title'] ?? '')),
'subtitle' => trim((string) ($item['subtitle'] ?? '')),
'sort_number' => (int) ($item['sort_number'] ?? 0),
'video_url' => $mediaBaseUrl . ltrim((string) $video->getData('video_path'), '/'),
'cover_url' => $mediaBaseUrl . ltrim((string) $video->getData('cover_path'), '/'),
'product' => $product,
];
}
return $this->items;
}
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_CREATE_ANYTHING',
(int) $this->_storeManager->getStore()->getId(),
(int) $this->httpContext->getValue(CustomerContext::CONTEXT_GROUP),
sha1((string) $this->_scopeConfig->getValue(
self::XML_PATH_ITEMS,
ScopeInterface::SCOPE_STORE
)),
];
}
public function getIdentities(): array
{
$identities = [];
foreach ($this->getItems() as $item) {
$product = $item['product'] ?? null;
if ($product instanceof Product) {
$identities = array_merge($identities, $product->getIdentities());
}
}
return array_values(array_unique($identities));
}
/**
* @return array<int, array<string, mixed>>
*/
private function getConfiguredItems(): array
{
$value = $this->_scopeConfig->getValue(
self::XML_PATH_ITEMS,
ScopeInterface::SCOPE_STORE
);
if (is_array($value)) {
return array_values($value);
}
if (!is_string($value) || trim($value) === '') {
return [];
}
try {
$items = $this->serializer->unserialize($value);
} catch (\InvalidArgumentException) {
return [];
}
return is_array($items) ? array_values($items) : [];
}
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()
);
}
}