<?php
declare(strict_types=1);
namespace scha1\scha1AdditionalProductBasketFields\Storefront\Subscriber;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Core\Checkout\Cart\Event\CheckoutOrderPlacedEvent;
use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\Struct\ArrayEntity;
use Shopware\Storefront\Page\Checkout\Cart\CheckoutCartPageLoadedEvent;
use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent;
use Shopware\Storefront\Page\Checkout\Finish\CheckoutFinishPageLoadedEvent;
use Shopware\Storefront\Page\Checkout\Offcanvas\OffcanvasCartPageLoadedEvent;
use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Contracts\Translation\TranslatorInterface;
use scha1\scha1AdditionalProductBasketFields\scha1AdditionalProductBasketFields;
/**
*
*/
class SubscriberInterface implements EventSubscriberInterface {
/**
*
*/
const PRODUCT_LINE_ITEM_TYPE = 'product';
private $session;
private $translator;
private $systemConfigService;
private $orderLineItemRepository;
/**
*
* @param Session $session
* @param TranslatorInterface $translator
* @param SystemConfigService $systemConfigService
* @param EntityRepositoryInterface $orderLineItemRepository
*/
public function __construct( Session $session, TranslatorInterface $translator, SystemConfigService $systemConfigService, EntityRepositoryInterface $orderLineItemRepository ) {
$this->session = $session;
$this->translator = $translator;
$this->systemConfigService = $systemConfigService;
$this->orderLineItemRepository = $orderLineItemRepository;
}
/**
*
* @return array
*/
public static function getSubscribedEvents(): array {
return [ ProductPageLoadedEvent::class => 'onProductPageLoaded',
OffcanvasCartPageLoadedEvent::class => 'onOffcanvasCartPageLoaded',
CheckoutCartPageLoadedEvent::class => 'onCheckoutCartPageLoaded',
CheckoutConfirmPageLoadedEvent::class => 'onCheckoutConfirmPageLoaded',
CheckoutFinishPageLoadedEvent::class => 'onCheckoutFinishPageLoaded',
CheckoutOrderPlacedEvent::class => 'onCheckoutOrderPlaced',
];
}
/**
*
* provide on the product detail page
* @param ProductPageLoadedEvent $event
* @return SalesChannelProductEntity
*/
public function onProductPageLoaded(ProductPageLoadedEvent $event): SalesChannelProductEntity {
$showOnProductDetailPage = $this->systemConfigService->get('scha1AdditionalProductBasketFields.config.showOnProductDetailPage');
$product = $event->getPage()->getProduct();
if ($showOnProductDetailPage == 'yes') {
for ($i = 1; $i <= scha1AdditionalProductBasketFields::MAX_FIELD; ++$i) {
$productExtensionData['value'] = $this->getAdditionalProductBasketFieldFromSession($product->getProductNumber(), 'value', $i);
$productExtension = $this->createArrayEntity($productExtensionData);
$product->addExtension('additionalproductbasketfields' . $i, $productExtension);
}
}
$additionalproductbasketfieldsCount['value'] = scha1AdditionalProductBasketFields::MAX_FIELD;
$additionalproductbasketfieldsCountValue = $this->createArrayEntity($additionalproductbasketfieldsCount);
$product->addExtension('additionalproductbasketfieldsCountValue', $additionalproductbasketfieldsCountValue);
return $product;
}
/**
*
* provide on the offcanvas cart page
* @param OffcanvasCartPageLoadedEvent $event
* @return array
*/
public function onOffcanvasCartPageLoaded(OffcanvasCartPageLoadedEvent $event): array {
return $this->getLineItemsAdditionalProductBasketField($event);
}
/**
*
* provide on the checkout cart page
* @param CheckoutCartPageLoadedEvent $event
* @return array
*/
public function onCheckoutCartPageLoaded(CheckoutCartPageLoadedEvent $event): array {
return $this->getLineItemsAdditionalProductBasketField($event);
}
/**
*
* provide on the checkout confirm page
* @param CheckoutConfirmPageLoadedEvent $event
* @return array
*/
public function onCheckoutConfirmPageLoaded(CheckoutConfirmPageLoadedEvent $event): array {
return $this->getLineItemsAdditionalProductBasketField($event);
}
/**
*
* save in the order line item custom fields after a successful order
* @param CheckoutFinishPageLoadedEvent $event
*/
public function onCheckoutFinishPageLoaded(CheckoutFinishPageLoadedEvent $event): void {
$lineItems = $event->getPage()->getOrder()->getLineItems();
$this->saveAdditionalProductBasketFieldsInLineItemCustomFields($event, $lineItems, true);
$event->getPage()->assign([ 'additionalproductbasketfieldsCountValue' => scha1AdditionalProductBasketFields::MAX_FIELD ]);
}
/**
*
* save in the order line item custom fields when order is placed
* @param CheckoutOrderPlacedEvent $event
*/
public function onCheckoutOrderPlaced(CheckoutOrderPlacedEvent $event): void {
$lineItems = $event->getOrder()->getLineItems();
$this->saveAdditionalProductBasketFieldsInLineItemCustomFields($event, $lineItems, false);
}
/**
*
* save in the order line item custom fields
* @param type $event
* @param type $lineItems
* @param type $isCheckoutFinishPage
*/
protected function saveAdditionalProductBasketFieldsInLineItemCustomFields($event, $lineItems, $isCheckoutFinishPage): void {
foreach ($lineItems as $lineItem) {
if ($lineItem->getType() === self::PRODUCT_LINE_ITEM_TYPE) {
$this->getProductBasketField($event, $lineItem, $isCheckoutFinishPage);
}
}
}
/**
*
* @param type $event
* @param type $lineItem
* @param type $isCheckoutFinishPage
*/
private function getProductBasketField($event, $lineItem, $isCheckoutFinishPage) {
$productNumber = $lineItem->getPayload()['productNumber'] ?? null;
if ($lineItem->getType() === self::PRODUCT_LINE_ITEM_TYPE && $productNumber) {
$additionalproductbasketfieldsValueArray = [];
$additionalproductbasketfieldsHasValue = 0;
for ($i = 1; $i <= scha1AdditionalProductBasketFields::MAX_FIELD; ++$i) {
$additionalproductbasketfieldsValue = $this->getAdditionalProductBasketFieldFromSession($productNumber, 'value', $i);
$additionalproductbasketfieldsLabel = $this->getAdditionalProductBasketFieldFromSession($productNumber, 'label', $i);
$additionalproductbasketfieldsPlaceholder = $this->getAdditionalProductBasketFieldFromSession($productNumber, 'placeholder', $i);
$additionalproductbasketfieldsFieldType = $this->getAdditionalProductBasketFieldFromSession($productNumber, 'fieldtype', $i);
if ($additionalproductbasketfieldsValue ) {
$additionalproductbasketfieldsValueArray[$i]['value'] = ($additionalproductbasketfieldsFieldType == 'boolean' ? ($additionalproductbasketfieldsValue == 1 ? $this->translator->trans('scha1.additionalproductbasketfields.selectedValue') : $this->translator->trans('scha1.additionalproductbasketfields.unselectedValue')) : $additionalproductbasketfieldsValue);
$additionalproductbasketfieldsValueArray[$i]['label'] = $additionalproductbasketfieldsLabel;
$additionalproductbasketfieldsValueArray[$i]['placeholder'] = $additionalproductbasketfieldsPlaceholder;
$additionalproductbasketfieldsValueArray[$i]['fieldtype'] = $additionalproductbasketfieldsFieldType;
$additionalproductbasketfieldsHasValue = $additionalproductbasketfieldsHasValue + 1;
}
}
$this->getCustomFields($event, $lineItem, $isCheckoutFinishPage, $productNumber, $additionalproductbasketfieldsValueArray, $additionalproductbasketfieldsHasValue);
}
}
/**
*
* @param type $event
* @param type $lineItem
* @param type $isCheckoutFinishPage
* @param type $productNumber
* @param type $additionalproductbasketfieldsValueArray
* @param type $additionalproductbasketfieldsHasValue
*/
private function getCustomFields($event, $lineItem, $isCheckoutFinishPage, $productNumber, $additionalproductbasketfieldsValueArray, $additionalproductbasketfieldsHasValue) {
$additionalproductbasketfieldsValueCustomFieldArray = [];
$additionalproductbasketfieldsValueTypeArray = array('value', 'label', 'placeholder', 'fieldtype');
for ($i = 1; $i <= scha1AdditionalProductBasketFields::MAX_FIELD; ++$i) {
foreach ($additionalproductbasketfieldsValueTypeArray as $basketField) {
if (isset($additionalproductbasketfieldsValueArray[$i][$basketField])) {
$additionalproductbasketfieldsValueCustomFieldArray['scha1additionalproductbasketfields' . $i . '_' . $basketField] = $additionalproductbasketfieldsValueArray[$i][$basketField];
}
}
}
$lineItem->setCustomFields($additionalproductbasketfieldsValueCustomFieldArray);
if ($isCheckoutFinishPage) {
for ($i = 1; $i <= scha1AdditionalProductBasketFields::MAX_FIELD; ++$i) {
$this->removeAdditionalProductBasketFieldFromSession($productNumber, $i);
}
}
if ($additionalproductbasketfieldsHasValue > 0) {
$this->orderLineItemRepository->upsert([ [ 'id' => $lineItem->getId(), 'customFields' => $lineItem->getCustomFields(),],], $event->getContext() ?? Context::createDefaultContext());
}
}
/**
*
* get for each line item
* @param type $event
* @return array
*/
private function getLineItemsAdditionalProductBasketField($event): array {
$lineItems = $event->getPage()->getCart()->getLineItems()->getElements();
foreach ($lineItems as $lineItem) {
if ($lineItem->getType() === self::PRODUCT_LINE_ITEM_TYPE) {
$this->getLineItemValue($lineItem);
}
}
return $lineItems;
}
/**
* get value in line item
* @param type $lineItem
*/
private function getLineItemValue($lineItem) {
$productNumber = $lineItem->getPayloadValue('productNumber') ?? null;
if ($lineItem->getType() === self::PRODUCT_LINE_ITEM_TYPE && $productNumber) {
for ($i = 1; $i <= scha1AdditionalProductBasketFields::MAX_FIELD; ++$i) {
$productExtensionData['value'] = $this->getAdditionalProductBasketFieldFromSession($productNumber, 'value', $i);
$lineItemExtension = $this->createArrayEntity($productExtensionData);
$lineItem->addExtension('lineItemadditionalproductbasketfield' . $i, $lineItemExtension);
}
$lineItemadditionalproductbasketfieldCount['value'] = scha1AdditionalProductBasketFields::MAX_FIELD;
$lineItemadditionalproductbasketfieldCountValue = $this->createArrayEntity($lineItemadditionalproductbasketfieldCount);
$lineItem->addExtension('lineItemadditionalproductbasketfieldCountValue', $lineItemadditionalproductbasketfieldCountValue);
}
}
/**
*
* create an ArrayEntity with the given data
* @param type $extensionData
* @return ArrayEntity
*/
private function createArrayEntity($extensionData): ArrayEntity {
return new ArrayEntity($extensionData);
}
/**
*
* @param type $productNumber
* @param type $type
* @param type $count
* @return string
*/
private function getAdditionalProductBasketFieldFromSession($productNumber, $type, $count): string {
$sessionAdditionalProductBasketField = '';
$additionalproductbasketfields = sprintf('scha1additionalproductbasketfields%d_%s', $count, $productNumber);
if ($this->session->has($additionalproductbasketfields)) {
if (in_array($type, ['value', 'label', 'placeholder', 'fieldtype'])) {
$sessionAdditionalProductBasketField = $this->session->get($additionalproductbasketfields)['scha1additionalproductbasketfields' . $type];
}
if ($type == 'value' && $sessionAdditionalProductBasketField == null) {
$sessionAdditionalProductBasketField = '';
}
}
return $sessionAdditionalProductBasketField;
}
/**
*
* removes from the session based on the product number
* @param type $productNumber
* @param type $count
*/
private function removeAdditionalProductBasketFieldFromSession($productNumber, $count): void {
$this->session->remove('scha1additionalproductbasketfields' . $count . '_' . $productNumber);
}
}