1
|
|
|
<?php declare(strict_types=1); |
2
|
|
|
|
3
|
|
|
namespace Shopware\Storefront\Controller; |
4
|
|
|
|
5
|
|
|
use Shopware\Core\Content\Category\Exception\CategoryNotFoundException; |
6
|
|
|
use Shopware\Core\Content\Category\SalesChannel\AbstractCategoryRoute; |
7
|
|
|
use Shopware\Core\Content\Cms\Exception\PageNotFoundException; |
8
|
|
|
use Shopware\Core\Content\Cms\SalesChannel\AbstractCmsRoute; |
9
|
|
|
use Shopware\Core\Content\Product\Exception\ProductNotFoundException; |
10
|
|
|
use Shopware\Core\Content\Product\SalesChannel\Detail\AbstractProductDetailRoute; |
11
|
|
|
use Shopware\Core\Content\Product\SalesChannel\Detail\ProductConfiguratorLoader; |
12
|
|
|
use Shopware\Core\Content\Product\SalesChannel\Listing\AbstractProductListingRoute; |
13
|
|
|
use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException; |
14
|
|
|
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria; |
15
|
|
|
use Shopware\Core\Framework\Feature; |
16
|
|
|
use Shopware\Core\Framework\Routing\Annotation\RouteScope; |
17
|
|
|
use Shopware\Core\Framework\Routing\Annotation\Since; |
18
|
|
|
use Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException; |
19
|
|
|
use Shopware\Core\System\SalesChannel\SalesChannelContext; |
20
|
|
|
use Shopware\Storefront\Framework\Cache\Annotation\HttpCache; |
21
|
|
|
use Shopware\Storefront\Page\Product\Configurator\ProductCombinationFinder; |
22
|
|
|
use Shopware\Storefront\Page\Product\Review\ProductReviewLoader; |
23
|
|
|
use Symfony\Component\HttpFoundation\JsonResponse; |
24
|
|
|
use Symfony\Component\HttpFoundation\Request; |
25
|
|
|
use Symfony\Component\HttpFoundation\Response; |
26
|
|
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; |
27
|
|
|
use Symfony\Component\Routing\Annotation\Route; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @RouteScope(scopes={"storefront"}) |
31
|
|
|
*/ |
32
|
|
|
class CmsController extends StorefrontController |
33
|
|
|
{ |
34
|
|
|
/** |
35
|
|
|
* @var AbstractCmsRoute |
36
|
|
|
*/ |
37
|
|
|
private $cmsRoute; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @var AbstractCategoryRoute |
41
|
|
|
*/ |
42
|
|
|
private $categoryRoute; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* @var AbstractProductListingRoute |
46
|
|
|
*/ |
47
|
|
|
private $listingRoute; |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* @var AbstractProductDetailRoute |
51
|
|
|
*/ |
52
|
|
|
private $productRoute; |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* @var ProductConfiguratorLoader; |
56
|
|
|
*/ |
57
|
|
|
private $productConfiguratorLoader; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* @var ProductReviewLoader |
61
|
|
|
*/ |
62
|
|
|
private $productReviewLoader; |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* @var ProductCombinationFinder |
66
|
|
|
*/ |
67
|
|
|
private $combinationFinder; |
68
|
|
|
|
69
|
|
|
public function __construct( |
70
|
|
|
AbstractCmsRoute $cmsRoute, |
71
|
|
|
AbstractCategoryRoute $categoryRoute, |
72
|
|
|
AbstractProductListingRoute $listingRoute, |
73
|
|
|
AbstractProductDetailRoute $productRoute, |
74
|
|
|
ProductConfiguratorLoader $productConfiguratorLoader, |
75
|
|
|
ProductReviewLoader $productReviewLoader, |
76
|
|
|
ProductCombinationFinder $combinationFinder |
77
|
|
|
) { |
78
|
|
|
$this->cmsRoute = $cmsRoute; |
79
|
|
|
$this->categoryRoute = $categoryRoute; |
80
|
|
|
$this->listingRoute = $listingRoute; |
81
|
|
|
$this->productRoute = $productRoute; |
82
|
|
|
$this->productConfiguratorLoader = $productConfiguratorLoader; |
83
|
|
|
$this->productReviewLoader = $productReviewLoader; |
84
|
|
|
$this->combinationFinder = $combinationFinder; |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* @Since("6.0.0.0") |
89
|
|
|
* Route for cms data (used in XmlHttpRequest) |
90
|
|
|
* |
91
|
|
|
* @HttpCache() |
92
|
|
|
* @Route("/widgets/cms/{id}", name="frontend.cms.page", methods={"GET", "POST"}, defaults={"id"=null, "XmlHttpRequest"=true}) |
93
|
|
|
* |
94
|
|
|
* @throws InconsistentCriteriaIdsException |
95
|
|
|
* @throws MissingRequestParameterException |
96
|
|
|
* @throws PageNotFoundException |
97
|
|
|
*/ |
98
|
|
|
public function page(?string $id, Request $request, SalesChannelContext $salesChannelContext): Response |
99
|
|
|
{ |
100
|
|
|
if (!$id) { |
101
|
|
|
throw new MissingRequestParameterException('Parameter id missing'); |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
$cmsPage = $this->cmsRoute->load($id, $request, $salesChannelContext)->getCmsPage(); |
105
|
|
|
|
106
|
|
|
return $this->renderStorefront('@Storefront/storefront/page/content/detail.html.twig', ['cmsPage' => $cmsPage]); |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
/** |
110
|
|
|
* @Since("6.0.0.0") |
111
|
|
|
* Route to load a cms page which assigned to the provided navigation id. |
112
|
|
|
* Navigation id is required to load the slot config for the navigation |
113
|
|
|
* |
114
|
|
|
* @Route("/widgets/cms/navigation/{navigationId}", name="frontend.cms.navigation.page", methods={"GET", "POST"}, defaults={"navigationId"=null, "XmlHttpRequest"=true}) |
115
|
|
|
* |
116
|
|
|
* @throws CategoryNotFoundException |
117
|
|
|
* @throws MissingRequestParameterException |
118
|
|
|
* @throws PageNotFoundException |
119
|
|
|
* @throws InconsistentCriteriaIdsException |
120
|
|
|
*/ |
121
|
|
|
public function category(?string $navigationId, Request $request, SalesChannelContext $salesChannelContext): Response |
122
|
|
|
{ |
123
|
|
|
if (!$navigationId) { |
124
|
|
|
throw new MissingRequestParameterException('Parameter navigationId missing'); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
$category = $this->categoryRoute->load($navigationId, $request, $salesChannelContext)->getCategory(); |
128
|
|
|
|
129
|
|
|
if (!$category->getCmsPageId()) { |
130
|
|
|
throw new PageNotFoundException(''); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
return $this->renderStorefront('@Storefront/storefront/page/content/detail.html.twig', ['cmsPage' => $category->getCmsPage()]); |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* @Since("6.0.0.0") |
138
|
|
|
* @HttpCache() |
139
|
|
|
* |
140
|
|
|
* Route to load the listing filters |
141
|
|
|
* |
142
|
|
|
* @RouteScope(scopes={"storefront"}) |
143
|
|
|
* @Route("/widgets/cms/navigation/{navigationId}/filter", name="frontend.cms.navigation.filter", methods={"GET", "POST"}, defaults={"XmlHttpRequest"=true}) |
144
|
|
|
* |
145
|
|
|
* @throws MissingRequestParameterException |
146
|
|
|
*/ |
147
|
|
|
public function filter(string $navigationId, Request $request, SalesChannelContext $context): Response |
148
|
|
|
{ |
149
|
|
|
if (!$navigationId) { |
150
|
|
|
throw new MissingRequestParameterException('Parameter navigationId missing'); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
// Allows to fetch only aggregations over the gateway. |
154
|
|
|
$request->request->set('only-aggregations', true); |
155
|
|
|
|
156
|
|
|
// 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. |
157
|
|
|
$request->request->set('reduce-aggregations', true); |
158
|
|
|
|
159
|
|
|
$listing = $this->listingRoute |
|
|
|
|
160
|
|
|
->load($navigationId, $request, $context, new Criteria()) |
|
|
|
|
161
|
|
|
->getResult(); |
162
|
|
|
|
163
|
|
|
$mapped = []; |
164
|
|
|
foreach ($listing->getAggregations() as $aggregation) { |
165
|
|
|
$mapped[$aggregation->getName()] = $aggregation; |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
return new JsonResponse($mapped); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* @internal (flag:FEATURE_NEXT_10078) |
173
|
|
|
* @Since("6.3.5.0") |
174
|
|
|
* @HttpCache() |
175
|
|
|
* |
176
|
|
|
* Route to load the cms element buy box product config which assigned to the provided product id. |
177
|
|
|
* Product id is required to load the slot config for the buy box |
178
|
|
|
* |
179
|
|
|
* @RouteScope(scopes={"storefront"}) |
180
|
|
|
* @Route("/widgets/cms/buybox/{productId}/switch", name="frontend.cms.buybox.switch", methods={"GET"}, defaults={"productId"=null, "XmlHttpRequest"=true}) |
181
|
|
|
* |
182
|
|
|
* @throws MissingRequestParameterException |
183
|
|
|
* @throws ProductNotFoundException |
184
|
|
|
*/ |
185
|
|
|
public function switchBuyBoxVariant(string $productId, Request $request, SalesChannelContext $context): Response |
186
|
|
|
{ |
187
|
|
|
if (!Feature::isActive('FEATURE_NEXT_10078')) { |
188
|
|
|
throw new NotFoundHttpException(); |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
if (!$productId) { |
192
|
|
|
throw new MissingRequestParameterException('Parameter productId missing'); |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
/** @var string $switchedOption */ |
196
|
|
|
$switchedOption = $request->query->get('switched'); |
197
|
|
|
|
198
|
|
|
/** @var string $elementId */ |
199
|
|
|
$elementId = $request->query->get('elementId'); |
200
|
|
|
|
201
|
|
|
/** @var array $newOptions */ |
202
|
|
|
$newOptions = json_decode($request->query->get('options'), true); |
203
|
|
|
|
204
|
|
|
$redirect = $this->combinationFinder->find($productId, $switchedOption, $newOptions, $context); |
205
|
|
|
|
206
|
|
|
$newProductId = $redirect->getVariantId(); |
207
|
|
|
|
208
|
|
|
$result = $this->productRoute->load($newProductId, $request, $context, new Criteria()); |
209
|
|
|
$product = $result->getProduct(); |
210
|
|
|
$configurator = $this->productConfiguratorLoader->load($product, $context); |
211
|
|
|
|
212
|
|
|
$request->request->set('parentId', $product->getParentId()); |
213
|
|
|
$request->request->set('productId', $product->getId()); |
214
|
|
|
$reviews = $this->productReviewLoader->load($request, $context); |
215
|
|
|
$reviews->setParentId($product->getParentId() ?? $product->getId()); |
216
|
|
|
|
217
|
|
|
return $this->renderStorefront('@Storefront/storefront/component/buy-widget/buy-widget.html.twig', [ |
218
|
|
|
'product' => $product, |
219
|
|
|
'configuratorSettings' => $configurator, |
220
|
|
|
'totalReviews' => $reviews->getTotalReviews(), |
221
|
|
|
'elementId' => $elementId, |
222
|
|
|
]); |
223
|
|
|
} |
224
|
|
|
} |
225
|
|
|
|
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.