Current File : /var/www/prestashop/modules/ps_eventbus/src/Decorator/ProductDecorator.php |
<?php
namespace PrestaShop\Module\PsEventbus\Decorator;
use PrestaShop\Module\PsEventbus\Config\Config;
use PrestaShop\Module\PsEventbus\Formatter\ArrayFormatter;
use PrestaShop\Module\PsEventbus\Repository\BundleRepository;
use PrestaShop\Module\PsEventbus\Repository\CategoryRepository;
use PrestaShop\Module\PsEventbus\Repository\LanguageRepository;
use PrestaShop\Module\PsEventbus\Repository\ProductRepository;
class ProductDecorator
{
/**
* @var \Context
*/
private $context;
/**
* @var LanguageRepository
*/
private $languageRepository;
/**
* @var ProductRepository
*/
private $productRepository;
/**
* @var CategoryRepository
*/
private $categoryRepository;
/**
* @var ArrayFormatter
*/
private $arrayFormatter;
/**
* @var BundleRepository
*/
private $bundleRepository;
/**
* @var int
*/
private $shopId;
public function __construct(
\Context $context,
LanguageRepository $languageRepository,
ProductRepository $productRepository,
CategoryRepository $categoryRepository,
ArrayFormatter $arrayFormatter,
BundleRepository $bundleRepository
) {
$this->context = $context;
$this->languageRepository = $languageRepository;
$this->productRepository = $productRepository;
$this->categoryRepository = $categoryRepository;
$this->arrayFormatter = $arrayFormatter;
$this->bundleRepository = $bundleRepository;
if ($this->context->shop === null) {
throw new \PrestaShopException('No shop context');
}
$this->shopId = (int) $this->context->shop->id;
}
/**
* @param array<mixed> $products
* @param string $langIso
* @param int $langId
*
* @return void
*
* @@throws \PrestaShopDatabaseException
*/
public function decorateProducts(&$products, $langIso, $langId)
{
$this->addFeatureValues($products, $langId);
$this->addAttributeValues($products, $langId);
$this->addImages($products);
foreach ($products as &$product) {
$this->addLanguageIsoCode($product, $langIso);
$this->addUniqueId($product);
$this->addAttributeId($product);
$this->addLink($product);
$this->addProductPrices($product);
$this->formatDescriptions($product);
$this->addCategoryTree($product);
$this->castPropertyValues($product);
}
}
/**
* @param array<mixed> $products
*
* @return array<mixed>
*/
public function getBundles($products)
{
$bundles = [];
foreach ($products as $product) {
if ($product['is_bundle']) {
$bundles = array_merge($bundles, $this->getBundleCollection($product));
}
}
return $bundles;
}
/**
* @param array<mixed> $product
*
* @return void
*/
private function addLink(&$product)
{
try {
if ($this->context->link === null) {
throw new \PrestaShopException('No link context');
}
$product['link'] = $this->context->link->getProductLink(
$product,
null,
null,
null,
$this->languageRepository->getLanguageIdByIsoCode($product['iso_code']),
$this->shopId,
$product['id_attribute']
);
} catch (\PrestaShopException $e) {
$product['link'] = '';
}
}
/**
* @param array<mixed> $product
*
* @return void
*/
private function addProductPrices(&$product)
{
$product['price_tax_excl'] = (float) $product['price_tax_excl'];
$product['price_tax_incl'] =
(float) $this->productRepository->getPriceTaxIncluded($product['id_product'], $product['id_attribute']);
$product['sale_price_tax_excl'] =
(float) $this->productRepository->getSalePriceTaxExcluded($product['id_product'], $product['id_attribute']);
$product['sale_price_tax_incl'] =
(float) $this->productRepository->getSalePriceTaxIncluded($product['id_product'], $product['id_attribute']);
$product['tax'] = $product['price_tax_incl'] - $product['price_tax_excl'];
$product['sale_tax'] = $product['sale_price_tax_incl'] - $product['sale_price_tax_excl'];
}
/**
* @param array<mixed> $product
*
* @return array<mixed>
*/
private function getBundleCollection($product)
{
$bundleProducts = $this->bundleRepository->getBundleProducts($product['id_product']);
$uniqueProductId = $product['unique_product_id'];
return array_map(function ($bundleProduct) use ($uniqueProductId) {
return [
'id' => $bundleProduct['id_bundle'],
'collection' => Config::COLLECTION_BUNDLES,
'properties' => [
'id_bundle' => $bundleProduct['id_bundle'],
'id_product' => $bundleProduct['id_product'],
'id_product_attribute' => $bundleProduct['id_product_attribute'],
'unique_product_id' => $uniqueProductId,
'quantity' => $bundleProduct['quantity'],
],
];
}, $bundleProducts);
}
/**
* @param array<mixed> $product
*
* @return void
*/
private function formatDescriptions(&$product)
{
$product['description'] = base64_encode($product['description']);
$product['description_short'] = base64_encode($product['description_short']);
}
/**
* @param array<mixed> $product
*
* @return void
*/
private function addCategoryTree(&$product)
{
$categoryPaths = $this->categoryRepository->getCategoryPaths(
$product['id_category_default'],
$this->languageRepository->getLanguageIdByIsoCode($product['iso_code']),
$this->shopId
);
$product['category_path'] = $categoryPaths['category_path'];
$product['category_id_path'] = $categoryPaths['category_id_path'];
}
/**
* @param array<mixed> $product
*
* @return void
*/
private function castPropertyValues(&$product)
{
$product['id_product'] = (int) $product['id_product'];
$product['id_manufacturer'] = (int) $product['id_manufacturer'];
$product['id_supplier'] = (int) $product['id_supplier'];
$product['id_attribute'] = (int) $product['id_attribute'];
$product['id_category_default'] = (int) $product['id_category_default'];
$product['quantity'] = (int) $product['quantity'];
$product['weight'] = (float) $product['weight'];
$product['active'] = $product['active'] == '1';
$product['manufacturer'] = (string) $product['manufacturer'];
$product['default_category'] = (string) $product['default_category'];
$product['isbn'] = isset($product['isbn']) ? (string) $product['isbn'] : '';
$product['mpn'] = isset($product['mpn']) ? (string) $product['mpn'] : '';
$product['ean'] = (string) $product['ean'];
$product['upc'] = (string) $product['upc'];
$product['is_default_attribute'] = $product['id_attribute'] === 0 ? true : $product['is_default_attribute'] == 1;
$product['available_for_order'] = $product['available_for_order'] == '1';
$product['available_date'] = (string) $product['available_date'];
$product['is_bundle'] = $product['is_bundle'] == '1';
$product['is_virtual'] = $product['is_virtual'] == '1';
$product['unit_price_ratio'] = (float) $product['unit_price_ratio'];
$product['unity'] = (string) $product['unity'];
if ($product['unit_price_ratio'] != 0) {
$product['price_per_unit'] = (float) $product['price_tax_excl'] / (float) $product['unit_price_ratio'];
}
}
/**
* @param array<mixed> $product
*
* @return void
*/
private function addUniqueId(&$product)
{
$product['unique_product_id'] = "{$product['id_product']}-{$product['id_attribute']}-{$product['iso_code']}";
}
/**
* @param array<mixed> $product
*
* @return void
*/
private function addAttributeId(&$product)
{
$product['id_product_attribute'] = "{$product['id_product']}-{$product['id_attribute']}";
}
/**
* @param array<mixed> $product
* @param string $langiso
*
* @return void
*/
private function addLanguageIsoCode(&$product, $langiso)
{
$product['iso_code'] = $langiso;
}
/**
* @param array<mixed> $products
* @param int $langId
*
* @return void
*
* @@throws \PrestaShopDatabaseException
*/
private function addFeatureValues(&$products, $langId)
{
$productIds = $this->arrayFormatter->formatValueArray($products, 'id_product', true);
$features = $this->productRepository->getProductFeatures($productIds, $langId);
foreach ($products as &$product) {
$product['features'] = isset($features[$product['id_product']]) ? $features[$product['id_product']] : '';
}
}
/**
* @param array<mixed> $products
* @param int $langId
*
* @return void
*
* @@throws \PrestaShopDatabaseException
*/
private function addAttributeValues(&$products, $langId)
{
$attributeIds = $this->arrayFormatter->formatValueArray($products, 'id_attribute', true);
$attributes = $this->productRepository->getProductAttributeValues($attributeIds, $langId);
foreach ($products as &$product) {
$product['attributes'] = isset($attributes[$product['id_attribute']]) ? $attributes[$product['id_attribute']] : '';
}
}
/**
* @param array<mixed> $products
*
* @return void
*
* @@throws \PrestaShopDatabaseException
*/
private function addImages(&$products)
{
$productIds = $this->arrayFormatter->formatValueArray($products, 'id_product', true);
$attributeIds = $this->arrayFormatter->formatValueArray($products, 'id_attribute', true);
$images = $this->productRepository->getProductImages($productIds);
$attributeImages = $this->productRepository->getAttributeImages($attributeIds);
foreach ($products as &$product) {
$coverImageId = '0';
$productImages = array_filter($images, function ($image) use ($product) {
return $image['id_product'] === $product['id_product'];
});
foreach ($productImages as $productImage) {
if ($productImage['cover'] == 1) {
$coverImageId = $productImage['id_image'];
break;
}
}
// Product is without attributes -> get product images
if ($product['id_attribute'] == 0) {
$productImageIds = $this->arrayFormatter->formatValueArray($productImages, 'id_image');
} else {
$productAttributeImages = array_filter($attributeImages, function ($image) use ($product) {
return $image['id_product_attribute'] === $product['id_attribute'];
});
// If a combination has some pictures -> the first one is the cover
if (count($productAttributeImages)) {
$productImageIds = $this->arrayFormatter->formatValueArray($productAttributeImages, 'id_image');
$coverImageId = reset($productImageIds);
}
// Fallback on cover & images of the product when no pictures are chosen
else {
$productImageIds = $this->arrayFormatter->formatValueArray($productImages, 'id_image');
}
}
$productImageIds = array_diff($productImageIds, [$coverImageId]);
if ($this->context->link === null) {
throw new \PrestaShopException('No link context');
}
$link = $this->context->link;
// For some stores, we might implement a behavior that dynamically adapts,
// retrieving the appropriate label from an image table to accurately reflect
// the merchant's available items.
$product['images'] = $this->arrayFormatter->arrayToString(
array_map(function ($imageId) use ($product, $link) {
return $link->getImageLink($product['link_rewrite'], (string) $imageId);
}, $productImageIds)
);
$product['cover'] = $coverImageId == '0' ?
'' :
$link->getImageLink($product['link_rewrite'], (string) $coverImageId);
}
}
}