<?php declare(strict_types=1);
namespace MindsShoppingCartGoals\Subscriber;
use MindsShoppingCartGoals\Main\SCGHelper;
use MindsShoppingCartGoals\Main\structs\SCGData;
use MindsShoppingCartGoals\Main\structs\SCGBoolean;
use MindsShoppingCartGoals\Main\structs\SCGItem;
use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
use Shopware\Core\Framework\Adapter\Translation\Translator;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Storefront\Theme\Event\ThemeCompilerEnrichScssVariablesEvent;
use Shopware\Storefront\Page\Checkout\Offcanvas\OffcanvasCartPageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Storefront\Page\Checkout\Cart\CheckoutCartPageLoadedEvent;
use Shopware\Storefront\Page\Checkout\Register\CheckoutRegisterPageLoadedEvent;
use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
use Shopware\Storefront\Page\Product\ProductPageLoader;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\DevOps\Environment\EnvironmentHelper;
use Shopware\Core\Framework\Struct\ArrayEntity;
/**
* Class Frontend
*
* @phpstan-ignore-next-line */
class Frontend implements EventSubscriberInterface {
protected SystemConfigService $systemConfig;
private EntityRepository $productRepository;
private EntityRepository $freeProductRepository;
private Translator $translator;
private CartService $cartService;
// add the `SystemConfigService` to your constructor
public function __construct(SystemConfigService $systemConfig, EntityRepository $productRepository, EntityRepository $freeProductRepository, Translator $translator, CartService $cartService) {
$this->systemConfig = $systemConfig;
$this->productRepository = $productRepository;
$this->freeProductRepository = $freeProductRepository;
$this->translator = $translator;
$this->cartService = $cartService;
}
public static function getSubscribedEvents(): array {
return [
ThemeCompilerEnrichScssVariablesEvent::class => 'onAddVariables',
CheckoutCartPageLoadedEvent::class => 'onCartLoadedEvent',
OffcanvasCartPageLoadedEvent::class => 'onOffcanvasCartLoadedEvent',
CheckoutRegisterPageLoadedEvent::class => 'onCheckoutRegisterPageLoadedEvent',
ProductPageLoadedEvent::class => 'onProductPageLoadedEvent'
];
}
public function onAddVariables(ThemeCompilerEnrichScssVariablesEvent $event): void {
$databaseUrl = EnvironmentHelper::getVariable('DATABASE_URL', getenv('DATABASE_URL'));
if (!$databaseUrl || $databaseUrl === 'mysql://_placeholder.test') {
// deployment server without database
return;
}
$configSCGBaseColor = $this->systemConfig->get('MindsShoppingCartGoals.config.scgBaseColor', $event->getSalesChannelId());
$configSCGBadgeColor = $this->systemConfig->get('MindsShoppingCartGoals.config.scgBadgeColor', $event->getSalesChannelId());
$configSCGProgressColor = $this->systemConfig->get('MindsShoppingCartGoals.config.scgProgressColor', $event->getSalesChannelId());
$configSCGProgressCircleAsRectangle = $this->systemConfig->get('MindsShoppingCartGoals.config.scgRectangleProgressPoints', $event->getSalesChannelId());
$configSCGBorderRadius = $this->systemConfig->get('MindsShoppingCartGoals.config.scgBaseBorderRadius', $event->getSalesChannelId());
if ($configSCGBaseColor) {
$event->addVariable('scg-base-color', $configSCGBaseColor);
}
if ($configSCGProgressColor) {
$event->addVariable('scg-progress-color', $configSCGProgressColor);
}
if ($configSCGProgressCircleAsRectangle) {
$event->addVariable('scg-progress-circle-as-rectangle', $configSCGProgressCircleAsRectangle ? '1' : '0');
}
if ($configSCGBadgeColor) {
$event->addVariable('scg-badge-color', $configSCGBadgeColor);
}
if ($configSCGBorderRadius) {
$event->addVariable('scg-border-radius', strval($configSCGBorderRadius) . '%');
}
}
private function loadSCGData(&$event) {
$scgData = new SCGData();
$positionPrice = SCGHelper::getPositionPrice($event->getPage()->getCart(), $this->systemConfig, $event->getContext());
$addOnlyHighestFreeProduct = $this->systemConfig->get('MindsShoppingCartGoals.config.scgAddOnlyHighestFreeProduct', $event->getContext()->getSource()->getSalesChannelId());
$startsAtZero = $this->systemConfig->get('MindsShoppingCartGoals.config.scgStartsAtZero', $event->getContext()->getSource()->getSalesChannelId());
$items = SCGHelper::getSCGItems($this->systemConfig, $this->productRepository, $this->translator, $event->getContext(), $positionPrice, $this->freeProductRepository);
// Calculate the Difference to the next possible position when exists
$diffToNextPosition = 0;
$nextPositionName = "";
foreach ($items as $itemKey=>&$item) {
if (!empty($item->getRuleId())) {
if (!in_array($item->getRuleId(), $event->getSalesChannelContext()->getRuleIds())) {
unset($items[$itemKey]);
}
}
}
$index = 0;
foreach ($items as $itemKey=>&$item) {
if (!$item->isCartValueReached()) {
$diffToNextPosition = $item->getCartValue() - $positionPrice;
$nextPositionName = $item->getName();
break;
} else {
$index++;
}
}
if ($event->getPage()->getCart()) {
foreach ($items as $itemKey=>&$item) {
foreach ($event->getPage()->getCart()->getLineItems() as $lineItem) {
if (!empty($lineItem->getExtension('scgItem'))) {
$item->updateIsInCart($lineItem->getReferencedId());
}
}
}
}
$items = array_filter($items, function($var) {
if (!$var->isAddToShoppingCart()) return true;
if ($var->hasVariantItems()) {
if ($var->hasVariantItemsWithStock()) {
return true;
} else {
return false;
}
} else {
if (!$var->getCurrentStock() >= $var->getCount()) {
return false;
}
}
if ($var->isRemoved()) return false;
return true;
});
$freeItems = array_filter($items, function($var) {
return $var->isCartValueReached();
});
$scgData->setFreeItems($addOnlyHighestFreeProduct ? [ end($freeItems) ] : $freeItems);
$displayAddFreeItems = false;
foreach ($scgData->getFreeItems() as $itemKey=>&$item) {
if (!empty($item)) {
if ($item->isActive() and $item->hasVariantItems() and $item->isCartValueReached() and $item->isAddToShoppingCart() and $item->hasVariantItemsWithStock()) {
$displayAddFreeItems = true;
}
}
}
$scgData->setItems($items);
$scgData->setDisplayAddFreeProducts($displayAddFreeItems);
$scgData->setDiffToNextPosition($diffToNextPosition);
$scgData->setNextPositionName($nextPositionName);
$scgData->setItemCount(count($items));
$scgData->setAddOnlyHighestFreeProduct($addOnlyHighestFreeProduct);
$scgData->setStartsAtZero($startsAtZero);
$scgData->setHighestProductIndex($index);
$event->getPage()->addExtension('scg', $scgData);
}
public function onCartLoadedEvent(CheckoutCartPageLoadedEvent $event) {
$this->loadSCGData($event);
}
public function onOffcanvasCartLoadedEvent(OffcanvasCartPageLoadedEvent $event) {
$this->loadSCGData($event);
}
public function onCheckoutRegisterPageLoadedEvent(CheckoutRegisterPageLoadedEvent $event) {
$this->loadSCGData($event);
$scgShowProgressOnRegisterSite = $this->systemConfig->get('MindsShoppingCartGoals.config.scgShowProgressOnRegisterSite', $event->getSalesChannelContext()->getSalesChannelId());
if (empty($scgShowProgressOnRegisterSite)) {
$scgShowProgressOnRegisterSite = false;
}
$event->getPage()->addExtension('scgShow', new SCGBoolean($scgShowProgressOnRegisterSite));
}
public function onProductPageLoadedEvent(ProductPageLoadedEvent $event) {
$cri = new Criteria();
$cri->addFilter(new EqualsFilter('active', true));
$cri->addFilter(new EqualsFilter('preventSale', true));
$cri->addFilter(new EqualsFilter('productId', $event->getPage()->getProduct()->getId()));
if (!empty($this->freeProductRepository->search($cri, $event->getContext())->first())) {
$event->getPage()->addExtension('m28_scg_prevent_sale', new SCGBoolean(true));
}
$showNextPositionNameOnProductPage = $this->systemConfig->get('MindsShoppingCartGoals.config.scgShowNextPositionNameOnProductPage', $event->getSalesChannelContext()->getSalesChannelId());
if ($showNextPositionNameOnProductPage) {
$cart = $this->cartService->getCart($event->getSalesChannelContext()->getToken(), $event->getSalesChannelContext());
$positionPrice = SCGHelper::getPositionPrice($cart, $this->systemConfig, $event->getContext());
$items = SCGHelper::getSCGItems($this->systemConfig, $this->productRepository, $this->translator, $event->getContext(), $positionPrice, $this->freeProductRepository);
// Calculate the Difference to the next possible position when exists
$diffToNextPosition = 0;
$nextPositionName = "";
foreach ($items as $itemKey=>&$item) {
if (!empty($item->getRuleId())) {
if (!in_array($item->getRuleId(), $event->getSalesChannelContext()->getRuleIds())) {
unset($items[$itemKey]);
}
}
}
$index = 0;
foreach ($items as $itemKey=>&$item) {
if (!$item->isCartValueReached()) {
$diffToNextPosition = $item->getCartValue() - $positionPrice;
$nextPositionName = $item->getName();
break;
} else {
$index++;
}
}
$event->getPage()->addExtension('m28_scg_display_next_position', new ArrayEntity([ 'diffToNextPosition' => $diffToNextPosition, 'nextPositionName' => $nextPositionName ]));
}
}
}