Passed
Push — master ( 619744...1270d0 )
by Christian
12:47 queued 17s
created

recompileThemesIfNecessary()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 12
c 1
b 0
f 0
nc 4
nop 3
dl 0
loc 20
rs 9.5555
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Storefront\Theme;
4
5
use Shopware\Core\Framework\Context;
6
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
7
use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
8
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
9
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
10
use Shopware\Core\System\SalesChannel\SalesChannelCollection;
11
use Shopware\Storefront\Theme\Exception\ThemeAssignmentException;
12
use Shopware\Storefront\Theme\StorefrontPluginConfiguration\StorefrontPluginConfiguration;
13
use Shopware\Storefront\Theme\StorefrontPluginConfiguration\StorefrontPluginConfigurationCollection;
14
15
class ThemeLifecycleHandler
16
{
17
    /**
18
     * @var ThemeLifecycleService
19
     */
20
    private $themeLifecycleService;
21
22
    /**
23
     * @var ThemeService
24
     */
25
    private $themeService;
26
27
    /**
28
     * @var EntityRepositoryInterface
29
     */
30
    private $salesChannelRepository;
31
32
    /**
33
     * @var EntityRepositoryInterface
34
     */
35
    private $themeRepository;
36
37
    /**
38
     * @var StorefrontPluginRegistryInterface
39
     */
40
    private $storefrontPluginRegistry;
41
42
    public function __construct(
43
        ThemeLifecycleService $themeLifecycleService,
44
        ThemeService $themeService,
45
        EntityRepositoryInterface $salesChannelRepository,
46
        EntityRepositoryInterface $themeRepository,
47
        StorefrontPluginRegistryInterface $storefrontPluginRegistry
48
    ) {
49
        $this->themeLifecycleService = $themeLifecycleService;
50
        $this->themeService = $themeService;
51
        $this->salesChannelRepository = $salesChannelRepository;
52
        $this->themeRepository = $themeRepository;
53
        $this->storefrontPluginRegistry = $storefrontPluginRegistry;
54
    }
55
56
    public function handleThemeInstallOrUpdate(
57
        StorefrontPluginConfiguration $config,
58
        StorefrontPluginConfigurationCollection $configurationCollection,
59
        Context $context
60
    ): void {
61
        if ($config->getIsTheme()) {
62
            $this->themeLifecycleService->refreshTheme($config, $context);
63
            $this->changeThemeActive($config->getTechnicalName(), true, $context);
64
        }
65
66
        $this->recompileThemesIfNecessary($config, $context, $configurationCollection);
67
    }
68
69
    public function handleThemeUninstall(StorefrontPluginConfiguration $config, Context $context): void
70
    {
71
        if ($config->getIsTheme()) {
72
            // throw an exception if theme is still assigned to a sales channel
73
            $this->validateThemeAssignment($config->getTechnicalName(), $context);
74
75
            // set active = false in the database to theme and all children
76
            $this->changeThemeActive($config->getTechnicalName(), false, $context);
77
        }
78
79
        $configs = $this->storefrontPluginRegistry->getConfigurations();
80
        $configs = $configs->filter(function (StorefrontPluginConfiguration $registeredConfig) use ($config): bool {
81
            return $registeredConfig->getTechnicalName() !== $config->getTechnicalName();
82
        });
83
84
        $this->recompileThemesIfNecessary($config, $context, $configs);
85
    }
86
87
    /**
88
     * @throws ThemeAssignmentException
89
     * @throws InconsistentCriteriaIdsException
90
     */
91
    private function validateThemeAssignment(string $technicalName, Context $context): void
92
    {
93
        $criteria = new Criteria();
94
        $criteria->addAssociation('salesChannels');
95
        $criteria->addFilter(new EqualsFilter('technicalName', $technicalName));
96
        /** @var ThemeEntity|null $theme */
97
        $theme = $this->themeRepository->search($criteria, $context)->first();
98
99
        if (!$theme) {
100
            return;
101
        }
102
103
        $themeSalesChannel = [];
104
        if ($theme->getSalesChannels() && $theme->getSalesChannels()->count() > 0) {
105
            $themeSalesChannel[$technicalName] = $this->getSalesChannelNames($theme->getSalesChannels());
106
        }
107
108
        $criteria = new Criteria();
109
        $criteria->addFilter(new EqualsFilter('parentThemeId', $theme->getId()));
110
        $criteria->addAssociation('salesChannels');
111
        /** @var ThemeCollection|null $childThemes */
112
        $childThemes = $this->themeRepository->search($criteria, $context);
113
114
        $childThemeSalesChannel = [];
115
        if ($childThemes && $childThemes->count() > 0) {
116
            foreach ($childThemes as $childTheme) {
117
                if (!$childTheme->getSalesChannels() || $childTheme->getSalesChannels()->count() === 0) {
118
                    continue;
119
                }
120
                $childThemeSalesChannel[$childTheme->getName()] = $this->getSalesChannelNames($childTheme->getSalesChannels());
121
            }
122
        }
123
124
        if (count($themeSalesChannel) === 0 && count($childThemeSalesChannel) === 0) {
125
            return;
126
        }
127
128
        throw new ThemeAssignmentException($technicalName, $themeSalesChannel, $childThemeSalesChannel);
129
    }
130
131
    private function getSalesChannelNames(SalesChannelCollection $salesChannels): array
132
    {
133
        $names = [];
134
        foreach ($salesChannels as $salesChannel) {
135
            $names[] = $salesChannel->getName();
136
        }
137
138
        return $names;
139
    }
140
141
    private function changeThemeActive(string $technicalName, bool $active, Context $context): void
142
    {
143
        $criteria = new Criteria();
144
        $criteria->addFilter(new EqualsFilter('technicalName', $technicalName));
145
        $criteria->addAssociation('childThemes');
146
        /** @var ThemeEntity|null $theme */
147
        $theme = $this->themeRepository->search($criteria, $context)->first();
148
149
        if (!$theme) {
150
            return;
151
        }
152
153
        $data = [];
154
        $data[] = ['id' => $theme->getId(), 'active' => $active];
155
        if ($theme->getChildThemes()) {
156
            foreach ($theme->getChildThemes()->getIds() as $id) {
157
                $data[] = ['id' => $id, 'active' => $active];
158
            }
159
        }
160
161
        if (count($data)) {
162
            $this->themeRepository->update($data, $context);
163
        }
164
    }
165
166
    private function getSalesChannels(Context $context): SalesChannelCollection
167
    {
168
        $criteria = new Criteria();
169
        $criteria->addAssociation('themes');
170
171
        /** @var SalesChannelCollection $result */
172
        $result = $this->salesChannelRepository->search($criteria, $context)->getEntities();
173
174
        return $result;
175
    }
176
177
    private function recompileThemesIfNecessary(StorefrontPluginConfiguration $config, Context $context, StorefrontPluginConfigurationCollection $configurationCollection): void
178
    {
179
        if (!$config->hasFilesToCompile()) {
180
            return;
181
        }
182
183
        $salesChannels = $this->getSalesChannels($context);
184
185
        foreach ($salesChannels as $salesChannel) {
186
            /** @var ThemeCollection|null $themes */
187
            $themes = $salesChannel->getExtensionOfType('themes', ThemeCollection::class);
188
            if (!$themes || !$theme = $themes->first()) {
189
                continue;
190
            }
191
192
            $this->themeService->compileTheme(
193
                $salesChannel->getId(),
194
                $theme->getId(),
195
                $context,
196
                $configurationCollection
197
            );
198
        }
199
    }
200
}
201