Completed
Pull Request — master (#474)
by Christian
05:11
created

VariantConfigurator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 2
1
<?php
2
/**
3
 * (c) shopware AG <[email protected]>
4
 * For the full copyright and license information, please view the LICENSE
5
 * file that was distributed with this source code.
6
 */
7
8
namespace ShopwarePlugins\Connect\Components;
9
10
use Doctrine\Common\Collections\ArrayCollection;
11
use ShopwarePlugins\Connect\Components\Gateway\ProductTranslationsGateway;
12
use ShopwarePlugins\Connect\Components\Translations\LocaleMapper;
13
use Shopware\Components\Model\ModelManager;
14
use Shopware\Connect\Struct\Product;
15
use Shopware\Models\Article\Detail;
16
use Shopware\Models\Article\Configurator\Group;
17
use Shopware\Models\Article\Configurator\Option;
18
use Shopware\Models\Article\Configurator\Set;
19
20
/**
21
 * @category  Shopware
22
 * @package   Shopware\Plugins\SwagConnect
23
 */
24
class VariantConfigurator
25
{
26
    /**
27
     * @var ModelManager
28
     */
29
    private $manager;
30
31
    private $translationGateway;
32
33
    private $localeRepository;
34
35
    private $shopRepository;
36
37
    public function __construct(ModelManager $manager, ProductTranslationsGateway $translationsGateway)
38
    {
39
        $this->manager = $manager;
40
        $this->translationGateway = $translationsGateway;
41
    }
42
43
    /**
44
     * Configure variant group, options and configurator set
45
     *
46
     * @param \Shopware\Connect\Struct\Product $product
47
     * @param \Shopware\Models\Article\Detail $detail
48
     */
49
    public function configureVariantAttributes(Product $product, Detail $detail)
50
    {
51
        if (count($product->variant) === 0) {
52
            return;
53
        }
54
55
        $article = $detail->getArticle();
56
        $detailOptions = $detail->getConfiguratorOptions();
57
        if (!$article->getConfiguratorSet()) {
58
            $configSet = new Set();
59
            $configSet->setName('Set-' . $article->getName());
60
            $configSet->setArticles([$article]);
61
            $configSet->setType(0);
62
            $article->setConfiguratorSet($configSet);
63
        } else {
64
            $configSet = $article->getConfiguratorSet();
65
        }
66
        if ($product->configuratorSetType !== null) {
67
            $configSet->setType($product->configuratorSetType);
68
        }
69
70
        foreach ($product->variant as $key => $value) {
71
            $group = $this->getGroupByName($configSet, $key);
72
73
            $option = $this->getOrCreateOptionByName($configSet, $group, $value);
74
75
            $configSet = $this->addGroupToConfiguratorSet($configSet, $group);
76
            $configSet = $this->addOptionToConfiguratorSet($configSet, $option);
0 ignored issues
show
Documentation introduced by
$option is of type null|object, but the function expects a object<Shopware\Models\A...le\Configurator\Option>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
77
78
            $this->manager->persist($option);
79
            $this->manager->persist($group);
80
            if (!$detailOptions->contains($option)) {
81
                $detailOptions->add($option);
82
            }
83
        }
84
85
        $this->manager->persist($configSet);
86
87
        $detail->setConfiguratorOptions($detailOptions);
88
        $this->manager->persist($detail);
89
        $this->manager->persist($article);
90
        $this->manager->persist($article);
91
92
        $this->deleteUnusedOptions($product, $detailOptions, $configSet);
93
94
        $this->manager->flush();
95
96
97
        foreach ($product->variant as $key => $value) {
98
            $group = $this->getGroupByName($configSet, $key);
99
            $option = $this->getOrCreateOptionByName($configSet, $group, $value);
100
101
            //translate configurator groups and configurator options
102
            $this->addGroupTranslation($group, $product);
103
            $this->addOptionTranslation($option, $product);
0 ignored issues
show
Documentation introduced by
$option is of type null|object, but the function expects a object<Shopware\Models\A...le\Configurator\Option>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
104
        }
105
    }
106
107
108
    /**
109
     * @param Product $product
110
     * @param $detailOptions
111
     * @param Set $configSet
112
     * @throws \Doctrine\DBAL\DBALException
113
     */
114
    private function deleteUnusedOptions(Product $product, $detailOptions, Set $configSet)
115
    {
116
        /** @var Option $detailOption */
117
        foreach ($detailOptions as $detailOption) {
118
            if (!in_array($detailOption->getName(), $product->variant)) {
119
120
                $detailOptions->removeElement($detailOption);
121
122
                $configSet->getOptions()->removeElement($detailOption);
123
124
                $this->manager->flush();
125
126
                if (!($this->isOptionUsed($detailOption))) {
127
                    $this->manager->remove($detailOption);
128
                }
129
            }
130
        }
131
    }
132
133
134
    /**
135
     * @param $detailOption
136
     * @return bool
137
     * @throws \Doctrine\DBAL\DBALException
138
     */
139
    private function isOptionUsed(Option $detailOption)
140
    {
141
        $connection = $this->manager->getConnection();
142
        $query = $connection->prepare(
143
            'SELECT option_id FROM s_article_configurator_set_option_relations WHERE option_id = :optionId UNION 
144
              SELECT option_id FROM s_article_configurator_option_relations WHERE option_id = :optionId
145
              LIMIT 1'
146
        );
147
        $query->bindValue('optionId', $detailOption->getId());
148
        $query->execute();
149
        $result = $query->fetchColumn();
150
151
        return $result !== false;
152
    }
153
154
    /**
155
     * Creates variant configurator group
156
     *
157
     * @param string $name
158
     * @return \Shopware\Models\Article\Configurator\Group
159
     */
160
    public function createConfiguratorGroup($name)
161
    {
162
        $latestGroup = $this->manager
163
            ->getRepository('Shopware\Models\Article\Configurator\Group')
164
            ->findOneBy([], ['position' => 'DESC']);
165
166
        $position = $latestGroup ? $latestGroup->getPosition() + 1 : 1;
167
168
        $group = new Group();
169
        $group->setName($name);
170
        $group->setPosition($position);
171
172
        return $group;
173
    }
174
175
    /**
176
     * Adds group to configurator set if it does not exist
177
     *
178
     * @param Set $set
179
     * @param Group $group
180
     * @return Set
181
     */
182
    private function addGroupToConfiguratorSet(Set $set, Group $group)
183
    {
184
        $configuratorGroups = $set->getGroups();
185
        /** @var \Shopware\Models\Article\Configurator\Group $configuratorGroup */
186
        foreach ($configuratorGroups as $configuratorGroup) {
187
            if ($configuratorGroup->getName() === $group->getName()) {
188
                return $set;
189
            }
190
        }
191
192
        $configuratorGroups[] = $group;
193
        $set->setGroups($configuratorGroups);
194
        $this->manager->persist($set);
195
196
        return $set;
197
    }
198
199
    /**
200
     * Adds option to configurator set if it does not exist
201
     *
202
     * @param Set $set
203
     * @param Option $option
204
     * @return Set
205
     */
206
    private function addOptionToConfiguratorSet(Set $set, Option $option)
207
    {
208
        $configSetOptions = $set->getOptions();
209
        /** @var \Shopware\Models\Article\Configurator\Option $option */
210
        foreach ($configSetOptions as $configSetOption) {
211
            if ($configSetOption->getName() === $option->getName()
212
                && $configSetOption->getGroup()->getName() === $option->getGroup()->getName()) {
213
                return $set;
214
            }
215
        }
216
217
        $configSetOptions[] = $option;
218
        $set->setOptions($configSetOptions);
219
220
        return $set;
221
    }
222
223
    /**
224
     * Finds group in already assigned configurator set groups.
225
     * If it does not exist, then create it.
226
     *
227
     * @param Set $set
228
     * @param $groupName
229
     * @return Group
230
     */
231
    private function getGroupByName(Set $set, $groupName)
232
    {
233
        /** @var \Shopware\Models\Article\Configurator\Group $group */
234
        foreach ($set->getGroups() as $group) {
235
            if ($group->getName() === $groupName) {
236
                return $group;
237
            }
238
        }
239
240
        $repository = $this->manager->getRepository('Shopware\Models\Article\Configurator\Group');
241
        $group = $repository->findOneBy(['name' => $groupName]);
242
243
        if (empty($group)) {
244
            $group = $this->createConfiguratorGroup($groupName);
245
        }
246
247
        return $group;
248
    }
249
250
    /**
251
     * Find option in already assigned configurator set options.
252
     * If it does not exist, then create it.
253
     *
254
     * @param Set $set
255
     * @param Group $group
256
     * @param $optionName
257
     * @return null|object|Option
258
     */
259
    private function getOrCreateOptionByName(Set $set, Group $group, $optionName)
260
    {
261
        $configSetOptions = $set->getOptions();
262
263
        /** @var \Shopware\Models\Article\Configurator\Option $configSetOption */
264
        foreach ($configSetOptions as $configSetOption) {
265
            if ($configSetOption->getName() === $optionName
266
                && $configSetOption->getGroup()->getName() == $group->getName()
267
            ) {
268
                return $configSetOption;
269
            }
270
        }
271
272
        $optionsRepository = $this->manager->getRepository('Shopware\Models\Article\Configurator\Option');
273
        $option = $optionsRepository->findOneBy(['name' => $optionName, 'group' => $group]);
274
275
        if (empty($option)) {
276
            $option = new Option();
277
            $option->setName($optionName);
278
            $option->setGroup($group);
279
            $optionPositionsCount = count($group->getOptions());
280
            ++$optionPositionsCount;
281
            $option->setPosition($optionPositionsCount);
282
            $groupOptions = $group->getOptions();
283
            $groupOptions->add($option);
284
            $group->setOptions($groupOptions);
285
            $this->manager->persist($group);
286
            $this->manager->persist($option);
287
        }
288
289
        return $option;
290
    }
291
292 View Code Duplication
    private function addGroupTranslation(Group $group, Product $product)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
293
    {
294
        /** @var \Shopware\Connect\Struct\Translation $translation */
295
        foreach ($product->translations as $key => $translation) {
296
            if (!array_key_exists($group->getName(), $translation->variantLabels)) {
297
                continue;
298
            }
299
300
            /** @var \Shopware\Models\Shop\Locale $locale */
301
            $locale = $this->getLocaleRepository()->findOneBy(['locale' => LocaleMapper::getShopwareLocale($key)]);
302
303
            /** @var \Shopware\Models\Shop\Shop $shop */
304
            $shop = $this->getShopRepository()->findOneBy(['locale' => $locale]);
305
            if (!$shop) {
306
                continue;
307
            }
308
309
            foreach ($translation->variantLabels as $groupKey => $groupTranslation) {
310
                if ($groupKey === $group->getName()) {
311
                    $this->translationGateway->addGroupTranslation($groupTranslation, $group->getId(), $shop->getId());
312
                }
313
            }
314
        }
315
    }
316
317 View Code Duplication
    private function addOptionTranslation(Option $option, Product $product)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
318
    {
319
        /** @var \Shopware\Connect\Struct\Translation $translation */
320
        foreach ($product->translations as $key => $translation) {
321
            if (!array_key_exists($option->getName(), $translation->variantValues)) {
322
                continue;
323
            }
324
325
            /** @var \Shopware\Models\Shop\Locale $locale */
326
            $locale = $this->getLocaleRepository()->findOneBy(['locale' => LocaleMapper::getShopwareLocale($key)]);
327
328
            /** @var \Shopware\Models\Shop\Shop $shop */
329
            $shop = $this->getShopRepository()->findOneBy(['locale' => $locale]);
330
            if (!$shop) {
331
                continue;
332
            }
333
334
            foreach ($translation->variantValues as $optionKey => $optionTranslation) {
335
                if ($optionKey === $option->getName()) {
336
                    $this->translationGateway->addOptionTranslation($optionTranslation, $option->getId(), $shop->getId());
337
                }
338
            }
339
        }
340
    }
341
342
    private function getShopRepository()
343
    {
344
        if (!$this->shopRepository) {
345
            $this->shopRepository = $this->manager->getRepository('Shopware\Models\Shop\Shop');
346
        }
347
348
        return $this->shopRepository;
349
    }
350
351
    private function getLocaleRepository()
352
    {
353
        if (!$this->localeRepository) {
354
            $this->localeRepository = $this->manager->getRepository('Shopware\Models\Shop\Locale');
355
        }
356
357
        return $this->localeRepository;
358
    }
359
}
360