vendor/shopware/storefront/Controller/CmsController.php line 147

Open in your IDE?
  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\Feature;
  11. use Shopware\Core\Framework\Log\Package;
  12. use Shopware\Core\Framework\Routing\Annotation\Since;
  13. use Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException;
  14. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  15. use Shopware\Storefront\Event\SwitchBuyBoxVariantEvent;
  16. use Shopware\Storefront\Framework\Cache\Annotation\HttpCache;
  17. use Shopware\Storefront\Page\Cms\CmsPageLoadedHook;
  18. use Shopware\Storefront\Page\Product\Configurator\ProductCombinationFinder;
  19. use Shopware\Storefront\Page\Product\Review\ProductReviewLoader;
  20. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  21. use Symfony\Component\HttpFoundation\JsonResponse;
  22. use Symfony\Component\HttpFoundation\Request;
  23. use Symfony\Component\HttpFoundation\Response;
  24. use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener;
  25. use Symfony\Component\Routing\Annotation\Route;
  26. /**
  27. * @Route(defaults={"_routeScope"={"storefront"}})
  28. *
  29. * @deprecated tag:v6.5.0 - reason:becomes-internal - Will be internal
  30. */
  31. #[Package('content')]
  32. class CmsController extends StorefrontController
  33. {
  34. private AbstractCmsRoute $cmsRoute;
  35. private AbstractCategoryRoute $categoryRoute;
  36. private AbstractProductListingRoute $listingRoute;
  37. private AbstractProductDetailRoute $productRoute;
  38. private ProductReviewLoader $productReviewLoader;
  39. private EventDispatcherInterface $eventDispatcher;
  40. private AbstractFindProductVariantRoute $findVariantRoute;
  41. /**
  42. * @deprecated tag:v6.5.0 - will be removed
  43. */
  44. private ProductCombinationFinder $productCombinationFinder;
  45. /**
  46. * @internal
  47. */
  48. public function __construct(
  49. AbstractCmsRoute $cmsRoute,
  50. AbstractCategoryRoute $categoryRoute,
  51. AbstractProductListingRoute $listingRoute,
  52. AbstractProductDetailRoute $productRoute,
  53. ProductReviewLoader $productReviewLoader,
  54. AbstractFindProductVariantRoute $findVariantRoute,
  55. ProductCombinationFinder $productCombinationFinder,
  56. EventDispatcherInterface $eventDispatcher
  57. ) {
  58. $this->cmsRoute = $cmsRoute;
  59. $this->categoryRoute = $categoryRoute;
  60. $this->listingRoute = $listingRoute;
  61. $this->productRoute = $productRoute;
  62. $this->productReviewLoader = $productReviewLoader;
  63. $this->eventDispatcher = $eventDispatcher;
  64. $this->findVariantRoute = $findVariantRoute;
  65. $this->productCombinationFinder = $productCombinationFinder;
  66. }
  67. /**
  68. * @Since("6.0.0.0")
  69. * Route for cms data (used in XmlHttpRequest)
  70. *
  71. * @HttpCache()
  72. * @Route("/widgets/cms/{id}", name="frontend.cms.page", methods={"GET", "POST"}, defaults={"id"=null, "XmlHttpRequest"=true})
  73. */
  74. public function page(?string $id, Request $request, SalesChannelContext $salesChannelContext): Response
  75. {
  76. if (!$id) {
  77. throw new MissingRequestParameterException('id');
  78. }
  79. $page = $this->cmsRoute->load($id, $request, $salesChannelContext)->getCmsPage();
  80. $this->hook(new CmsPageLoadedHook($page, $salesChannelContext));
  81. $response = $this->renderStorefront('@Storefront/storefront/page/content/detail.html.twig', ['cmsPage' => $page]);
  82. $response->headers->set('x-robots-tag', 'noindex');
  83. return $response;
  84. }
  85. /**
  86. * @Since("6.0.0.0")
  87. * Route to load a cms page which assigned to the provided navigation id.
  88. * Navigation id is required to load the slot config for the navigation
  89. *
  90. * @Route("/widgets/cms/navigation/{navigationId}", name="frontend.cms.navigation.page", methods={"GET", "POST"}, defaults={"navigationId"=null, "XmlHttpRequest"=true})
  91. */
  92. public function category(?string $navigationId, Request $request, SalesChannelContext $salesChannelContext): Response
  93. {
  94. if (!$navigationId) {
  95. throw new MissingRequestParameterException('navigationId');
  96. }
  97. $category = $this->categoryRoute->load($navigationId, $request, $salesChannelContext)->getCategory();
  98. $page = $category->getCmsPage();
  99. if (!$page) {
  100. throw new PageNotFoundException('');
  101. }
  102. $this->hook(new CmsPageLoadedHook($page, $salesChannelContext));
  103. $response = $this->renderStorefront('@Storefront/storefront/page/content/detail.html.twig', ['cmsPage' => $page]);
  104. $response->headers->set('x-robots-tag', 'noindex');
  105. return $response;
  106. }
  107. /**
  108. * @Since("6.0.0.0")
  109. * @HttpCache()
  110. *
  111. * Route to load the listing filters
  112. *
  113. * @Route("/widgets/cms/navigation/{navigationId}/filter", name="frontend.cms.navigation.filter", methods={"GET", "POST"}, defaults={"XmlHttpRequest"=true, "_routeScope"={"storefront"}})
  114. */
  115. public function filter(string $navigationId, Request $request, SalesChannelContext $context): Response
  116. {
  117. // Allows to fetch only aggregations over the gateway.
  118. $request->request->set('only-aggregations', true);
  119. // 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.
  120. $request->request->set('reduce-aggregations', true);
  121. $listing = $this->listingRoute
  122. ->load($navigationId, $request, $context, new Criteria())
  123. ->getResult();
  124. $mapped = [];
  125. foreach ($listing->getAggregations() as $aggregation) {
  126. $mapped[$aggregation->getName()] = $aggregation;
  127. }
  128. $response = new JsonResponse($mapped);
  129. $response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, '1');
  130. $response->headers->set('x-robots-tag', 'noindex');
  131. return $response;
  132. }
  133. /**
  134. * @Since("6.4.0.0")
  135. * @HttpCache()
  136. *
  137. * Route to load the cms element buy box product config which assigned to the provided product id.
  138. * Product id is required to load the slot config for the buy box
  139. *
  140. * @Route("/widgets/cms/buybox/{productId}/switch", name="frontend.cms.buybox.switch", methods={"GET"}, defaults={"productId"=null, "XmlHttpRequest"=true, "_routeScope"={"storefront"}})
  141. */
  142. public function switchBuyBoxVariant(string $productId, Request $request, SalesChannelContext $context): Response
  143. {
  144. /** @var string $elementId */
  145. $elementId = $request->query->get('elementId');
  146. /** @var array|null $options */
  147. $options = json_decode($request->query->get('options', ''), true);
  148. if (Feature::isActive('v6.5.0.0')) {
  149. $variantResponse = $this->findVariantRoute->load(
  150. $productId,
  151. new Request(
  152. [
  153. 'switchedGroup' => $request->query->get('switched'),
  154. 'options' => $options ?? [],
  155. ]
  156. ),
  157. $context
  158. );
  159. $newProductId = $variantResponse->getFoundCombination()->getVariantId();
  160. } else {
  161. $finderResponse = $this->productCombinationFinder->find(
  162. $productId,
  163. $request->query->get('switched'),
  164. $options ?? [],
  165. $context
  166. );
  167. $newProductId = $finderResponse->getVariantId();
  168. }
  169. $result = $this->productRoute->load($newProductId, $request, $context, new Criteria());
  170. $product = $result->getProduct();
  171. $configurator = $result->getConfigurator();
  172. $request->request->set('parentId', $product->getParentId());
  173. $request->request->set('productId', $product->getId());
  174. $reviews = $this->productReviewLoader->load($request, $context);
  175. $reviews->setParentId($product->getParentId() ?? $product->getId());
  176. $event = new SwitchBuyBoxVariantEvent($elementId, $product, $configurator, $request, $context);
  177. $this->eventDispatcher->dispatch($event);
  178. $response = $this->renderStorefront('@Storefront/storefront/component/buy-widget/buy-widget.html.twig', [
  179. 'product' => $product,
  180. 'configuratorSettings' => $configurator,
  181. 'totalReviews' => $reviews->getTotalReviews(),
  182. 'elementId' => $elementId,
  183. ]);
  184. $response->headers->set('x-robots-tag', 'noindex');
  185. return $response;
  186. }
  187. }