Files
ltsecurityinc/app/code/Olegnax/ProductLabel/Helper/Helper.php
T

746 lines
23 KiB
PHP
Executable File

<?php /** @noinspection PhpDeprecationInspection */
/**
* Olegnax ProductLabel
*
* NOTICE OF LICENSE
*
* This source file is subject to the Olegnax.com license that is
* available through the world-wide-web at this URL:
* https://www.olegnax.com/license
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this extension to newer
* version in the future.
*
* @category Olegnax
* @package Olegnax_ProductLabel
* @copyright Copyright (c) 2023 Olegnax (http://www.olegnax.com/)
* @license https://www.olegnax.com/license
*/
declare(strict_types=1);
namespace Olegnax\ProductLabel\Helper;
use DateTime;
use Magento\Catalog\Helper\Data;
use Magento\Catalog\Model\Product;
use Magento\Framework\Data\Collection;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Phrase;
use Magento\Framework\Registry;
use Magento\Sales\Model\ResourceModel\Report\Bestsellers\CollectionFactory;
use Magento\Store\Model\ScopeInterface;
use Olegnax\Core\Helper\Helper as CoreHelperHelper;
class Helper extends CoreHelperHelper
{
const CONFIG_MODULE = 'olegnax_productlabel';
/**
* @var \Magento\Framework\Stdlib\DateTime\DateTime
*/
protected $dateTime;
/**
* @var CollectionFactory
*/
protected $reportBestsellers;
/**
* @var array|int[]
*/
private $_bestsellerIds;
/**
* @var int
*/
private $storeCode;
/**
* @var array|array[]
*/
private $cacheCondition = [];
/**
* @param string $method
* @param array $args
*
* @return bool|string
* @throws LocalizedException
*/
public function __call($method, $args)
{
if (preg_match('/^showLabel(.+)$/', $method, $matches)) {
$label = strtolower($matches[1]);
$product = isset($args[0]) ? $args[0] : null;
return $this->getLabel($product, $label);
}
if (preg_match('/^isEnabledLabel(.+)$/', $method, $matches)) {
$label = strtolower($matches[1]);
return $this->isEnabledLabel($label);
}
throw new LocalizedException(
new Phrase('Invalid method %1::%2', [get_class($this), $method])
);
}
/**
* @param Product $product
* @param string $label
*
* @return string
*/
public function getLabel($product, $label)
{
if ($this->isEnabledLabel($label) && $this->isCondition($product, $label) && $this->isLoggedIn()) {
$style = $this->prepareStyle([
'color' => $this->getLabelAttr($label, 'color'),
'background-color' => $this->getLabelAttr($label, 'background_color'),
]);
if (!empty($style)) {
$style = ' style="' . $style . '"';
}
$text = (string)$this->getLabelAttr($label, 'text');
if (false !== strpos($text, '{{')) {
$text = $this->prepareText($text, $product);
}
$text = trim($text);
if (empty($text)) {
return '';
}
return '<span class="ox-product-label-' . $label . '"' . $style . '>' . $text . '</span>';
}
return '';
}
/**
* @param string $label
*
* @return bool
*/
public function isEnabledLabel($label)
{
return (bool)$this->isEnabled() && $this->getModuleConfig('label/' . $label);
}
/**
* @return bool
*/
public function isEnabled()
{
return (bool)$this->getModuleConfig('general/enable');
}
/**
* @param string $path
* @param null|int $storeCode
* @param string $scopeType
*
* @return mixed
*/
public function getModuleConfig($path = '', $storeCode = null, $scopeType = ScopeInterface::SCOPE_STORE)
{
return parent::getModuleConfig($path, $this->getStoreId());
}
/**
* @return int
*/
private function getStoreId()
{
if (empty($this->storeCode)) {
$this->storeCode = $this->getStore()->getId();
}
return $this->storeCode;
}
/**
* @param Product $product
* @param string $label
*
* @return bool|mixed
*/
protected function isCondition($product, $label)
{
$result = false;
$productId = $product->getId();
if (isset($this->cacheCondition[$productId]) && isset($this->cacheCondition[$productId][$label])) {
return $this->cacheCondition[$productId][$label];
}
switch ($label) {
case 'bestseller':
$result = $this->isConditionBestseller($productId);
break;
case 'custom':
$result = $this->isConditionCustom($product);
break;
case 'featured':
$result = $this->isConditionFeatured($product);
break;
case 'new':
$result = $this->isConditionNew($product);
break;
case 'sale':
$result = $this->isConditionSale($product);
break;
default:
$method = 'isCondition' . ucfirst($label);
if (method_exists($this, $method)) {
$result = call_user_func([$this, $method], $product);
}
}
$this->cacheCondition[$productId][$label] = $result;
return $result;
}
/**
* @param int $productId
*
* @return bool
*/
public function isConditionBestseller($productId)
{
return in_array($productId, $this->getBestsellerIds());
}
/**
* @return array
*/
protected function getBestsellerIds()
{
if (empty($this->_bestsellerIds)) {
$this->_bestsellerIds = [];
$collection = $this->getReportBestsellers()->create();
$period = $this->getModuleConfig('label/bestseller_period');
if ($period) {
$collection
->addFieldToFilter(
'period',
[
'date' => true,
'from' => (new DateTime())
->modify('-1 ' . $period)
->setTime(0, 0, 0)
->getTimestamp(),
]
);
}
if (method_exists($collection, 'addStoreRestrictions')) {
$collection->addStoreRestrictions([0, $this->getStoreId()]);
}
$bestsellers = $collection
->setOrder('MIN(rating_pos)', Collection::SORT_ORDER_ASC)
->setPageSize(
max(
(int)($this->getModuleConfig('label/bestseller_count') ?: 200),
10
)
);
foreach ($bestsellers as $item) {
$this->_bestsellerIds[] = $item->getProductId();
}
}
return $this->_bestsellerIds;
}
/**
* @return CollectionFactory
*/
protected function getReportBestsellers()
{
if (!$this->reportBestsellers) {
$this->reportBestsellers = $this->_loadObject(CollectionFactory::class);
}
return $this->reportBestsellers;
}
/**
* @param Product $product
*
* @return bool
*/
public function isConditionCustom($product)
{
return (bool)$product->getData('ox_custom');
}
/**
* @param Product $product
*
* @return bool
*/
public function isConditionFeatured($product)
{
return (bool)$product->getData('ox_featured') || $product->getData('thm_featured');
}
/**
* @param Product $product
*
* @return bool
* @noinspection PhpUndefinedMethodInspection
*/
public function isConditionNew($product)
{
$productFrom = $product->getNewsFromDate();
$productTo = $product->getNewsToDate();
$productFrom = '0000-00-00 00:00:00' === $productFrom ? '' : $productFrom;
$productTo = '0000-00-00 00:00:00' === $productTo ? '' : $productTo;
if (!empty($productFrom) && !empty($productTo)) {
return ($this->getEndDate() >= $productFrom && $this->getDate() <= $productTo);
} elseif (!empty($productFrom) && empty($productTo)) {
return ($this->getEndDate() >= $productFrom);
} elseif (empty($productFrom) && !empty($productTo)) {
return ($this->getDate() <= $productTo);
}
$productType = $product->getTypeID();
switch ($productType) {
case 'bundle':
case 'grouped':
$childs = $product->getTypeInstance()->getAssociatedProducts($product);
foreach ($childs as $child) {
if ($this->isConditionNew($child)) {
return true;
}
}
break;
case 'configurable':
$childs = $product->getTypeInstance()->getUsedProducts($product);
foreach ($childs as $child) {
if ($this->isConditionNew($child)) {
return true;
}
}
break;
}
return false;
}
/**
* @return string
*/
protected function getEndDate()
{
return $this->getDate('23:59:59');
}
/**
* @param string $time
*
* @return string
*/
protected function getDate($time = '0:0:0')
{
return $this->getDateTime()->date(null, $time);
}
/**
* @return \Magento\Framework\Stdlib\DateTime\DateTime
*/
protected function getDateTime()
{
if (!$this->dateTime) {
$this->dateTime = $this->_loadObject(\Magento\Framework\Stdlib\DateTime\DateTime::class);
}
return $this->dateTime;
}
/**
* @param Product $product
*
* @return bool
*/
public function isConditionSale($product)
{
switch ($product->getTypeID()) {
case 'grouped':
$childs = $product->getTypeInstance()->getAssociatedProducts($product);
foreach ($childs as $child) {
if ($this->isConditionSale($child)) {
return true;
}
}
break;
case 'configurable':
$childs = $product->getTypeInstance()->getUsedProducts($product);
foreach ($childs as $child) {
if ($this->isConditionSale($child)) {
return true;
}
}
break;
default:
$specialPrice = $this->getProductPrice($product,'special');
$price = $this->getProductPrice($product);
if (!empty($specialPrice) && $specialPrice < $price) {
$productFrom = $product->getSpecialFromDate();
$productTo = $product->getSpecialToDate();
$productFrom = '0000-00-00 00:00:00' === $productFrom ? '' : $productFrom;
$productTo = '0000-00-00 00:00:00' === $productTo ? '' : $productTo;
if (!empty($productFrom) && !empty($productTo)) {
return ($this->getEndDate() >= $productFrom && $this->getDate() <= $productTo);
} elseif (!empty($productFrom) && empty($productTo)) {
return ($this->getEndDate() >= $productFrom);
} elseif (empty($productFrom) && !empty($productTo)) {
return ($this->getDate() <= $productTo);
}
}
}
return false;
}
/**
* @param array $style
* @param string $separatorValue
* @param string $separatorAttribute
*
* @return string
*/
public function prepareStyle(array $style, $separatorValue = ': ', $separatorAttribute = ';')
{
$style = array_filter($style);
if (empty($style)) {
return '';
}
foreach ($style as $key => &$value) {
$value = $key . $separatorValue . $value;
}
$style = implode($separatorAttribute, $style);
return $style;
}
/**
* @param string $label
* @param string $attribute
*
* @return mixed
*/
protected function getLabelAttr($label, $attribute = '')
{
return $this->getModuleConfig(sprintf('label/%s_%s', $label, $attribute));
}
/**
* @param string $text
* @param Product $product
*
* @return string|string[]
*/
protected function prepareText($text, $product)
{
$search = [];
$replace = [];
$templates = $this->templateReplace($product);
$index = 0;
if (is_array($templates) && !empty($templates)) {
foreach ($templates as $key => $value) {
$search[$index] = '{{' . $key . '}}';
$replace[$index] = $value;
$index++;
}
}
if (preg_match_all('/{{attribute:([^:}]+)}}/im', $text, $matches, PREG_SET_ORDER)) {
foreach ($matches as $matche) {
$search[$index] = $matche[0];
$replace[$index] = $product->getData($matche[1]);
$index++;
}
}
return str_replace($search, $replace, $text);
}
/**
* @param Product $product
*
* @return array
*/
public function templateReplace($product)
{
$discount = '';
$discount_percent = '';
$special_price = '';
$productType = $product->getTypeID();
switch ($productType) {
case 'grouped':
$childs = $product->getTypeInstance()->getAssociatedProducts($product);
$_discount = [];
$_discount_percent = [];
$_special_price = [];
foreach ($childs as $child) {
$specialPrice = $this->getProductPrice($child, 'special');
if (!empty($specialPrice)) {
$price = $this->getProductPrice($child);
$_special_price[] = $specialPrice;
$_discount[] = $price - $specialPrice;
$_discount_percent[] = round((1 - $specialPrice / $price) * 100);
}
}
if (1 == count($_discount)) {
$discount = array_shift($_discount);
$discount = $this->convertValute($discount);
$discount_percent = array_shift($_discount_percent) . '%';
$special_price = array_shift($_special_price);
} elseif (1 < count($_discount)) {
$minDiscount = min($_discount);
$maxDiscount = max($_discount);
$minDiscount = $this->convertValute($minDiscount);
$maxDiscount = $this->convertValute($maxDiscount);
if ($minDiscount !== $maxDiscount) {
$discount = $minDiscount . '-' . $maxDiscount;
} else {
$discount = $maxDiscount;
}
$minDiscount = min($_discount_percent);
$maxDiscount = max($_discount_percent);
if ($minDiscount !== $maxDiscount) {
$discount_percent = min($_discount_percent) . '%-' . max($_discount_percent) . '%';
} else {
$discount_percent = max($_discount_percent) . '%';
}
$special_price = min($_special_price);
}
break;
case 'configurable':
$childs = $product->getTypeInstance()->getUsedProducts($product);
$_discount = [];
$_discount_percent = [];
$_special_price = [];
foreach ($childs as $child) {
$specialPrice = $this->getProductPrice($child, 'special');
if (!empty($specialPrice)) {
$price = $this->getProductPrice($child);
$_special_price[] = $specialPrice;
$_discount[] = $price - $specialPrice;
$_discount_percent[] = round((1 - $specialPrice / $price) * 100);
}
}
if (1 == count($_discount)) {
$discount = array_shift($_discount);
$discount = $this->convertValute($discount);
$discount_percent = array_shift($_discount_percent) . '%';
$special_price = array_shift($_special_price);
} elseif (1 < count($_discount)) {
$minDiscount = min($_discount);
$maxDiscount = max($_discount);
$minDiscount = $this->convertValute($minDiscount);
$maxDiscount = $this->convertValute($maxDiscount);
if ($minDiscount !== $maxDiscount) {
$discount = $minDiscount . '-' . $maxDiscount;
} else {
$discount = $maxDiscount;
}
$minDiscount = min($_discount_percent);
$maxDiscount = max($_discount_percent);
if ($minDiscount !== $maxDiscount) {
$discount_percent = $minDiscount . '%-' . $maxDiscount . '%';
} else {
$discount_percent = $maxDiscount . '%';
}
$special_price = min($_special_price);
}
break;
case 'bundle':
$specialPrice = $this->getProductPrice($product,'special');
if (!empty($specialPrice)) {
$discount_percent = round(100 - $specialPrice) . '%';
}
break;
case 'simple':
default:
$specialPrice = $this->getProductPrice($product,'special');
if (!empty($specialPrice)) {
$special_price = $specialPrice;
$price = $this->getProductPrice($product);
$discount = $price - $specialPrice;
$discount = $this->convertValute($discount);
if ($price > 0) {
$discount_percent = round((1 - $specialPrice / $price) * 100) . '%';
}
}
}
return [
'discount' => $discount,
'discount_percent' => $discount_percent,
'special_price' => $this->convertValute($special_price),
];
}
/**
* @param \Magento\Catalog\Model\Product $product
* @param string $type
* @return float
*/
protected function getProductPrice($product, $type = '')
{
switch ($type) {
case 'special':
$price = $product->getSpecialPrice();
break;
case 'minimal':
$price = $product->getMinimalPrice();
break;
case 'final':
$price = $product->getFinalPrice();
break;
case 'calculatedFinal':
$price = $product->getCalculatedFinalPrice();
break;
default:
$price = $product->getPrice();
}
return $this->getTaxHelper()->getTaxPrice($product, $price);
}
/**
* @param string $value
*
* @return string
*/
private function convertValute($value)
{
$value = floatval($value);
$value = number_format($value, 2, '.', ',');
return $value;
}
/**
* @return bool|Cache|string
*/
public function showLabelsProduct()
{
$labelsPosition = 'ox-product-labels--' . $this->getModuleConfig('label/label_position_product');
$product = $this->getProduct();
if ($product) {
return $this->showLabels($product, $labelsPosition);
}
return '';
}
/**
* @return Product|null
*/
protected function getProduct()
{
$register = $this->_loadObject(Registry::class);
$product = $register->registry('product');
if ($product) {
return $product;
}
$product = $register->registry('current_product');
if ($product) {
return $product;
}
return null;
}
/**
* @param Product $product
* @param null $labelsPosition
*
* @return bool|Cache|string
*/
public function showLabels($product, $labelsPosition = null)
{
if (!$this->isEnabled()) {
return '';
}
$_labelsPosition = $labelsPosition;
$productId = $product->getId();
$html = $this->getCacheHtml($productId, $_labelsPosition);
if (!empty($html)) {
return $html;
}
$labels = [];
foreach (['new', 'sale', 'featured', 'bestseller', 'custom'] as $label) {
$labels[] = $this->getLabel($product, $label);
}
if (empty($labelsPosition)) {
$labelsPosition = 'ox-product-labels--' . $this->getModuleConfig('label/label_position');
}
$labelsOutput = implode('', $labels);
if ($labelsOutput) {
$labelsOutput = '<div class="ox-product-labels-wrapper ' . $labelsPosition . '">' . $labelsOutput . '</div>';
}
$this->setCacheHtml($labelsOutput, $productId, $_labelsPosition);
return $labelsOutput;
}
/**
* @param int $productId
* @param $labelsPosition
*
* @return bool|Cache|string
*/
protected function getCacheHtml($productId, $labelsPosition)
{
/** @var Cache $cache */
$cache = $this->_loadObject(Cache::class);
$cache = $cache->load($cache->getId('showLabels', [$productId, $labelsPosition, $this->getStoreId()]));
return empty($cache) ? "" : $cache;
}
/**
* @param string $html
* @param int $productId
* @param $labelsPosition
*
* @return bool
*/
protected function setCacheHtml($html, $productId, $labelsPosition)
{
/** @var Cache $cache */
$cache = $this->_loadObject(Cache::class);
return $cache->save(
$html,
$cache->getId('showLabels', [$productId, $labelsPosition, $this->getStoreId()])
);
}
/**
* @return Data
*/
protected function getTaxHelper()
{
return $this->_loadObject(Data::class);
}
/**
* @param string $date
*
* @return DateTime|false
*/
protected function convDate($date)
{
return DateTime::createFromFormat('Y-m-d H:i:s', $date);
}
}