custom/static-plugins/CioProductCustomerInputs/src/Storefront/Subscriber/FrontendSubscriber.php line 307

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace CioProductCustomerInputs\Storefront\Subscriber;
  4. use CioProductCustomerInputs\CioProductCustomerInputs;
  5. use CioProductCustomerInputs\Service\SessionService;
  6. use Shopware\Core\Checkout\Cart\Error\IncompleteLineItemError;
  7. use Shopware\Core\Checkout\Cart\Event\AfterLineItemAddedEvent;
  8. use Shopware\Core\Checkout\Cart\Event\CheckoutOrderPlacedEvent;
  9. use Shopware\Core\Checkout\Cart\LineItem\LineItem;
  10. use Shopware\Core\Checkout\Cart\Order\OrderConverter;
  11. use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
  12. use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemEntity;
  13. use Shopware\Core\Content\Product\ProductEntity;
  14. use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
  15. use Shopware\Core\Framework\Context;
  16. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  17. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  18. use Shopware\Core\Framework\Struct\ArrayEntity;
  19. use Shopware\Core\System\SalesChannel\Context\AbstractSalesChannelContextFactory;
  20. use Shopware\Core\System\SalesChannel\Context\SalesChannelContextRestorer;
  21. use Shopware\Core\System\SalesChannel\Context\SalesChannelContextService;
  22. use Shopware\Core\System\SystemConfig\SystemConfigService;
  23. use Shopware\Storefront\Page\Account\Order\AccountOrderPageLoadedEvent;
  24. use Shopware\Storefront\Page\Account\Overview\AccountOverviewPageLoadedEvent;
  25. use Shopware\Storefront\Page\Checkout\Cart\CheckoutCartPageLoadedEvent;
  26. use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent;
  27. use Shopware\Storefront\Page\Checkout\Finish\CheckoutFinishPageLoadedEvent;
  28. use Shopware\Storefront\Page\Checkout\Offcanvas\OffcanvasCartPageLoadedEvent;
  29. use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
  30. use Swag\CmsExtensions\Storefront\Pagelet\Quickview\QuickviewPageletLoadedEvent;
  31. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  32. use Symfony\Component\HttpFoundation\RedirectResponse;
  33. use Symfony\Contracts\Translation\TranslatorInterface;
  34. class FrontendSubscriber implements EventSubscriberInterface
  35. {
  36.     /**
  37.      * @var TranslatorInterface
  38.      */
  39.     private TranslatorInterface $translator;
  40.     /**
  41.      * @var SystemConfigService
  42.      */
  43.     private SystemConfigService $systemConfigService;
  44.     /**
  45.      * @var EntityRepositoryInterface
  46.      */
  47.     private EntityRepositoryInterface $orderLineItemRepository;
  48.     private EntityRepositoryInterface $productRepository;
  49.     /**
  50.      * @var SessionService
  51.      */
  52.     private SessionService $sessionService;
  53.     private CartService $cartService;
  54.     private AbstractSalesChannelContextFactory $salesChannelContextFactory;
  55.     public function __construct(
  56.         TranslatorInterface                $translator,
  57.         SystemConfigService                $systemConfigService,
  58.         EntityRepositoryInterface          $orderLineItemRepository,
  59.         EntityRepositoryInterface          $productRepository,
  60.         SessionService                     $sessionService,
  61.         CartService                        $cartService,
  62.         AbstractSalesChannelContextFactory $salesChannelContextFactory
  63.     ) {
  64.         $this->translator $translator;
  65.         $this->systemConfigService $systemConfigService;
  66.         $this->orderLineItemRepository $orderLineItemRepository;
  67.         $this->productRepository $productRepository;
  68.         $this->sessionService $sessionService;
  69.         $this->cartService $cartService;
  70.         $this->salesChannelContextFactory $salesChannelContextFactory;
  71.     }
  72.     public static function getSubscribedEvents(): array
  73.     {
  74.         if (class_exists('\\Swag\\CmsExtensions\\Storefront\\Pagelet\\Quickview\\QuickviewPageletLoadedEvent')) {
  75.             return [
  76.                 ProductPageLoadedEvent::class => 'onProductPageLoaded',
  77.                 CheckoutCartPageLoadedEvent::class => 'onCheckoutCartPageLoaded',
  78.                 CheckoutConfirmPageLoadedEvent::class => 'onCheckoutConfirmPageLoaded',
  79.                 CheckoutFinishPageLoadedEvent::class => 'onCheckoutFinishPageLoaded',
  80.                 CheckoutOrderPlacedEvent::class => 'onCheckoutOrderPlaced',
  81.                 AccountOrderPageLoadedEvent::class => 'onAccountOrderPageLoaded',
  82.                 AccountOverviewPageLoadedEvent::class => 'onAccountOverviewPageLoaded',
  83.                 QuickviewPageletLoadedEvent::class => 'onQuickviewPageletLoaded',
  84.                 OffcanvasCartPageLoadedEvent::class => 'onOffcanvasCartPageLoadedEvent',
  85.                 AfterLineItemAddedEvent::class => 'onLineItemAdded'
  86.             ];
  87.         } else {
  88.             return [
  89.                 ProductPageLoadedEvent::class => 'onProductPageLoaded',
  90.                 CheckoutCartPageLoadedEvent::class => 'onCheckoutCartPageLoaded',
  91.                 CheckoutConfirmPageLoadedEvent::class => 'onCheckoutConfirmPageLoaded',
  92.                 CheckoutFinishPageLoadedEvent::class => 'onCheckoutFinishPageLoaded',
  93.                 CheckoutOrderPlacedEvent::class => 'onCheckoutOrderPlaced',
  94.                 AccountOrderPageLoadedEvent::class => 'onAccountOrderPageLoaded',
  95.                 AccountOverviewPageLoadedEvent::class => 'onAccountOverviewPageLoaded',
  96.                 OffcanvasCartPageLoadedEvent::class => 'onOffcanvasCartPageLoadedEvent',
  97.                 AfterLineItemAddedEvent::class => 'onLineItemAdded'
  98.             ];
  99.         }
  100.     }
  101.     /**
  102.      * provide the customer input on the product detail page
  103.      */
  104.     public function onProductPageLoaded(ProductPageLoadedEvent $event): SalesChannelProductEntity
  105.     {
  106.         $customerInputShowOnProductDetailPage $this->systemConfigService->get('CioProductCustomerInputs.config.customerInputShowOnProductDetailPage');
  107.         $product $event->getPage()->getProduct();
  108.         $lineItemId $event->getRequest()->get('lineItemId');
  109.         $lineItem null;
  110.         if (!is_null($lineItemId)) {
  111.             $cart $this->cartService->getCart($event->getSalesChannelContext()->getToken(), $event->getSalesChannelContext());
  112.             if (!$cart->has($lineItemId)) {
  113.                 $request $event->getRequest();
  114.                 $response = new RedirectResponse($request->getRequestUri());
  115.                 $response->send();
  116.                 exit;
  117.             }
  118.             $lineItem $cart->get($lineItemId);
  119.         }
  120.         if ($customerInputShowOnProductDetailPage == 'yes') {
  121.             if ($product->getCustomFields() && is_array($product->getCustomFields()) && isset($product->getCustomFields()['cio_customer_input_count_rows'])) {
  122.                 for ($row 1$row <= $product->getCustomFields()['cio_customer_input_count_rows']; ++$row) {
  123.                     for ($i 1$i <= CioProductCustomerInputs::CUSTOMER_INPUT_COUNT; ++$i) {
  124.                         $productExtensionData['value'] = $this->sessionService->getCustomerInputFromSession($product->getProductNumber(), 'value'$row$i$lineItemId$lineItem);
  125.                         $productExtensionData['checkboxValue'] = $this->sessionService->getCustomerInputFromSession($product->getProductNumber(), 'checkbox_value'$row$i$lineItemId$lineItem);
  126.                         $productExtension $this->sessionService->createArrayEntity($productExtensionData);
  127.                         $product->addExtension('cioCustomerInput' $row $i$productExtension);
  128.                     }
  129.                 }
  130.             }
  131.         }
  132.         $cioCustomerInputCount['value'] = CioProductCustomerInputs::CUSTOMER_INPUT_COUNT;
  133.         $cioCustomerInputCountValue $this->sessionService->createArrayEntity($cioCustomerInputCount);
  134.         $product->addExtension('cioCustomerInputCountValue'$cioCustomerInputCountValue);
  135.         return $product;
  136.     }
  137.     /**
  138.      * provide the customer input on the checkout cart page
  139.      */
  140.     public function onCheckoutCartPageLoaded(CheckoutCartPageLoadedEvent $event): array
  141.     {
  142.         return $this->getLineItemsCustomerInput($event->getPage()->getCart()->getLineItems()->getElements(), $event->getPage()->getCart());
  143.     }
  144.     /**
  145.      * provide the customer input on the off-canvas cart page
  146.      */
  147.     public function onOffcanvasCartPageLoadedEvent(OffcanvasCartPageLoadedEvent $event): array
  148.     {
  149.         return $this->getLineItemsCustomerInput($event->getPage()->getCart()->getLineItems()->getElements(), $event->getPage()->getCart());
  150.     }
  151.     /**
  152.      * provide the customer input on the checkout confirm page
  153.      */
  154.     public function onCheckoutConfirmPageLoaded(CheckoutConfirmPageLoadedEvent $event): array
  155.     {
  156.         $result $this->getLineItemsCustomerInput($event->getPage()->getCart()->getLineItems()->getElements(), $event->getPage()->getCart());
  157.         foreach ($result as $lineItem) {
  158.             if (!($lineItem instanceof LineItem) || $lineItem->getType() !== LineItem::PRODUCT_LINE_ITEM_TYPE) {
  159.                 continue;
  160.             }
  161.             $product $this->productRepository->search(new Criteria([$lineItem->getReferencedId()]), Context::createDefaultContext())->first();
  162.             /** @var array $customFields */
  163.             $customFields $product->getCustomFields();
  164.             if (is_null($customFields)) {
  165.                 continue;
  166.             }
  167.             $checkIndexes = [];
  168.             $numberOfRows array_key_exists('cio_customer_input_count_rows'$customFields) ? (int)$customFields['cio_customer_input_count_rows'] : 1;
  169.             for ($i 1$i <= 10$i++) {
  170.                 if (isset($customFields['cio_customer_input_' $i '_active']) && $customFields['cio_customer_input_' $i '_active'] === true &&
  171.                     isset($customFields['cio_customer_input_' $i '_required']) && $customFields['cio_customer_input_' $i '_required'] === true) {
  172.                     // add to $checkIndexes for every row
  173.                     for ($j 1$j <= $numberOfRows$j++) {
  174.                         $checkIndexes[] = 'cioLineItemCustomerInput' $j $i;
  175.                     }
  176.                 }
  177.             }
  178.             foreach ($checkIndexes as $checkIndex) {
  179.                 $lineItemExtension $lineItem->getExtension($checkIndex);
  180.                 if (!$lineItemExtension instanceof ArrayEntity) {
  181.                     //$event->getPage()->getCart()->getErrors()->add(new IncompleteLineItemError('', 'missingRequiredCustomFields'));
  182.                     break;
  183.                 }
  184.                 if (empty($lineItemExtension->get('value'))) {
  185.                     //$event->getPage()->getCart()->getErrors()->add(new IncompleteLineItemError('', 'missingRequiredCustomFields'));
  186.                     break;
  187.                 }
  188.             }
  189.         }
  190.         return $result;
  191.     }
  192.     /**
  193.      * save the customer inputs in the order line item custom fields after a successful order
  194.      */
  195.     public function onCheckoutFinishPageLoaded(CheckoutFinishPageLoadedEvent $event): void
  196.     {
  197.         $this->getLineItemsCustomerInput($event->getPage()->getOrder()->getLineItems()->getElements());
  198.         $event->getPage()->assign([
  199.             'cioCustomerInputCountValue' => CioProductCustomerInputs::CUSTOMER_INPUT_COUNT,
  200.         ]);
  201.     }
  202.     /**
  203.      * save the customer inputs in the order line item custom fields when order is placed
  204.      */
  205.     public function onCheckoutOrderPlaced(CheckoutOrderPlacedEvent $event): void
  206.     {
  207.         $lineItems $event->getOrder()->getLineItems();
  208.         $this->saveCustomerInputsInLineItemCustomFields($event$lineItemsfalse);
  209.     }
  210.     /**
  211.      * assign the customer input count value to the account order page
  212.      */
  213.     public function onAccountOrderPageLoaded(AccountOrderPageLoadedEvent $event): void
  214.     {
  215.         $event->getPage()->assign([
  216.             'cioCustomerInputCountValue' => CioProductCustomerInputs::CUSTOMER_INPUT_COUNT,
  217.         ]);
  218.     }
  219.     /**
  220.      * assign the customer input count value to the account overview page
  221.      */
  222.     public function onAccountOverviewPageLoaded(AccountOverviewPageLoadedEvent $event): void
  223.     {
  224.         $event->getPage()->assign([
  225.             'cioCustomerInputCountValue' => CioProductCustomerInputs::CUSTOMER_INPUT_COUNT,
  226.         ]);
  227.     }
  228.     /**
  229.      * provide the customer input on the quickview
  230.      * @return ProductEntity
  231.      */
  232.     public function onQuickviewPageletLoaded($event): ProductEntity
  233.     {
  234.         $customerInputShowOnProductDetailPage $this->systemConfigService->get('CioProductCustomerInputs.config.customerInputShowOnProductDetailPage');
  235.         $product $event->getPagelet()->getProduct();
  236.         if ($customerInputShowOnProductDetailPage == 'yes') {
  237.             for ($row 1$row <= $product->getCustomFields()['cio_customer_input_count_rows']; ++$row) {
  238.                 for ($i 1$i <= CioProductCustomerInputs::CUSTOMER_INPUT_COUNT; ++$i) {
  239.                     $productExtensionData['value'] = $this->sessionService->getCustomerInputFromSession($product->getProductNumber(), 'value'$row$i);
  240.                     $productExtensionData['checkboxValue'] = $this->sessionService->getCustomerInputFromSession($product->getProductNumber(), 'checkbox_value'$row$i);
  241.                     $productExtension $this->sessionService->createArrayEntity($productExtensionData);
  242.                     $product->addExtension('cioCustomerInput' $row $i$productExtension);
  243.                 }
  244.             }
  245.         }
  246.         $cioCustomerInputCount['value'] = CioProductCustomerInputs::CUSTOMER_INPUT_COUNT;
  247.         $cioCustomerInputCountValue $this->sessionService->createArrayEntity($cioCustomerInputCount);
  248.         $product->addExtension('cioCustomerInputCountValue'$cioCustomerInputCountValue);
  249.         return $product;
  250.     }
  251.     public function onLineItemAdded(AfterLineItemAddedEvent $event)
  252.     {
  253.         foreach ($event->getLineItems() as $lineItem) {
  254.             $this->sessionService->cloneSessionToLineItemSession($lineItem);
  255.         }
  256.     }
  257.     /**
  258.      * save the customer inputs in the order line item custom fields
  259.      */
  260.     protected function saveCustomerInputsInLineItemCustomFields($event$lineItems$isCheckoutFinishPage): void
  261.     {
  262.         $customerInputTransferUnselectedCheckboxFieldsAsValue $this->systemConfigService->get('CioProductCustomerInputs.config.customerInputTransferUnselectedCheckboxFieldsAsValue');
  263.         foreach ($lineItems as $item) {
  264.             /** @var OrderLineItemEntity $item */
  265.             if ($item->getType() !== LineItem::PROMOTION_LINE_ITEM_TYPE) {
  266.                 $productNumber $item->getPayload()['productNumber'];
  267.                 $cioCustomerInputValueArray = [];
  268.                 $cioCustomerInputHasValue 0;
  269.                 if (isset($item->getPayload()['customFields']['cio_customer_input_count_rows'])) {
  270.                     for ($row 1$row <= $item->getPayload()['customFields']['cio_customer_input_count_rows']; ++$row) {
  271.                         for ($i 1$i <= CioProductCustomerInputs::CUSTOMER_INPUT_COUNT; ++$i) {
  272.                             $lineItem null;
  273.                             if (isset($item->getPayload()['cartToken'])) {
  274.                                 $token $item->getPayload()['cartToken'];
  275.                                 $salesChannelContext $this->salesChannelContextFactory->create($token$event->getOrder()->getSalesChannelId(), [SalesChannelContextService::LANGUAGE_ID => $event->getOrder()->getLanguageId()]);
  276.                                 $lineItem $this->cartService->getCart($token$salesChannelContext)->get($item->getIdentifier());
  277.                             }
  278.                             $cioCustomerInputValue $this->sessionService->getCustomerInputFromSession($productNumber'value'$row$i$item->getIdentifier(), $lineItem);
  279.                             $cioCustomerInputCheckboxValue $this->sessionService->getCustomerInputFromSession($productNumber'checkbox_value'$row$i$item->getIdentifier(), $lineItem);
  280.                             $cioCustomerInputLabel $this->sessionService->getCustomerInputFromSession($productNumber'label'$row$i$item->getIdentifier(), $lineItem);
  281.                             $cioCustomerInputPlaceholder $this->sessionService->getCustomerInputFromSession($productNumber'placeholder'$row$i$item->getIdentifier(), $lineItem);
  282.                             $cioCustomerInputFieldType $this->sessionService->getCustomerInputFromSession($productNumber'fieldtype'$row$i$item->getIdentifier(), $lineItem);
  283.                             if ($cioCustomerInputValue || (($customerInputTransferUnselectedCheckboxFieldsAsValue) && ($cioCustomerInputFieldType == 'boolean') && ($cioCustomerInputValue == 0))) {
  284.                                 $cioCustomerInputValueArray[$row][$i]['value'] = ($cioCustomerInputFieldType == 'boolean' ? ($cioCustomerInputValue == $this->translator->trans('cio.customerInput.selectedValue') : $this->translator->trans('cio.customerInput.unselectedValue')) : $cioCustomerInputValue);
  285.                                 $cioCustomerInputValueArray[$row][$i]['checkbox_value'] = $cioCustomerInputCheckboxValue;
  286.                                 $cioCustomerInputValueArray[$row][$i]['label'] = $cioCustomerInputLabel;
  287.                                 $cioCustomerInputValueArray[$row][$i]['placeholder'] = $cioCustomerInputPlaceholder;
  288.                                 $cioCustomerInputValueArray[$row][$i]['fieldtype'] = $cioCustomerInputFieldType;
  289.                                 $cioCustomerInputHasValue $cioCustomerInputHasValue 1;
  290.                             } elseif ($customerInputTransferUnselectedCheckboxFieldsAsValue) {
  291.                                 if ($item->getCustomFields() and (!isset($item->getCustomFields()['cio_customer_input_' $i '_value']))) {
  292.                                     $productCustomFields $item->getPayload()['customFields'];
  293.                                     if (isset($productCustomFields['cio_customer_input_' $i '_active'])) {
  294.                                         if ($productCustomFields['cio_customer_input_' $i '_active'] && $productCustomFields['cio_customer_input_' $i '_fieldtype'] == 'boolean') {
  295.                                             $cioCustomerInputValue $this->sessionService->getCustomerInputFromSession($productNumber'value'$row$i$item->getId(), $lineItem);
  296.                                             if ($cioCustomerInputValue == '') {
  297.                                                 $cioCustomerInputValue $this->translator->trans('cio.customerInput.unselectedValue');
  298.                                                 $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'));
  299.                                                 $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'));
  300.                                                 $cioCustomerInputFieldType $productCustomFields['cio_customer_input_' $i '_fieldtype'];
  301.                                                 $cioCustomerInputValueArray[$row][$i]['value'] = $cioCustomerInputValue;
  302.                                                 $cioCustomerInputValueArray[$row][$i]['label'] = $cioCustomerInputLabel;
  303.                                                 $cioCustomerInputValueArray[$row][$i]['placeholder'] = $cioCustomerInputPlaceholder;
  304.                                                 $cioCustomerInputValueArray[$row][$i]['fieldtype'] = $cioCustomerInputFieldType;
  305.                                                 $cioCustomerInputHasValue $cioCustomerInputHasValue 1;
  306.                                             }
  307.                                         }
  308.                                     }
  309.                                 }
  310.                             }
  311.                         }
  312.                     }
  313.                 }
  314.                 $cioCustomerInputValueCustomFieldArray = [];
  315.                 $cioCustomerInputValueTypeArray = array('value''checkbox_value''label''placeholder''fieldtype');
  316.                 if (isset($item->getPayload()['customFields']['cio_customer_input_count_rows'])) {
  317.                     for ($row 1$row <= $item->getPayload()['customFields']['cio_customer_input_count_rows']; ++$row) {
  318.                         for ($i 1$i <= CioProductCustomerInputs::CUSTOMER_INPUT_COUNT; ++$i) {
  319.                             foreach ($cioCustomerInputValueTypeArray as $ta) {
  320.                                 if (isset($cioCustomerInputValueArray[$row][$i][$ta])) {
  321.                                     $cioCustomerInputValueCustomFieldArray['cio_customer_input_' $row '_' $i '_' $ta] = $cioCustomerInputValueArray[$row][$i][$ta];
  322.                                 }
  323.                             }
  324.                         }
  325.                     }
  326.                 }
  327.                 $item->setCustomFields(
  328.                     $cioCustomerInputValueCustomFieldArray
  329.                 );
  330.                 if ($isCheckoutFinishPage) {
  331.                     for ($row 1$row <= $item->getPayload()['customFields']['cio_customer_input_count_rows']; ++$row) {
  332.                         for ($i 1$i <= CioProductCustomerInputs::CUSTOMER_INPUT_COUNT; ++$i) {
  333.                             $this->sessionService->removeCustomerInputFromSession($productNumber$row$i$item->getId());
  334.                         }
  335.                     }
  336.                 }
  337.                 if ($cioCustomerInputHasValue 0) {
  338.                     $this->orderLineItemRepository->upsert(
  339.                         [
  340.                             [
  341.                                 'id' => $item->getId(),
  342.                                 'customFields' => $item->getCustomFields(),
  343.                             ],
  344.                         ],
  345.                         $event->getContext() ?? Context::createDefaultContext()
  346.                     );
  347.                 }
  348.             }
  349.         }
  350.     }
  351.     /**
  352.      * get the customer input for each line item
  353.      */
  354.     private function getLineItemsCustomerInput($lineItems$cart null): array
  355.     {
  356.         foreach ($lineItems as $lineItem) {
  357.             $this->sessionService->addLineItemsCustomerInput($lineItem$cart);
  358.         }
  359.         return $lineItems;
  360.     }
  361. }