<?php
declare(strict_types=1);
namespace CioProductCustomerInputs\Storefront\Subscriber;
use CioProductCustomerInputs\CioProductCustomerInputs;
use CioProductCustomerInputs\Service\SessionService;
use Shopware\Core\Checkout\Cart\Event\AfterLineItemAddedEvent;
use Shopware\Core\Checkout\Cart\Event\CheckoutOrderPlacedEvent;
use Shopware\Core\Checkout\Cart\LineItem\LineItem;
use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemEntity;
use Shopware\Core\Content\Product\ProductEntity;
use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Storefront\Page\Account\Order\AccountOrderPageLoadedEvent;
use Shopware\Storefront\Page\Account\Overview\AccountOverviewPageLoadedEvent;
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 Swag\CmsExtensions\Storefront\Pagelet\Quickview\QuickviewPageletLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Contracts\Translation\TranslatorInterface;
class FrontendSubscriber implements EventSubscriberInterface
{
/**
* @var TranslatorInterface
*/
private TranslatorInterface $translator;
/**
* @var SystemConfigService
*/
private SystemConfigService $systemConfigService;
/**
* @var EntityRepositoryInterface
*/
private EntityRepositoryInterface $orderLineItemRepository;
/**
* @var SessionService
*/
private SessionService $sessionService;
private CartService $cartService;
public function __construct(
TranslatorInterface $translator,
SystemConfigService $systemConfigService,
EntityRepositoryInterface $orderLineItemRepository,
SessionService $sessionService,
CartService $cartService
)
{
$this->translator = $translator;
$this->systemConfigService = $systemConfigService;
$this->orderLineItemRepository = $orderLineItemRepository;
$this->sessionService = $sessionService;
$this->cartService = $cartService;
}
public static function getSubscribedEvents(): array
{
if (class_exists('\\Swag\\CmsExtensions\\Storefront\\Pagelet\\Quickview\\QuickviewPageletLoadedEvent')) {
return [
ProductPageLoadedEvent::class => 'onProductPageLoaded',
CheckoutCartPageLoadedEvent::class => 'onCheckoutCartPageLoaded',
CheckoutConfirmPageLoadedEvent::class => 'onCheckoutConfirmPageLoaded',
CheckoutFinishPageLoadedEvent::class => 'onCheckoutFinishPageLoaded',
CheckoutOrderPlacedEvent::class => 'onCheckoutOrderPlaced',
AccountOrderPageLoadedEvent::class => 'onAccountOrderPageLoaded',
AccountOverviewPageLoadedEvent::class => 'onAccountOverviewPageLoaded',
QuickviewPageletLoadedEvent::class => 'onQuickviewPageletLoaded',
OffcanvasCartPageLoadedEvent::class => 'onOffcanvasCartPageLoadedEvent',
AfterLineItemAddedEvent::class => 'onLineItemAdded'
];
} else {
return [
ProductPageLoadedEvent::class => 'onProductPageLoaded',
CheckoutCartPageLoadedEvent::class => 'onCheckoutCartPageLoaded',
CheckoutConfirmPageLoadedEvent::class => 'onCheckoutConfirmPageLoaded',
CheckoutFinishPageLoadedEvent::class => 'onCheckoutFinishPageLoaded',
CheckoutOrderPlacedEvent::class => 'onCheckoutOrderPlaced',
AccountOrderPageLoadedEvent::class => 'onAccountOrderPageLoaded',
AccountOverviewPageLoadedEvent::class => 'onAccountOverviewPageLoaded',
OffcanvasCartPageLoadedEvent::class => 'onOffcanvasCartPageLoadedEvent',
AfterLineItemAddedEvent::class => 'onLineItemAdded'
];
}
}
/**
* provide the customer input on the product detail page
*/
public function onProductPageLoaded(ProductPageLoadedEvent $event): SalesChannelProductEntity
{
$customerInputShowOnProductDetailPage = $this->systemConfigService->get('CioProductCustomerInputs.config.customerInputShowOnProductDetailPage');
$product = $event->getPage()->getProduct();
$lineItemId = $event->getRequest()->get('lineItemId');
if (!is_null($lineItemId)) {
if (!$this->cartService->getCart($event->getSalesChannelContext()->getToken(), $event->getSalesChannelContext())->has($lineItemId)) {
$request = $event->getRequest();
$response = new RedirectResponse($request->getRequestUri());
$response->send();
}
}
if ($customerInputShowOnProductDetailPage == 'yes') {
if ($product->getCustomFields() && is_array($product->getCustomFields()) && isset($product->getCustomFields()['cio_customer_input_count_rows'])) {
for ($row = 1; $row <= $product->getCustomFields()['cio_customer_input_count_rows']; ++$row) {
for ($i = 1; $i <= CioProductCustomerInputs::CUSTOMER_INPUT_COUNT; ++$i) {
$productExtensionData['value'] = $this->sessionService->getCustomerInputFromSession($product->getProductNumber(), 'value', $row, $i, $lineItemId);
$productExtensionData['checkboxValue'] = $this->sessionService->getCustomerInputFromSession($product->getProductNumber(), 'checkbox_value', $row, $i, $lineItemId);
$productExtension = $this->sessionService->createArrayEntity($productExtensionData);
$product->addExtension('cioCustomerInput' . $row . $i, $productExtension);
}
}
}
}
$cioCustomerInputCount['value'] = CioProductCustomerInputs::CUSTOMER_INPUT_COUNT;
$cioCustomerInputCountValue = $this->sessionService->createArrayEntity($cioCustomerInputCount);
$product->addExtension('cioCustomerInputCountValue', $cioCustomerInputCountValue);
return $product;
}
/**
* provide the customer input on the checkout cart page
*/
public function onCheckoutCartPageLoaded(CheckoutCartPageLoadedEvent $event): array
{
return $this->getLineItemsCustomerInput($event->getPage()->getCart()->getLineItems()->getElements());
}
/**
* provide the customer input on the off-canvas cart page
*/
public function onOffcanvasCartPageLoadedEvent(OffcanvasCartPageLoadedEvent $event): array
{
return $this->getLineItemsCustomerInput($event->getPage()->getCart()->getLineItems()->getElements());
}
/**
* provide the customer input on the checkout confirm page
*/
public function onCheckoutConfirmPageLoaded(CheckoutConfirmPageLoadedEvent $event): array
{
return $this->getLineItemsCustomerInput($event->getPage()->getCart()->getLineItems()->getElements());
}
/**
* save the customer inputs in the order line item custom fields after a successful order
*/
public function onCheckoutFinishPageLoaded(CheckoutFinishPageLoadedEvent $event): void
{
$this->getLineItemsCustomerInput($event->getPage()->getOrder()->getLineItems()->getElements());
$event->getPage()->assign([
'cioCustomerInputCountValue' => CioProductCustomerInputs::CUSTOMER_INPUT_COUNT,
]);
}
/**
* save the customer inputs in the order line item custom fields when order is placed
*/
public function onCheckoutOrderPlaced(CheckoutOrderPlacedEvent $event): void
{
$lineItems = $event->getOrder()->getLineItems();
$this->saveCustomerInputsInLineItemCustomFields($event, $lineItems, false);
}
/**
* assign the customer input count value to the account order page
*/
public function onAccountOrderPageLoaded(AccountOrderPageLoadedEvent $event): void
{
$event->getPage()->assign([
'cioCustomerInputCountValue' => CioProductCustomerInputs::CUSTOMER_INPUT_COUNT,
]);
}
/**
* assign the customer input count value to the account overview page
*/
public function onAccountOverviewPageLoaded(AccountOverviewPageLoadedEvent $event): void
{
$event->getPage()->assign([
'cioCustomerInputCountValue' => CioProductCustomerInputs::CUSTOMER_INPUT_COUNT,
]);
}
/**
* provide the customer input on the quickview
* @param QuickviewPageletLoadedEvent
* @return ProductEntity
*/
public function onQuickviewPageletLoaded($event): ProductEntity
{
$customerInputShowOnProductDetailPage = $this->systemConfigService->get('CioProductCustomerInputs.config.customerInputShowOnProductDetailPage');
$product = $event->getPagelet()->getProduct();
if ($customerInputShowOnProductDetailPage == 'yes') {
for ($row = 1; $row <= $product->getCustomFields()['cio_customer_input_count_rows']; ++$row) {
for ($i = 1; $i <= CioProductCustomerInputs::CUSTOMER_INPUT_COUNT; ++$i) {
$productExtensionData['value'] = $this->sessionService->getCustomerInputFromSession($product->getProductNumber(), 'value', $row, $i);
$productExtensionData['checkboxValue'] = $this->sessionService->getCustomerInputFromSession($product->getProductNumber(), 'checkbox_value', $row, $i);
$productExtension = $this->sessionService->createArrayEntity($productExtensionData);
$product->addExtension('cioCustomerInput' . $row . $i, $productExtension);
}
}
}
$cioCustomerInputCount['value'] = CioProductCustomerInputs::CUSTOMER_INPUT_COUNT;
$cioCustomerInputCountValue = $this->sessionService->createArrayEntity($cioCustomerInputCount);
$product->addExtension('cioCustomerInputCountValue', $cioCustomerInputCountValue);
return $product;
}
public function onLineItemAdded(AfterLineItemAddedEvent $event)
{
foreach ($event->getLineItems() as $lineItem) {
$this->sessionService->cloneSessionToLineItemSession($lineItem);
}
}
/**
* save the customer inputs in the order line item custom fields
*/
protected function saveCustomerInputsInLineItemCustomFields($event, $lineItems, $isCheckoutFinishPage): void
{
$customerInputTransferUnselectedCheckboxFieldsAsValue = $this->systemConfigService->get('CioProductCustomerInputs.config.customerInputTransferUnselectedCheckboxFieldsAsValue');
foreach ($lineItems as $item) {
/** @var OrderLineItemEntity $item */
if ($item->getType() !== LineItem::PROMOTION_LINE_ITEM_TYPE) {
$productNumber = $item->getPayload()['productNumber'];
$cioCustomerInputValueArray = [];
$cioCustomerInputHasValue = 0;
if (isset($item->getPayload()['customFields']['cio_customer_input_count_rows'])) {
for ($row = 1; $row <= $item->getPayload()['customFields']['cio_customer_input_count_rows']; ++$row) {
for ($i = 1; $i <= CioProductCustomerInputs::CUSTOMER_INPUT_COUNT; ++$i) {
$cioCustomerInputValue = $this->sessionService->getCustomerInputFromSession($productNumber, 'value', $row, $i, $item->getIdentifier());
$cioCustomerInputCheckboxValue = $this->sessionService->getCustomerInputFromSession($productNumber, 'checkbox_value', $row, $i, $item->getIdentifier());
$cioCustomerInputLabel = $this->sessionService->getCustomerInputFromSession($productNumber, 'label', $row, $i, $item->getIdentifier());
$cioCustomerInputPlaceholder = $this->sessionService->getCustomerInputFromSession($productNumber, 'placeholder', $row, $i, $item->getIdentifier());
$cioCustomerInputFieldType = $this->sessionService->getCustomerInputFromSession($productNumber, 'fieldtype', $row, $i, $item->getIdentifier());
if ($cioCustomerInputValue || (($customerInputTransferUnselectedCheckboxFieldsAsValue) && ($cioCustomerInputFieldType == 'boolean') && ($cioCustomerInputValue == 0)) || ($cioCustomerInputFieldType == 'input' && $cioCustomerInputValue == '0')) {
$cioCustomerInputValueArray[$row][$i]['value'] = ($cioCustomerInputFieldType == 'boolean' ? ($cioCustomerInputValue == 1 ? $this->translator->trans('cio.customerInput.selectedValue') : $this->translator->trans('cio.customerInput.unselectedValue')) : $cioCustomerInputValue);
$cioCustomerInputValueArray[$row][$i]['checkbox_value'] = $cioCustomerInputCheckboxValue;
$cioCustomerInputValueArray[$row][$i]['label'] = $cioCustomerInputLabel;
$cioCustomerInputValueArray[$row][$i]['placeholder'] = $cioCustomerInputPlaceholder;
$cioCustomerInputValueArray[$row][$i]['fieldtype'] = $cioCustomerInputFieldType;
$cioCustomerInputHasValue = $cioCustomerInputHasValue + 1;
} elseif ($customerInputTransferUnselectedCheckboxFieldsAsValue) {
if ($item->getCustomFields() and (!isset($item->getCustomFields()['cio_customer_input_' . $i . '_value']))) {
$productCustomFields = $item->getPayload()['customFields'];
if (isset($productCustomFields['cio_customer_input_' . $i . '_active'])) {
if ($productCustomFields['cio_customer_input_' . $i . '_active'] && $productCustomFields['cio_customer_input_' . $i . '_fieldtype'] == 'boolean') {
$cioCustomerInputValue = $this->sessionService->getCustomerInputFromSession($productNumber, 'value', $row, $i, $item->getId());
if ($cioCustomerInputValue == '') {
$cioCustomerInputValue = $this->translator->trans('cio.customerInput.unselectedValue');
$cioCustomerInputLabel = (isset($productCustomFields['cio_customer_input_' . $i . '_title']) ? ($productCustomFields['cio_customer_input_' . $i . '_title'] !== '' ? $productCustomFields['cio_customer_input_' . $i . '_title'] : $this->translator->trans('cio.customerInput.titleLabel')) : $this->translator->trans('cio.customerInput.titleLabel'));
$cioCustomerInputPlaceholder = (isset($productCustomFields['cio_customer_input_' . $i . '_placeholder']) ? ($productCustomFields['cio_customer_input_' . $i . '_placeholder'] !== '' ? $productCustomFields['cio_customer_input_' . $i . '_placeholder'] : $this->translator->trans('cio.customerInput.placeholderLabel')) : $this->translator->trans('cio.customerInput.placeholderLabel'));
$cioCustomerInputFieldType = $productCustomFields['cio_customer_input_' . $i . '_fieldtype'];
$cioCustomerInputValueArray[$row][$i]['value'] = $cioCustomerInputValue;
$cioCustomerInputValueArray[$row][$i]['label'] = $cioCustomerInputLabel;
$cioCustomerInputValueArray[$row][$i]['placeholder'] = $cioCustomerInputPlaceholder;
$cioCustomerInputValueArray[$row][$i]['fieldtype'] = $cioCustomerInputFieldType;
$cioCustomerInputHasValue = $cioCustomerInputHasValue + 1;
}
}
}
}
}
}
}
}
$cioCustomerInputValueCustomFieldArray = [];
$cioCustomerInputValueTypeArray = array('value', 'checkbox_value', 'label', 'placeholder', 'fieldtype');
if (isset($item->getPayload()['customFields']['cio_customer_input_count_rows'])) {
for ($row = 1; $row <= $item->getPayload()['customFields']['cio_customer_input_count_rows']; ++$row) {
for ($i = 1; $i <= CioProductCustomerInputs::CUSTOMER_INPUT_COUNT; ++$i) {
foreach ($cioCustomerInputValueTypeArray as $ta) {
if (isset($cioCustomerInputValueArray[$row][$i][$ta])) {
$cioCustomerInputValueCustomFieldArray['cio_customer_input_' . $row . '_' . $i . '_' . $ta] = $cioCustomerInputValueArray[$row][$i][$ta];
}
}
}
}
}
$item->setCustomFields(
$cioCustomerInputValueCustomFieldArray
);
if ($isCheckoutFinishPage) {
for ($row = 1; $row <= $item->getPayload()['customFields']['cio_customer_input_count_rows']; ++$row) {
for ($i = 1; $i <= CioProductCustomerInputs::CUSTOMER_INPUT_COUNT; ++$i) {
$this->sessionService->removeCustomerInputFromSession($productNumber, $row, $i, $item->getId());
}
}
}
if ($cioCustomerInputHasValue > 0) {
$this->orderLineItemRepository->upsert(
[
[
'id' => $item->getId(),
'customFields' => $item->getCustomFields(),
],
],
$event->getContext() ?? Context::createDefaultContext()
);
}
}
}
}
/**
* get the customer input for each line item
*/
private function getLineItemsCustomerInput($lineItems): array
{
foreach ($lineItems as $lineItem) {
$this->sessionService->addLineItemsCustomerInput($lineItem);
}
return $lineItems;
}
}