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 '' . $text . ''; } 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 = '
' . $labelsOutput . '
'; } $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); } }