src/Storefront/Controller/CmsController.php line 46

  1. <?php declare(strict_types=1);
  2. namespace Shopware\Storefront\Controller;
  3. use Shopware\Core\Content\Category\SalesChannel\AbstractCategoryRoute;
  4. use Shopware\Core\Content\Cms\Exception\PageNotFoundException;
  5. use Shopware\Core\Content\Cms\SalesChannel\AbstractCmsRoute;
  6. use Shopware\Core\Content\Product\SalesChannel\Detail\AbstractProductDetailRoute;
  7. use Shopware\Core\Content\Product\SalesChannel\FindVariant\AbstractFindProductVariantRoute;
  8. use Shopware\Core\Content\Product\SalesChannel\Listing\AbstractProductListingRoute;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  10. use Shopware\Core\Framework\Log\Package;
  11. use Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException;
  12. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  13. use Shopware\Storefront\Event\SwitchBuyBoxVariantEvent;
  14. use Shopware\Storefront\Page\Cms\CmsPageLoadedHook;
  15. use Shopware\Storefront\Page\Product\Review\ProductReviewLoader;
  16. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  17. use Symfony\Component\HttpFoundation\JsonResponse;
  18. use Symfony\Component\HttpFoundation\Request;
  19. use Symfony\Component\HttpFoundation\Response;
  20. use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener;
  21. use Symfony\Component\Routing\Annotation\Route;
  22. /**
  23.  * @internal
  24.  */
  25. #[Route(defaults: ['_routeScope' => ['storefront']])]
  26. #[Package('content')]
  27. class CmsController extends StorefrontController
  28. {
  29.     /**
  30.      * @internal
  31.      */
  32.     public function __construct(private readonly AbstractCmsRoute $cmsRoute, private readonly AbstractCategoryRoute $categoryRoute, private readonly AbstractProductListingRoute $listingRoute, private readonly AbstractProductDetailRoute $productRoute, private readonly ProductReviewLoader $productReviewLoader, private readonly AbstractFindProductVariantRoute $findVariantRoute, private readonly EventDispatcherInterface $eventDispatcher)
  33.     {
  34.     }
  35.     #[Route(path'/widgets/cms/{id}'name'frontend.cms.page'defaults: ['id' => null'XmlHttpRequest' => true'_httpCache' => true], methods: ['GET''POST'])]
  36.     public function page(?string $idRequest $requestSalesChannelContext $salesChannelContext): Response
  37.     {
  38.         if (!$id) {
  39.             throw new MissingRequestParameterException('id');
  40.         }
  41.         $page $this->cmsRoute->load($id$request$salesChannelContext)->getCmsPage();
  42.         $this->hook(new CmsPageLoadedHook($page$salesChannelContext));
  43.         $response $this->renderStorefront('@Storefront/storefront/page/content/detail.html.twig', ['cmsPage' => $page]);
  44.         $response->headers->set('x-robots-tag''noindex');
  45.         return $response;
  46.     }
  47.     /**
  48.      * Navigation id is required to load the slot config for the navigation
  49.      */
  50.     #[Route(path'/widgets/cms/navigation/{navigationId}'name'frontend.cms.navigation.page'defaults: ['navigationId' => null'XmlHttpRequest' => true], methods: ['GET''POST'])]
  51.     public function category(?string $navigationIdRequest $requestSalesChannelContext $salesChannelContext): Response
  52.     {
  53.         if (!$navigationId) {
  54.             throw new MissingRequestParameterException('navigationId');
  55.         }
  56.         $category $this->categoryRoute->load($navigationId$request$salesChannelContext)->getCategory();
  57.         $page $category->getCmsPage();
  58.         if (!$page) {
  59.             throw new PageNotFoundException('');
  60.         }
  61.         $this->hook(new CmsPageLoadedHook($page$salesChannelContext));
  62.         $response $this->renderStorefront('@Storefront/storefront/page/content/detail.html.twig', ['cmsPage' => $page]);
  63.         $response->headers->set('x-robots-tag''noindex');
  64.         return $response;
  65.     }
  66.     /**
  67.      * Route to load the listing filters
  68.      */
  69.     #[Route(path'/widgets/cms/navigation/{navigationId}/filter'name'frontend.cms.navigation.filter'defaults: ['XmlHttpRequest' => true'_routeScope' => ['storefront'], '_httpCache' => true], methods: ['GET''POST'])]
  70.     public function filter(string $navigationIdRequest $requestSalesChannelContext $context): Response
  71.     {
  72.         // Allows to fetch only aggregations over the gateway.
  73.         $request->request->set('only-aggregations'true);
  74.         // Allows to convert all post-filters to filters. This leads to the fact that only aggregation values are returned, which are combinable with the previous applied filters.
  75.         $request->request->set('reduce-aggregations'true);
  76.         $listing $this->listingRoute
  77.             ->load($navigationId$request$context, new Criteria())
  78.             ->getResult();
  79.         $mapped = [];
  80.         foreach ($listing->getAggregations() as $aggregation) {
  81.             $mapped[$aggregation->getName()] = $aggregation;
  82.         }
  83.         $response = new JsonResponse($mapped);
  84.         $response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER'1');
  85.         $response->headers->set('x-robots-tag''noindex');
  86.         return $response;
  87.     }
  88.     /**
  89.      * Route to load the cms element buy box product config which assigned to the provided product id.
  90.      * Product id is required to load the slot config for the buy box
  91.      */
  92.     #[Route(path'/widgets/cms/buybox/{productId}/switch'name'frontend.cms.buybox.switch'defaults: ['productId' => null'XmlHttpRequest' => true'_routeScope' => ['storefront'], '_httpCache' => true], methods: ['GET'])]
  93.     public function switchBuyBoxVariant(string $productIdRequest $requestSalesChannelContext $context): Response
  94.     {
  95.         /** @var string $elementId */
  96.         $elementId $request->query->get('elementId');
  97.         /** @var string[]|null $options */
  98.         $options json_decode($request->query->get('options'''), true);
  99.         $variantResponse $this->findVariantRoute->load(
  100.             $productId,
  101.             new Request(
  102.                 [
  103.                     'switchedGroup' => $request->query->get('switched'),
  104.                     'options' => $options ?? [],
  105.                 ]
  106.             ),
  107.             $context
  108.         );
  109.         $newProductId $variantResponse->getFoundCombination()->getVariantId();
  110.         $result $this->productRoute->load($newProductId$request$context, new Criteria());
  111.         $product $result->getProduct();
  112.         $configurator $result->getConfigurator();
  113.         $request->request->set('parentId'$product->getParentId());
  114.         $request->request->set('productId'$product->getId());
  115.         $reviews $this->productReviewLoader->load($request$context);
  116.         $reviews->setParentId($product->getParentId() ?? $product->getId());
  117.         $event = new SwitchBuyBoxVariantEvent($elementId$product$configurator$request$context);
  118.         $this->eventDispatcher->dispatch($event);
  119.         $response $this->renderStorefront('@Storefront/storefront/component/buy-widget/buy-widget.html.twig', [
  120.             'product' => $product,
  121.             'configuratorSettings' => $configurator,
  122.             'totalReviews' => $reviews->getTotalReviews(),
  123.             'elementId' => $elementId,
  124.         ]);
  125.         $response->headers->set('x-robots-tag''noindex');
  126.         return $response;
  127.     }
  128. }