Passed
Push — master ( 527243...f676e6 )
by Christian
13:39 queued 11s
created

ProductPageLoader::load()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 44
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
cc 6
eloc 26
nc 4
nop 2
dl 0
loc 44
rs 8.8817
c 0
b 0
f 0
ccs 0
cts 0
cp 0
crap 42
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Storefront\Page\Product;
4
5
use Shopware\Core\Content\Category\Exception\CategoryNotFoundException;
6
use Shopware\Core\Content\Cms\CmsPageEntity;
7
use Shopware\Core\Content\Cms\DataResolver\CmsSlotsDataResolver;
8
use Shopware\Core\Content\Cms\DataResolver\ResolverContext\EntityResolverContext;
9
use Shopware\Core\Content\Cms\SalesChannel\SalesChannelCmsPageRepository;
10
use Shopware\Core\Content\Product\Exception\ProductNotFoundException;
11
use Shopware\Core\Content\Product\ProductDefinition;
12
use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
13
use Shopware\Core\Content\Property\Aggregate\PropertyGroupOption\PropertyGroupOptionCollection;
14
use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
15
use Shopware\Core\Framework\Feature;
16
use Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException;
17
use Shopware\Core\System\SalesChannel\SalesChannelContext;
18
use Shopware\Storefront\Page\GenericPageLoaderInterface;
19
use Shopware\Storefront\Page\Product\CrossSelling\CrossSellingLoader;
20
use Shopware\Storefront\Page\Product\Review\ProductReviewLoader;
21
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
22
use Symfony\Component\HttpFoundation\Request;
23
24
class ProductPageLoader
25
{
26
    /**
27
     * @var GenericPageLoaderInterface
28
     */
29
    private $genericLoader;
30
31
    /**
32
     * @var EventDispatcherInterface
33
     */
34
    private $eventDispatcher;
35
36
    /**
37
     * @var SalesChannelCmsPageRepository
38
     */
39
    private $cmsPageRepository;
40
41
    /**
42
     * @var CmsSlotsDataResolver
43
     */
44
    private $slotDataResolver;
45
46
    /**
47
     * @var ProductDefinition
48
     */
49
    private $productDefinition;
50
51
    /**
52
     * @var ProductLoader
53
     */
54
    private $productLoader;
55
56
    /**
57
     * @var ProductReviewLoader
58
     */
59
    private $productReviewLoader;
60
61
    /**
62
     * @var CrossSellingLoader
63
     */
64
    private $crossSellingLoader;
65
66
    public function __construct(
67
        GenericPageLoaderInterface $genericLoader,
68
        EventDispatcherInterface $eventDispatcher,
69
        SalesChannelCmsPageRepository $cmsPageRepository,
70
        CmsSlotsDataResolver $slotDataResolver,
71
        ProductDefinition $productDefinition,
72
        ProductLoader $productLoader,
73
        ProductReviewLoader $productReviewLoader,
74
        CrossSellingLoader $crossSellingLoader
75
    ) {
76
        $this->genericLoader = $genericLoader;
77
        $this->eventDispatcher = $eventDispatcher;
78
        $this->cmsPageRepository = $cmsPageRepository;
79
        $this->slotDataResolver = $slotDataResolver;
80
        $this->productDefinition = $productDefinition;
81
        $this->productLoader = $productLoader;
82
        $this->productReviewLoader = $productReviewLoader;
83
        $this->crossSellingLoader = $crossSellingLoader;
84
    }
85
86
    /**
87
     * @throws CategoryNotFoundException
88
     * @throws InconsistentCriteriaIdsException
89
     * @throws MissingRequestParameterException
90
     * @throws ProductNotFoundException
91
     */
92
    public function load(Request $request, SalesChannelContext $context): ProductPage
93
    {
94
        $page = $this->genericLoader->load($request, $context);
95
        $page = ProductPage::createFrom($page);
96
97
        $productId = $request->attributes->get('productId');
98
        if (!$productId) {
99
            throw new MissingRequestParameterException('productId', '/productId');
100
        }
101
102
        $product = $this->productLoader->load($productId, $context, ProductPageCriteriaEvent::class);
103
        $page->setProduct($product);
104
        $page->setConfiguratorSettings($product->getConfigurator());
0 ignored issues
show
Bug introduced by
It seems like $product->getConfigurator() can also be of type null; however, parameter $configuratorSettings of Shopware\Storefront\Page...tConfiguratorSettings() does only seem to accept Shopware\Core\Content\Pr...PropertyGroupCollection, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

104
        $page->setConfiguratorSettings(/** @scrutinizer ignore-type */ $product->getConfigurator());
Loading history...
Deprecated Code introduced by
The function Shopware\Core\Content\Pr...tity::getConfigurator() has been deprecated: tag:v6.4.0 - Only used for backward compatibility ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

104
        $page->setConfiguratorSettings(/** @scrutinizer ignore-deprecated */ $product->getConfigurator());

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.

Loading history...
105
106
        if (Feature::isActive('FEATURE_NEXT_10078') && $cmsPage = $product->getCmsPage()) {
107
            $page->setCmsPage($cmsPage);
108
        } else {
109
            $request->request->set('parentId', $product->getParentId());
110
            $reviews = $this->productReviewLoader->load($request, $context);
111
            $reviews->setParentId($product->getParentId() ?? $product->getId());
112
113
            $page->setReviews($reviews);
114
115
            $page->setCrossSellings(
116
                $this->crossSellingLoader->load($product->getId(), $context)
117
            );
118
119
            /** @var string $cmsPageId */
120
            $cmsPageId = $product->getCmsPageId();
121
122
            if ($cmsPageId !== null && $cmsPage = $this->getCmsPage($cmsPageId, $context)) {
123
                $this->loadSlotData($cmsPage, $context, $product, $request);
124
                $page->setCmsPage($cmsPage);
125
            }
126
        }
127
128
        $this->loadOptions($page);
129
        $this->loadMetaData($page);
130
131
        $this->eventDispatcher->dispatch(
132
            new ProductPageLoadedEvent($page, $context, $request)
133
        );
134
135
        return $page;
136
    }
137
138
    private function loadOptions(ProductPage $page): void
139
    {
140
        $options = new PropertyGroupOptionCollection();
141
        $optionIds = $page->getProduct()->getOptionIds();
142
143
        foreach ($page->getConfiguratorSettings() as $group) {
144
            $groupOptions = $group->getOptions();
145
            if ($groupOptions === null) {
146
                continue;
147
            }
148
            foreach ($optionIds as $optionId) {
149
                if ($groupOptions->has($optionId)) {
150
                    $options->add($groupOptions->get($optionId));
151
                }
152
            }
153
        }
154
155
        $page->setSelectedOptions($options);
156
    }
157
158
    private function loadMetaData(ProductPage $page): void
159
    {
160
        $metaInformation = $page->getMetaInformation();
161
162
        $metaDescription = $page->getProduct()->getTranslation('metaDescription')
163
            ?? $page->getProduct()->getTranslation('description');
164
        $metaInformation->setMetaDescription((string) $metaDescription);
165
166
        $metaInformation->setMetaKeywords((string) $page->getProduct()->getTranslation('keywords'));
167
168
        if ((string) $page->getProduct()->getTranslation('metaTitle') !== '') {
169
            $metaInformation->setMetaTitle((string) $page->getProduct()->getTranslation('metaTitle'));
170
171
            return;
172
        }
173
174
        $metaTitleParts = [$page->getProduct()->getTranslation('name')];
175
176
        foreach ($page->getSelectedOptions() as $option) {
177
            $metaTitleParts[] = $option->getTranslation('name');
178
        }
179
180
        $metaTitleParts[] = $page->getProduct()->getProductNumber();
181
182
        $metaInformation->setMetaTitle(implode(' | ', $metaTitleParts));
183
    }
184
185
    private function loadSlotData(
186
        CmsPageEntity $page,
187
        SalesChannelContext $salesChannelContext,
188
        SalesChannelProductEntity $product,
189
        Request $request
190
    ): void {
191
        if (!$page->getSections()) {
192
            return;
193
        }
194
195
        $resolverContext = new EntityResolverContext($salesChannelContext, $request, $this->productDefinition, $product);
196
197
        foreach ($page->getSections() as $section) {
198
            $slots = $this->slotDataResolver->resolve($section->getBlocks()->getSlots(), $resolverContext);
199
            $section->getBlocks()->setSlots($slots);
200
        }
201
    }
202
203
    private function getCmsPage(string $cmsPageId, SalesChannelContext $context): ?CmsPageEntity
204
    {
205
        $pages = $this->cmsPageRepository->read([$cmsPageId], $context);
206
207
        if ($pages->count() === 0) {
208
            return null;
209
        }
210
211
        /** @var CmsPageEntity $page */
212
        $page = $pages->first();
213
214
        return $page;
215
    }
216
}
217