vendor/shopware/storefront/Controller/ProductController.php line 92

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Storefront\Controller;
  3. use Shopware\Core\Content\Product\Exception\ReviewNotActiveExeption;
  4. use Shopware\Core\Content\Product\SalesChannel\ProductReviewService;
  5. use Shopware\Core\Content\Seo\SeoUrlPlaceholderHandlerInterface;
  6. use Shopware\Core\Framework\Feature;
  7. use Shopware\Core\Framework\Routing\Annotation\LoginRequired;
  8. use Shopware\Core\Framework\Routing\Annotation\RouteScope;
  9. use Shopware\Core\Framework\Routing\Annotation\Since;
  10. use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
  11. use Shopware\Core\Framework\Validation\Exception\ConstraintViolationException;
  12. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  13. use Shopware\Core\System\SystemConfig\SystemConfigService;
  14. use Shopware\Storefront\Framework\Cache\Annotation\HttpCache;
  15. use Shopware\Storefront\Framework\Routing\RequestTransformer;
  16. use Shopware\Storefront\Page\Product\Configurator\ProductCombinationFinder;
  17. use Shopware\Storefront\Page\Product\ProductPageLoader;
  18. use Shopware\Storefront\Page\Product\QuickView\MinimalQuickViewPageLoader;
  19. use Shopware\Storefront\Page\Product\Review\ProductReviewLoader;
  20. use Symfony\Component\HttpFoundation\JsonResponse;
  21. use Symfony\Component\HttpFoundation\Request;
  22. use Symfony\Component\HttpFoundation\Response;
  23. use Symfony\Component\Routing\Annotation\Route;
  24. /**
  25.  * @RouteScope(scopes={"storefront"})
  26.  */
  27. class ProductController extends StorefrontController
  28. {
  29.     /**
  30.      * @var ProductPageLoader
  31.      */
  32.     private $productPageLoader;
  33.     /**
  34.      * @var ProductCombinationFinder
  35.      */
  36.     private $combinationFinder;
  37.     /**
  38.      * @var MinimalQuickViewPageLoader
  39.      */
  40.     private $minimalQuickViewPageLoader;
  41.     /**
  42.      * @var ProductReviewService
  43.      */
  44.     private $productReviewService;
  45.     /**
  46.      * @var SeoUrlPlaceholderHandlerInterface
  47.      */
  48.     private $seoUrlPlaceholderHandler;
  49.     /**
  50.      * @var ProductReviewLoader
  51.      */
  52.     private $productReviewLoader;
  53.     /**
  54.      * @var SystemConfigService
  55.      */
  56.     private $systemConfigService;
  57.     public function __construct(
  58.         ProductPageLoader $productPageLoader,
  59.         ProductCombinationFinder $combinationFinder,
  60.         MinimalQuickViewPageLoader $minimalQuickViewPageLoader,
  61.         ProductReviewService $productReviewService,
  62.         SeoUrlPlaceholderHandlerInterface $seoUrlPlaceholderHandler,
  63.         ProductReviewLoader $productReviewLoader,
  64.         SystemConfigService $systemConfigService
  65.     ) {
  66.         $this->productPageLoader $productPageLoader;
  67.         $this->combinationFinder $combinationFinder;
  68.         $this->minimalQuickViewPageLoader $minimalQuickViewPageLoader;
  69.         $this->productReviewService $productReviewService;
  70.         $this->seoUrlPlaceholderHandler $seoUrlPlaceholderHandler;
  71.         $this->productReviewLoader $productReviewLoader;
  72.         $this->systemConfigService $systemConfigService;
  73.     }
  74.     /**
  75.      * @Since("6.3.3.0")
  76.      * @HttpCache()
  77.      * @Route("/detail/{productId}", name="frontend.detail.page", methods={"GET"})
  78.      */
  79.     public function index(SalesChannelContext $contextRequest $request): Response
  80.     {
  81.         $page $this->productPageLoader->load($request$context);
  82.         $ratingSuccess $request->get('success');
  83.         if (!Feature::isActive('FEATURE_NEXT_10078')) {
  84.             return $this->renderStorefront('@Storefront/storefront/page/product-detail/index.html.twig', ['page' => $page'ratingSuccess' => $ratingSuccess]);
  85.         }
  86.         // Fallback layout for non-assigned product layout
  87.         if (!$page->getCmsPage()) {
  88.             return $this->renderStorefront('@Storefront/storefront/page/product-detail/index.html.twig', ['page' => $page'ratingSuccess' => $ratingSuccess]);
  89.         }
  90.         return $this->renderStorefront('@Storefront/storefront/page/content/product-detail.html.twig', ['page' => $page]);
  91.     }
  92.     /**
  93.      * @Since("6.0.0.0")
  94.      * @HttpCache()
  95.      * @Route("/detail/{productId}/switch", name="frontend.detail.switch", methods={"GET"}, defaults={"XmlHttpRequest": true})
  96.      */
  97.     public function switch(string $productIdRequest $requestSalesChannelContext $salesChannelContext): JsonResponse
  98.     {
  99.         $switchedOption $request->query->get('switched');
  100.         $newOptions json_decode($request->query->get('options'), true);
  101.         $redirect $this->combinationFinder->find($productId$switchedOption$newOptions$salesChannelContext);
  102.         $host $request->attributes->get(RequestTransformer::SALES_CHANNEL_ABSOLUTE_BASE_URL)
  103.             . $request->attributes->get(RequestTransformer::SALES_CHANNEL_BASE_URL);
  104.         $url $this->seoUrlPlaceholderHandler->replace(
  105.             $this->seoUrlPlaceholderHandler->generate(
  106.                 'frontend.detail.page',
  107.                 ['productId' => $redirect->getVariantId()]
  108.             ),
  109.             $host,
  110.             $salesChannelContext
  111.         );
  112.         return new JsonResponse(['url' => $url]);
  113.     }
  114.     /**
  115.      * @Since("6.0.0.0")
  116.      * @Route("/quickview/{productId}", name="widgets.quickview.minimal", methods={"GET"}, defaults={"XmlHttpRequest": true})
  117.      */
  118.     public function quickviewMinimal(Request $requestSalesChannelContext $context): Response
  119.     {
  120.         $page $this->minimalQuickViewPageLoader->load($request$context);
  121.         return $this->renderStorefront('@Storefront/storefront/component/product/quickview/minimal.html.twig', ['page' => $page]);
  122.     }
  123.     /**
  124.      * @Since("6.0.0.0")
  125.      * @LoginRequired()
  126.      * @Route("/product/{productId}/rating", name="frontend.detail.review.save", methods={"POST"}, defaults={"XmlHttpRequest"=true})
  127.      */
  128.     public function saveReview(string $productIdRequestDataBag $dataSalesChannelContext $context): Response
  129.     {
  130.         $this->checkReviewsActive($context);
  131.         try {
  132.             $this->productReviewService->save($productId$data$context);
  133.         } catch (ConstraintViolationException $formViolations) {
  134.             return $this->forwardToRoute('frontend.product.reviews', [
  135.                 'productId' => $productId,
  136.                 'success' => -1,
  137.                 'formViolations' => $formViolations,
  138.                 'data' => $data,
  139.             ], ['productId' => $productId]);
  140.         }
  141.         $forwardParams = [
  142.             'productId' => $productId,
  143.             'success' => 1,
  144.             'data' => $data,
  145.             'parentId' => $data->get('parentId'),
  146.         ];
  147.         if ($data->has('id')) {
  148.             $forwardParams['success'] = 2;
  149.         }
  150.         return $this->forwardToRoute('frontend.product.reviews'$forwardParams, ['productId' => $productId]);
  151.     }
  152.     /**
  153.      * @Since("6.0.0.0")
  154.      * @Route("/product/{productId}/reviews", name="frontend.product.reviews", methods={"GET","POST"}, defaults={"XmlHttpRequest"=true})
  155.      */
  156.     public function loadReviews(Request $requestRequestDataBag $dataSalesChannelContext $context): Response
  157.     {
  158.         $this->checkReviewsActive($context);
  159.         $reviews $this->productReviewLoader->load($request$context);
  160.         return $this->renderStorefront('storefront/page/product-detail/review/review.html.twig', [
  161.             'reviews' => $reviews,
  162.             'ratingSuccess' => $request->get('success'),
  163.         ]);
  164.     }
  165.     /**
  166.      * @throws ReviewNotActiveExeption
  167.      */
  168.     private function checkReviewsActive(SalesChannelContext $context): void
  169.     {
  170.         $showReview $this->systemConfigService->get('core.listing.showReview'$context->getSalesChannel()->getId());
  171.         if (!$showReview) {
  172.             throw new ReviewNotActiveExeption();
  173.         }
  174.     }
  175. }