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

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