custom/plugins/NetzhirschPriceOnRequest/src/Subscriber/PageSubscriber.php line 144

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace NetzhirschPriceOnRequest\Subscriber;
  3. use Exception;
  4. use NetzhirschPriceOnRequest\NetzhirschPriceOnRequest;
  5. use Shopware\Core\Content\Cms\Aggregate\CmsBlock\CmsBlockEntity;
  6. use Shopware\Core\Content\Cms\Aggregate\CmsSection\CmsSectionCollection;
  7. use Shopware\Core\Content\Cms\Aggregate\CmsSection\CmsSectionEntity;
  8. use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotCollection;
  9. use Shopware\Core\Content\Cms\CmsPageEntity;
  10. use Shopware\Core\Content\Cms\Events\CmsPageLoadedEvent;
  11. use Shopware\Core\Content\Cms\SalesChannel\Struct\BuyBoxStruct;
  12. use Shopware\Core\Content\Cms\SalesChannel\Struct\ProductBoxStruct;
  13. use Shopware\Core\Content\Cms\SalesChannel\Struct\ProductListingStruct;
  14. use Shopware\Core\Content\Cms\SalesChannel\Struct\ProductSliderStruct;
  15. use Shopware\Core\Content\ImportExport\Event\ImportExportBeforeImportRecordEvent;
  16. use Shopware\Core\Content\Product\Events\ProductCrossSellingsLoadedEvent;
  17. use Shopware\Core\Content\Product\Events\ProductListingResultEvent;
  18. use Shopware\Core\Content\Product\Events\ProductSearchResultEvent;
  19. use Shopware\Core\Content\Product\ProductEntity;
  20. use Shopware\Core\Content\Product\SalesChannel\CrossSelling\CrossSellingElement;
  21. use Shopware\Core\Content\ProductStream\Service\ProductStreamBuilder;
  22. use Shopware\Core\Content\Rule\RuleEntity;
  23. use Shopware\Core\Framework\Context;
  24. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  25. use Shopware\Core\Framework\Struct\ArrayEntity;
  26. use Shopware\Core\Framework\Validation\DataBag\DataBag;
  27. use Shopware\Core\System\SystemConfig\SystemConfigService;
  28. use Shopware\Storefront\Event\StorefrontRenderEvent;
  29. use Shopware\Storefront\Page\Checkout\Offcanvas\OffcanvasCartPage;
  30. use Shopware\Storefront\Page\Navigation\NavigationPage;
  31. use Shopware\Storefront\Page\Product\ProductPage;
  32. use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
  33. use Shopware\Storefront\Page\Search\SearchPage;
  34. use Shopware\Storefront\Page\Suggest\SuggestPageLoadedEvent;
  35. use Shopware\Storefront\Page\Wishlist\WishlistPageLoadedEvent;
  36. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  37. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  38. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  39. use Symfony\Contracts\Translation\TranslatorInterface;
  40. class PageSubscriber implements EventSubscriberInterface
  41. {
  42.     /** @var SystemConfigService $systemConfigService */
  43.     private $systemConfigService;
  44.     /** @var EntityRepository $productRepository */
  45.     private $productRepository;
  46.     /** @var EntityRepository $cms */
  47.     private $cmsRepository;
  48.     /** @var ProductStreamBuilder $productStreamBuilder */
  49.     private $productStreamBuilder;
  50.     /** @var EntityRepository $productStreamRepository */
  51.     private $productStreamRepository;
  52.     /** @var EntityRepository $priceOnRequest */
  53.     private $priceOnRequest;
  54.     /** @var array $options */
  55.     private $options;
  56.     /** @var TranslatorInterface $translator */
  57.     private $translator;
  58.     public function __construct(
  59.         SystemConfigService       $systemConfigService,
  60.         EntityRepository $productRepository,
  61.         EntityRepository $cmsRepository,
  62.         EntityRepository $productStreamRepository,
  63.         EntityRepository $priceOnRequest,
  64.         ProductStreamBuilder      $productStreamBuilder,
  65.         TranslatorInterface       $translator
  66.     )
  67.     {
  68.         $this->systemConfigService = $systemConfigService;
  69.         $this->productRepository = $productRepository;
  70.         $this->cmsRepository = $cmsRepository;
  71.         $this->productStreamBuilder = $productStreamBuilder;
  72.         $this->priceOnRequest = $priceOnRequest;
  73.         $this->productStreamRepository = $productStreamRepository;
  74.         $this->translator = $translator;
  75.     }
  76.     public static function getSubscribedEvents(): array
  77.     {
  78.         return [
  79.             ProductListingResultEvent::class => 'onProductList',
  80.             ProductSearchResultEvent::class => 'onProductList',
  81.             ProductPageLoadedEvent::class => 'onProductPageLoaded',
  82.             StorefrontRenderEvent::class => 'onStorefrontRender',
  83.             SuggestPageLoadedEvent::class => 'onSuggestPageLoaded',
  84.             WishlistPageLoadedEvent::class => 'onWishListPageLoaded',
  85.             CmsPageLoadedEvent::class => 'onSlider',
  86.             ImportExportBeforeImportRecordEvent::class => 'onBeforeImportRow'
  87.         ];
  88.     }
  89.     public function onBeforeImportRow(ImportExportBeforeImportRecordEvent $event)
  90.     {
  91.         $record = $event->getRecord();
  92.         if (
  93.             !isset($record['priceOnRequest'])
  94.             && !isset($record['priceOnRequest']['id'])
  95.             && !isset($record['priceOnRequest']['active'])
  96.         ) {
  97.             return;
  98.         }
  99.         $this->priceOnRequest->upsert([
  100.             [
  101.                 'id' => $record['priceOnRequest']['id'],
  102.                 'active' => $record['priceOnRequest']['active'],
  103.                 'productId' => $record['id']
  104.             ]
  105.         ], $event->getContext());
  106.     }
  107.     public function onSlider(CmsPageLoadedEvent $event)
  108.     {
  109.         $salesChannelId = $event->getSalesChannelContext()->getSalesChannelId();
  110.         $activeForSalesChannel = $this->systemConfigService->get(
  111.             NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.activeForSalesChannel', $salesChannelId
  112.         );
  113.         if (empty($activeForSalesChannel)){
  114.             return;
  115.         }
  116.         $options = [];
  117.         /** @var CmsPageEntity $result */
  118.         foreach ($event->getResult() as $result) {
  119.             $options = $this->getOptionsBySections(
  120.                 $result->getSections(),
  121.                 $options,
  122.                 $event->getContext(),
  123.                 $salesChannelId
  124.             );
  125.             $result->assign($options);
  126.         }
  127.     }
  128.     public function onWishListPageLoaded(WishlistPageLoadedEvent $event)
  129.     {
  130.         $salesChannelId = $event->getSalesChannelContext()->getSalesChannelId();
  131.         $activeForSalesChannel = $this->systemConfigService->get(
  132.             NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.activeForSalesChannel', $salesChannelId
  133.         );
  134.         if (empty($activeForSalesChannel)){
  135.             return;
  136.         }
  137.         $page = $event->getPage();
  138.         $wishlist = $page->getWishlist();
  139.         $productListing = $wishlist->getProductListing();
  140.         $context = $event->getContext();
  141.         $optionToAssign = [];
  142.         foreach ($productListing->getElements() as $product)
  143.             $optionToAssign = $this->getOptionToAssign($context, $product, $salesChannelId, $optionToAssign);
  144.         $page->assign($optionToAssign);
  145.     }
  146.     public function onSuggestPageLoaded(SuggestPageLoadedEvent $event)
  147.     {
  148.         $salesChannelId = $event->getSalesChannelContext()->getSalesChannelId();
  149.         $activeForSalesChannel = $this->systemConfigService->get(
  150.             NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.activeForSalesChannel', $salesChannelId
  151.         );
  152.         if (empty($activeForSalesChannel)){
  153.             return;
  154.         }
  155.         $page = $event->getPage();
  156.         $searchResult = $page->getSearchResult();
  157.         $context = $event->getContext();
  158.         $optionToAssign = [];
  159.         foreach ($searchResult->getEntities() as $product)
  160.             $optionToAssign = $this->getOptionToAssign($context, $product, $salesChannelId, $optionToAssign);
  161.         $page->assign($optionToAssign);
  162.     }
  163.     public function onProductList(ProductListingResultEvent $event)
  164.     {
  165.         $salesChannelId = $event->getSalesChannelContext()->getSalesChannelId();
  166.         $activeForSalesChannel = $this->systemConfigService->get(
  167.             NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.activeForSalesChannel', $salesChannelId
  168.         );
  169.         if (empty($activeForSalesChannel)){
  170.             return;
  171.         }
  172.         $result = $event->getResult();
  173.         $context = $event->getContext();
  174.         $salesChannelId = $event->getSalesChannelContext()->getSalesChannelId();
  175.         $optionToAssign = [];
  176.         foreach ($result->getEntities() as $product)
  177.             $optionToAssign = $this->getOptionToAssign($context, $product, $salesChannelId, $optionToAssign);
  178.         $this->options = $optionToAssign;
  179.     }
  180.     public function onStorefrontRender(StorefrontRenderEvent $event)
  181.     {
  182.         $salesChannelId = $event->getSalesChannelContext()->getSalesChannelId();
  183.         $activeForSalesChannel = $this->systemConfigService->get(
  184.             NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.activeForSalesChannel', $salesChannelId
  185.         );
  186.         if (empty($activeForSalesChannel)){
  187.             return;
  188.         }
  189.         $this->setEventParameterForModal($event);
  190.         $params = $event->getParameters();
  191.         if (!isset($params['page']))
  192.             return;
  193.         $navigationPage = $params['page'];
  194.         /** @var NavigationPage $navigationPage */
  195.         if (
  196.             get_class($navigationPage) != NavigationPage::class
  197.             && get_class($navigationPage) != SearchPage::class
  198.             && get_class($navigationPage) != ProductPage::class
  199.         )
  200.             return;
  201.         /** @var OffcanvasCartPage|NavigationPage $offcanvasCartPage */
  202.         $offcanvasCartPage = $params['page'];
  203.         $options = [];
  204.         if (empty($this->options)) {
  205.             $varsPage = $offcanvasCartPage->getVars();
  206.             if (!isset($varsPage['cmsPage']))
  207.                 return;
  208.             /** @var CmsPageEntity $cmsPage */
  209.             $cmsPage = $varsPage['cmsPage'];
  210.             $options = $this->getOptionsBySections(
  211.                 $cmsPage->getSections(),
  212.                 $options,
  213.                 $event->getContext(),
  214.                 $event->getSalesChannelContext()->getSalesChannelId()
  215.             );
  216.             if (!empty($options))
  217.                 $offcanvasCartPage->assign($options);
  218.             return;
  219.         }
  220.         $navigationPage->assign($this->options);
  221.     }
  222.     private function getOptionsBySections(
  223.         CmsSectionCollection $sectionCollection,
  224.         array $options,
  225.         Context $context,
  226.         string $salesChannelId
  227.     )
  228.     {
  229.         foreach ($sectionCollection as $section) {
  230.             $varsSection = $section->getVars();
  231.             if (!isset($varsSection['blocks']))
  232.                 continue;
  233.             $blocks = $varsSection['blocks'];
  234.             /** @var CmsBlockEntity $block */
  235.             foreach ($blocks as $block) {
  236.                 $varsBlock = $block->getVars();
  237.                 if (!isset($varsBlock['slots']))
  238.                     continue;
  239.                 /** @var CmsSlotCollection $slots */
  240.                 $slots = $varsBlock['slots'];
  241.                 foreach ($slots->getElements() as $element) {
  242.                     $data = $element->getData();
  243.                     if (
  244.                         empty($data)
  245.                         || (
  246.                             get_class($data) != ProductBoxStruct::class
  247.                             && get_class($data) != BuyBoxStruct::class
  248.                             && get_class($data) != ProductListingStruct::class
  249.                             && get_class($data) != ProductSliderStruct::class
  250.                         )) {
  251.                         continue;
  252.                     }
  253.                     if (get_class($data) == ProductListingStruct::class) {
  254.                         $listing = $data->getListing();
  255.                         foreach ($listing->getEntities() as $entity) {
  256.                             $options = $this->getOptionToAssign(
  257.                                 $context,
  258.                                 $entity,
  259.                                 $salesChannelId,
  260.                                 $options
  261.                             );
  262.                         }
  263.                     } else if (get_class($data) == ProductSliderStruct::class) {
  264.                         $products = $data->getProducts();
  265.                         foreach ($products as $product) {
  266.                             $options = $this->getOptionToAssign(
  267.                                 $context,
  268.                                 $product,
  269.                                 $salesChannelId,
  270.                                 $options
  271.                             );
  272.                         }
  273.                     } else {
  274.                         $product = $data->getProduct();
  275.                         $options = $this->getOptionToAssign(
  276.                             $context,
  277.                             $product,
  278.                             $salesChannelId,
  279.                             $options
  280.                         );
  281.                     }
  282.                 }
  283.             }
  284.         }
  285.         return $options;
  286.     }
  287.     private function setEventParameterForModal(StorefrontRenderEvent $event)
  288.     {
  289.         $cmsPage = null;
  290.         $params = $event->getParameters();
  291.         if (isset($params['cmsPage'])) {
  292.             $cmsPage = $params['cmsPage'];
  293.         } elseif (isset($params['page'])) {
  294.             /** @var NavigationPage $navigationPage */
  295.             $navigationPage = $params['page'];
  296.             if (get_class($navigationPage) == NavigationPage::class)
  297.                 $cmsPage = $navigationPage->getCmsPage();
  298.         }
  299.         if (empty($cmsPage))
  300.             return;
  301.         /** @var CmsPageEntity $cmsPage */
  302.         $title = $cmsPage->getTranslated()['name'] ?? null;
  303.         if (empty($title))
  304.             return;
  305.         $formName = $this->getFormName($event->getSalesChannelContext()->getSalesChannelId());
  306.         $formInCmsPage = false;
  307.         if ($formName == $title) {
  308.             $formInCmsPage = true;
  309.         } else {
  310.             /** @var CmsSectionEntity $section */
  311.             foreach ($cmsPage->getSections() as $section) {
  312.                 if ($section->getPageId() == $formName) {
  313.                     $formInCmsPage = true;
  314.                 }
  315.             }
  316.         }
  317.         if (!$formInCmsPage)
  318.             return;
  319.         $productNumber = $event->getRequest()->get('productNumber');
  320.         $productName = $event->getRequest()->get('productName');
  321.         $data = new DataBag();
  322.         $comment = $this->translator->trans('netzhirsch-price-on-request.comment', [
  323.             '%productName%' => $productName,
  324.             '%productNumber%' => $productNumber,
  325.         ]);
  326.         $subject = $this->translator->trans('netzhirsch-price-on-request.subject', [
  327.             '%productName%' => $productName,
  328.             '%productNumber%' => $productNumber,
  329.         ]);
  330.         $data->set('comment', $comment);
  331.         $data->set('subject', $subject);
  332.         $event->setParameter('data', $data);
  333.     }
  334.     /**
  335.      * @throws Exception
  336.      */
  337.     public function onProductPageLoaded(ProductPageLoadedEvent $event): void
  338.     {
  339.         $salesChannelId = $event->getSalesChannelContext()->getSalesChannelId();
  340.         $activeForSalesChannel = $this->systemConfigService->get(
  341.             NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.activeForSalesChannel', $salesChannelId
  342.         );
  343.         if (empty($activeForSalesChannel)){
  344.             return;
  345.         }
  346.         $page = $event->getPage();
  347.         $product = $page->getProduct();
  348.         $optionToAssign = [];
  349.         $context = $event->getContext();
  350.         $salesChannelId = $event->getSalesChannelContext()->getSalesChannelId();
  351.         $optionToAssign['netzhirschPriceOnRequestActive'] = $this->isPriceOnRequestActive($context, $product, $salesChannelId);
  352.         $netzhirschPriceOnRequestShowProductPrice = $this->systemConfigService->get(
  353.             NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.showProductPrice', $salesChannelId
  354.         );
  355.         $optionToAssign['netzhirschPriceOnRequestShowProductPrice'] = $netzhirschPriceOnRequestShowProductPrice;
  356.         $netzhirschPriceOnRequestPageId = $this->getFormPageId($context, $salesChannelId);
  357.         $optionToAssign['netzhirschPriceOnRequestPageId'] = $netzhirschPriceOnRequestPageId;
  358.         $optionToAssign['netzhirschPriceOnRequestCrossSelling'] = [];
  359.         /** $page->getCrossSellings() kann null sein, obwohl der getter das nicht erlaubt */
  360.         if (!empty($page->getVars()['crossSellings'])) {
  361.             /** @var CrossSellingElement $crossSelling */
  362.             foreach ($page->getCrossSellings() as $crossSelling) {
  363.                 foreach ($crossSelling->getProducts() as $productCrossSelling) {
  364.                     $optionToAssign['netzhirschPriceOnRequestCrossSelling'][$productCrossSelling->getId()]
  365.                         =
  366.                         [
  367.                             'netzhirschPriceOnRequestActive' => $this->isPriceOnRequestActive($context, $productCrossSelling, $salesChannelId),
  368.                             'netzhirschPriceOnRequestShowProductPrice' => $netzhirschPriceOnRequestShowProductPrice,
  369.                             'netzhirschPriceOnRequestPageId' => $netzhirschPriceOnRequestPageId,
  370.                             'productId' => $productCrossSelling->getId()
  371.                         ]
  372.                     ;
  373.                 }
  374.             }
  375.         }
  376.         $page->assign(
  377.             $optionToAssign
  378.         );
  379.     }
  380.     private function isPriceOnRequestActive(Context $context, ProductEntity $product, string $salesChannelId)
  381.     {
  382.         $active = $this->isPriceOnRequestActiveByProduct($context, $product);
  383.         if (!$active)
  384.             $active = $this->isPriceOnRequestActiveByStream($context, $salesChannelId, $product);
  385.         return $active;
  386.     }
  387.     private function isPriceOnRequestActiveByProduct(Context $context, ProductEntity $product)
  388.     {
  389.         $criteria = new Criteria();
  390.         $criteria->addFilter(new EqualsFilter('productNumber', $product->getProductNumber()));
  391.         $criteria->addAssociation('priceOnRequest');
  392.         $products = $this->productRepository->search($criteria, $context);
  393.         if ($products->count() == 0)
  394.             return false;
  395.         /** @var ProductEntity $productWitExtensions */
  396.         $productWitExtensions = $products->first();
  397.         /** @var ArrayEntity $arrayEntity */
  398.         $arrayEntity = $productWitExtensions->getExtension('priceOnRequest');
  399.         if (empty($arrayEntity))
  400.             return false;
  401.         return $arrayEntity->get('active');
  402.     }
  403.     private function getFormPageId(Context $context, string $salesChannelId)
  404.     {
  405.         $equalsFilterField = 'name';
  406.         $equalsFilterFieldValue = 'Preis auf Anfrage';
  407.         $formId = $this->systemConfigService->get(
  408.             NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.formName', $salesChannelId
  409.         );
  410.         if (!empty($formId)) {
  411.             $equalsFilterField = 'id';
  412.             $equalsFilterFieldValue = $formId;
  413.         }
  414.         $criteria = new Criteria();
  415.         $criteria->addFilter(new EqualsFilter($equalsFilterField, $equalsFilterFieldValue));
  416.         $cmsPageEntities = $this->cmsRepository->search($criteria, $context);
  417.         if ($cmsPageEntities->count() == 0)
  418.             return null;
  419.         /** @var CmsPageEntity $cmsPageEntity */
  420.         $cmsPageEntity = $cmsPageEntities->first();
  421.         if (empty($cmsPageEntity))
  422.             return null;
  423.         return $cmsPageEntity->getId();
  424.     }
  425.     private function getFormName(string $salesChannelId)
  426.     {
  427.         $formName = $this->systemConfigService->get(
  428.             NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.formName', $salesChannelId
  429.         );
  430.         if (empty($formName))
  431.             return 'Preis auf Anfrage';
  432.         return $formName;
  433.     }
  434.     private function isPriceOnRequestActiveByStream(Context $context, string $salesChannelId, ProductEntity $product)
  435.     {
  436.         $streamNameId = $this->systemConfigService->get(
  437.             NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.streamName', $salesChannelId
  438.         );
  439.         $equalsFilterField = 'name';
  440.         $equalsFilterFieldValue = 'Preis auf Anfrage';
  441.         if (!empty($streamNameId)) {
  442.             $equalsFilterField = 'id';
  443.             $equalsFilterFieldValue = $streamNameId;
  444.         }
  445.         $criteria = new Criteria();
  446.         $criteria->addFilter(new EqualsFilter($equalsFilterField, $equalsFilterFieldValue));
  447.         $productStreams = $this->productStreamRepository->search($criteria, $context);
  448.         /** @var RuleEntity $productStream */
  449.         $productStream = $productStreams->first();
  450.         if (empty($productStream))
  451.             return false;
  452.         $criteria = new Criteria();
  453.         $criteria->addFilter(new EqualsFilter('productNumber', $product->getProductNumber()));
  454.         $filters = $this->productStreamBuilder->buildFilters($productStream->getId(), $context);
  455.         foreach ($filters as $filter)
  456.             $criteria->addFilter($filter);
  457.         /** @var ProductEntity $productWitExtensions */
  458.         $product = $this->productRepository->search($criteria, $context)->first();
  459.         return !empty($product);
  460.     }
  461.     /**
  462.      * @param Context $context
  463.      * @param $product
  464.      * @param string $salesChannelId
  465.      * @param array $optionToAssign
  466.      * @return array
  467.      */
  468.     private function getOptionToAssign(Context $context, $product, string $salesChannelId, array $optionToAssign): array
  469.     {
  470.         $optionToAssign['netzhirschPriceOnRequest'][$product->getId()]['netzhirschPriceOnRequestActive']
  471.             = $this->isPriceOnRequestActive($context, $product, $salesChannelId);
  472.         $optionToAssign['netzhirschPriceOnRequest'][$product->getId()]['netzhirschPriceOnRequestShowProductPrice']
  473.             = $this->systemConfigService->get(
  474.             NetzhirschPriceOnRequest::TECHNICAL_NAME . '.config.showProductPrice', $salesChannelId
  475.         );
  476.         $optionToAssign['netzhirschPriceOnRequest'][$product->getId()]['netzhirschPriceOnRequestPageId']
  477.             = $this->getFormPageId($context, $salesChannelId);
  478.         $optionToAssign['netzhirschPriceOnRequest'][$product->getId()]['productId'] = $product->getId();
  479.         return $optionToAssign;
  480.     }
  481. }