custom/static-plugins/SamsonCustomer/src/Controller/ProductController.php line 116

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Samson\Controller;
  3. /***
  4.  *
  5.  * This file is part of the "SAMSON Shop" project.
  6.  *
  7.  * For the full copyright and license information, please read the
  8.  * LICENSE.txt file that was distributed with this source code.
  9.  *
  10.  *  (c) 2020
  11.  *
  12.  ***/
  13. use GuzzleHttp\Exception\GuzzleException;
  14. use Samson\Defaults;
  15. use Samson\Exception\CustomerNeedsPasswordChangeException;
  16. use Samson\Exception\OfferSimulationException;
  17. use Samson\Service\IndustriesResolverService;
  18. use Samson\Service\OfferSimulationService;
  19. use Samson\Subscriber\ProductLoadedSerialNumberSubscriber;
  20. use Samson\Pages\Cms\SalesChannel\SalesChannelCmsPageLoader;
  21. use Sentry\State\Scope;
  22. use Shopware\Core\Content\Cms\CmsPageEntity;
  23. use Shopware\Core\Content\Cms\DataResolver\ResolverContext\EntityResolverContext;
  24. use Shopware\Core\Content\Product\SalesChannel\Review\AbstractProductReviewSaveRoute;
  25. use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductDefinition;
  26. use Shopware\Core\Content\Seo\SeoUrlPlaceholderHandlerInterface;
  27. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  28. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  29. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  30. use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
  31. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  32. use Shopware\Core\System\SystemConfig\SystemConfigService;
  33. use Shopware\Storefront\Controller\ProductController as ShopwareProductController;
  34. use Shopware\Storefront\Page\Product\Configurator\ProductCombinationFinder;
  35. use Shopware\Storefront\Page\Product\ProductPage;
  36. use Shopware\Storefront\Page\Product\ProductPageLoadedHook;
  37. use Shopware\Storefront\Page\Product\ProductPageLoader;
  38. use Shopware\Storefront\Page\Product\QuickView\MinimalQuickViewPageLoader;
  39. use Shopware\Storefront\Page\Product\Review\ProductReviewLoader;
  40. use Symfony\Component\HttpFoundation\JsonResponse;
  41. use Symfony\Component\HttpFoundation\Request;
  42. use Symfony\Component\HttpFoundation\Response;
  43. use Symfony\Component\HttpFoundation\Session\Session;
  44. use Shopware\Core\Framework\Routing\Annotation\RouteScope;
  45. use Symfony\Component\Routing\Annotation\Route;
  46. use Shopware\Core\Framework\Routing\Annotation\Since;
  47. use Shopware\Storefront\Framework\Cache\Annotation\HttpCache;
  48. use Samson\Annotation\CustomerNeedsPasswordChange;
  49. use Shopware\Core\Framework\Routing\Annotation\LoginRequired;
  50. use function Sentry\captureException;
  51. use function Sentry\withScope;
  52. /**
  53.  * @RouteScope(scopes={"storefront"})
  54.  */
  55. class ProductController extends ShopwareProductController
  56. {
  57.     protected const FLASH_NAME 'product-configurator-flash-message';
  58.     private EntityRepositoryInterface $productRepository;
  59.     private ProductPageLoader $productPageLoader;
  60.     private ProductLoadedSerialNumberSubscriber $productLoadedSerialNumberSubscriber;
  61.     private OfferSimulationService $offerSimulationService;
  62.     private SystemConfigService $systemConfigService;
  63.     private EntityRepositoryInterface $mediaRepository;
  64.     private IndustriesResolverService $industries;
  65.     private SalesChannelCmsPageLoader $cmsPageLoader;
  66.     private SalesChannelProductDefinition $productDefinition;
  67.     public function __construct(
  68.         SeoUrlPlaceholderHandlerInterface   $seoUrlPlaceholderHandler,
  69.         EntityRepositoryInterface           $productRepository,
  70.         ProductPageLoader                   $productPageLoader,
  71.         ProductLoadedSerialNumberSubscriber $productLoadedSerialNumberSubscriber,
  72.         ProductCombinationFinder            $combinationFinder,
  73.         MinimalQuickViewPageLoader          $minimalQuickViewPageLoader,
  74.         AbstractProductReviewSaveRoute      $productReviewSaveRoute,
  75.         ProductReviewLoader                 $productReviewLoader,
  76.         SystemConfigService                 $systemConfigService,
  77.         OfferSimulationService              $offerSimulationService,
  78.         EntityRepositoryInterface           $mediaRepository,
  79.         IndustriesResolverService           $industries,
  80.         SalesChannelCmsPageLoader           $cmsPageLoader,
  81.         SalesChannelProductDefinition       $productDefinition
  82.     )
  83.     {
  84.         parent::__construct($productPageLoader,
  85.             $combinationFinder,
  86.             $minimalQuickViewPageLoader,
  87.             $productReviewSaveRoute,
  88.             $seoUrlPlaceholderHandler,
  89.             $productReviewLoader,
  90.             $systemConfigService);
  91.         $this->productRepository $productRepository;
  92.         $this->productPageLoader $productPageLoader;
  93.         $this->productLoadedSerialNumberSubscriber $productLoadedSerialNumberSubscriber;
  94.         $this->offerSimulationService $offerSimulationService;
  95.         $this->systemConfigService $systemConfigService;
  96.         $this->mediaRepository $mediaRepository;
  97.         $this->industries $industries;
  98.         $this->cmsPageLoader $cmsPageLoader;
  99.         $this->productDefinition $productDefinition;
  100.     }
  101.     /**
  102.      * @Since("6.3.3.0")
  103.      * @HttpCache()
  104.      * @Route("/detail/{productId}/media/{mediaId}", name="frontend.detail.page.media", methods={"GET"})
  105.      * @Route("/detail/{productId}", name="frontend.detail.page", methods={"GET"})
  106.      * @throws GuzzleException
  107.      */
  108.     public function index(SalesChannelContext $contextRequest $request): Response
  109.     {
  110.         $page $this->productPageLoader->load($request$context);
  111.         $product $page->getProduct();
  112.         $media null;
  113.         if ($request->attributes->has('mediaId')) {
  114.             $mediaId $request->attributes->get('mediaId');
  115.             $media $this->mediaRepository->search(new Criteria([$mediaId]), $context->getContext())->first();
  116.         }
  117.         $ratingSuccess $request->get('success');
  118.         if ($this->systemConfigService->get(Defaults::SAP_ACTIVATION_KEY$context->getSalesChannelId())) {
  119.             try {
  120.                 $this->offerSimulationService->setProductPriceFromSap($product$context);
  121.             } catch (OfferSimulationException $exception) {
  122.                 $this->addFlash(parent::DANGER$exception->getMessage());
  123.                 withScope(function (Scope $scope) use ($exception){
  124.                     $scope->setContext("OfferSimulation"$exception->getContext());
  125.                     captureException($exception);
  126.                 });
  127.                 $productDetailPage $this->getProductDetailPageToRender($page$context$media$ratingSuccess);
  128.                 $parameters $productDetailPage['parameters'];
  129.                 $parameters['offerSimulationError'] = true;
  130.                 return $this->renderStorefront($productDetailPage['url'], $parameters);
  131.             }
  132.         }
  133.         $this->hook(new ProductPageLoadedHook($page$context));
  134.         $productDetailPage $this->getProductDetailPageToRender($page$context$media$ratingSuccess);
  135.         $parameters $productDetailPage['parameters'];
  136.         return $this->renderStorefront($productDetailPage['url'], $parameters);
  137.     }
  138.     /**
  139.      * @Since("6.0.0.0")
  140.      * @LoginRequired()
  141.      * @CustomerNeedsPasswordChange()
  142.      * @Route("/product/{productId}/rating", name="frontend.detail.review.save", methods={"POST"}, defaults={"XmlHttpRequest"=true})
  143.      *
  144.      * @throws CustomerNeedsPasswordChangeException
  145.      */
  146.     public function saveReview(string $productIdRequestDataBag $dataSalesChannelContext $context): Response
  147.     {
  148.         return parent::saveReview($productId$data$context);
  149.     }
  150.     /**
  151.      * @Route("/detail/info/{productNumber}", name="frontend.detail.info", options={"seo"="false"}, methods={"GET"}, defaults={"XmlHttpRequest"=true})
  152.      * @Route("/detail/info/{productNumber}/{serialNumber}", name="frontend.detail.info.serial", options={"seo"="false"}, methods={"GET"}, defaults={"XmlHttpRequest"=true})
  153.      * @param Request $request
  154.      * @param SalesChannelContext $context
  155.      * @return JsonResponse
  156.      */
  157.     public function showProductInformation(Request $requestSalesChannelContext $context): Response
  158.     {
  159.         // todo: introduce custom page type, not using ProductPage (better caching etc)!
  160.         $serialNumber $request->attributes->get('serialNumber');
  161.         $productNumber $request->attributes->get('productNumber');
  162.         if ($serialNumber) {
  163.             $this->productLoadedSerialNumberSubscriber->setSerialNumber($serialNumber);
  164.         }
  165.         $criteria = new Criteria();
  166.         $criteria->addFilter(new EqualsFilter('productNumber'$productNumber));
  167.         $productId $this->productRepository->searchIds($criteria$context->getContext())->firstId();
  168.         $request->attributes->add(['productId' => $productId]);
  169.         $page $this->productPageLoader->load($request$context);
  170.         $pageId $this->systemConfigService->get('SamsonCustomer.config.cmsTechnicalProductPage'$context->getSalesChannelId());
  171.         $resolverContext = new EntityResolverContext($context$request$this->productDefinition, clone $page->getProduct());
  172.         /** @var CmsPageEntity $technicalCmsPage */
  173.         $technicalCmsPage $this->cmsPageLoader->load(
  174.             $request,
  175.             new Criteria([$pageId]),
  176.             $context,
  177.             $page->getProduct()->getTranslation('slotConfig'),
  178.             $resolverContext)->first();
  179.         $page->setCmsPage($technicalCmsPage);
  180.         return $this->renderStorefront('@Storefront/storefront/page/content/product-detail.html.twig', ['page' => $page]);
  181.     }
  182.     private function getProductDetailPageToRender(ProductPage $pageSalesChannelContext $context$media$ratingSuccess): array
  183.     {
  184.         // Fallback layout for non-assigned product layout
  185.         if (!$page->getCmsPage()) {
  186.             $industries $this->industries->loadIndustries($page->getProduct(), $context);
  187.             if ($industries !== null) {
  188.                 $page->getProduct()->addExtension('industries'$industries);
  189.             }
  190.             return [
  191.                 'url' => '@Storefront/storefront/page/product-detail/index.html.twig',
  192.                 'parameters' => [
  193.                     'page' => $page,
  194.                     'media' => $media,
  195.                     'ratingSuccess' => $ratingSuccess
  196.                 ]
  197.             ];
  198.         }
  199.         return [
  200.             'url' => '@Storefront/storefront/page/content/product-detail.html.twig',
  201.             'parameters' => [
  202.                 'page' => $page,
  203.                 'media' => $media
  204.             ]
  205.         ];
  206.     }
  207. }