Completed
Push — master ( 49a1ac...de016e )
by Kamil
05:40
created

createSelectProductAttributeValue()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 24
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
rs 8.6845
c 0
b 0
f 0
cc 4
eloc 17
nc 4
nop 4
1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Sylius\Behat\Context\Setup;
15
16
use Behat\Behat\Context\Context;
17
use Doctrine\Common\Persistence\ObjectManager;
18
use Sylius\Behat\Service\SharedStorageInterface;
19
use Sylius\Component\Attribute\AttributeType\SelectAttributeType;
20
use Sylius\Component\Attribute\Factory\AttributeFactoryInterface;
21
use Sylius\Component\Core\Formatter\StringInflector;
22
use Sylius\Component\Core\Model\ProductInterface;
23
use Sylius\Component\Product\Model\ProductAttributeInterface;
24
use Sylius\Component\Product\Model\ProductAttributeValueInterface;
25
use Sylius\Component\Resource\Factory\FactoryInterface;
26
use Sylius\Component\Resource\Repository\RepositoryInterface;
27
28
/**
29
 * @author Anna Walasek <[email protected]>
30
 */
31
final class ProductAttributeContext implements Context
32
{
33
    /**
34
     * @var SharedStorageInterface
35
     */
36
    private $sharedStorage;
37
38
    /**
39
     * @var RepositoryInterface
40
     */
41
    private $productAttributeRepository;
42
43
    /**
44
     * @var AttributeFactoryInterface
45
     */
46
    private $productAttributeFactory;
47
48
    /**
49
     * @var FactoryInterface
50
     */
51
    private $productAttributeValueFactory;
52
53
    /**
54
     * @var ObjectManager
55
     */
56
    private $objectManager;
57
58
    /**
59
     * @var \Faker\Generator
60
     */
61
    private $faker;
62
63
    /**
64
     * @param SharedStorageInterface $sharedStorage
65
     * @param RepositoryInterface $productAttributeRepository
66
     * @param AttributeFactoryInterface $productAttributeFactory
67
     * @param FactoryInterface $productAttributeValueFactory
68
     * @param ObjectManager $objectManager
69
     */
70
    public function __construct(
71
        SharedStorageInterface $sharedStorage,
72
        RepositoryInterface $productAttributeRepository,
73
        AttributeFactoryInterface $productAttributeFactory,
74
        FactoryInterface $productAttributeValueFactory,
75
        ObjectManager $objectManager
76
    ) {
77
        $this->sharedStorage = $sharedStorage;
78
        $this->productAttributeRepository = $productAttributeRepository;
79
        $this->productAttributeFactory = $productAttributeFactory;
80
        $this->productAttributeValueFactory = $productAttributeValueFactory;
81
        $this->objectManager = $objectManager;
82
83
        $this->faker = \Faker\Factory::create();
84
    }
85
86
    /**
87
     * @Given the store has a :type product attribute :name with code :code
88
     */
89
    public function theStoreHasAProductAttributeWithCode($type, $name, $code)
90
    {
91
        $productAttribute = $this->createProductAttribute($type, $name, $code);
92
93
        $this->saveProductAttribute($productAttribute);
94
    }
95
96
    /**
97
     * @Given the store has( also) a :type product attribute :name at position :position
98
     */
99
    public function theStoreHasAProductAttributeWithPosition($type, $name, $position)
100
    {
101
        $productAttribute = $this->createProductAttribute($type, $name);
102
        $productAttribute->setPosition((int) $position);
103
104
        $this->saveProductAttribute($productAttribute);
105
    }
106
107
    /**
108
     * @Given /^the store has(?:| also)(?:| a| an) (text|textarea|integer|percent) product attribute "([^"]+)"$/
109
     */
110
    public function theStoreHasAProductAttribute(string $type, string $name): void
111
    {
112
        $productAttribute = $this->createProductAttribute($type, $name);
113
114
        $this->saveProductAttribute($productAttribute);
115
    }
116
117
    /**
118
     * @Given /^(this product attribute) has(?:| also) a value "([^"]+)" in ("[^"]+" locale)$/
119
     */
120
    public function thisProductAttributeHasAValueInLocale(
121
        ProductAttributeInterface $productAttribute,
122
        string $value,
123
        string $localeCode
124
    ): void {
125
        $choices = [
126
            $this->faker->uuid => [
127
                $localeCode => $value,
128
            ],
129
        ];
130
131
        $configuration = $productAttribute->getConfiguration();
132
        $configuration['choices'] = array_merge($configuration['choices'], $choices);
133
        $productAttribute->setConfiguration($configuration);
134
135
        $this->saveProductAttribute($productAttribute);
136
    }
137
138
    /**
139
     * @Given /^(this product attribute) has(?:| also) a value "([^"]+)" in ("[^"]+" locale) and "([^"]+)" in ("[^"]+" locale)$/
140
     */
141
    public function thisProductAttributeHasAValueInLocaleAndInLocale(
142
        ProductAttributeInterface $productAttribute,
143
        string $firstValue,
144
        string $firstLocaleCode,
145
        string $secondValue,
146
        string $secondLocaleCode
147
    ): void {
148
        $choices = [
149
            $this->faker->uuid => [
150
                $firstLocaleCode => $firstValue,
151
                $secondLocaleCode => $secondValue,
152
            ],
153
        ];
154
155
        $configuration = $productAttribute->getConfiguration();
156
        $configuration['choices'] = array_merge($configuration['choices'], $choices);
157
        $productAttribute->setConfiguration($configuration);
158
159
        $this->saveProductAttribute($productAttribute);
160
    }
161
162
    /**
163
     * @Given the store has a select product attribute :name
164
     */
165
    public function theStoreHasASelectProductAttribute(string $name): void
166
    {
167
        $this->theStoreHasASelectProductAttributeWithValue($name);
168
    }
169
170
    /**
171
     * @Given the store has a select product attribute :name with value :value
172
     * @Given the store has a select product attribute :name with values :firstValue and :secondValue
173
     */
174
    public function theStoreHasASelectProductAttributeWithValue(string $name, string ...$values): void
175
    {
176
        $choices = [];
177
        foreach ($values as $value) {
178
            $choices[$this->faker->uuid] = ['en_US' => $value];
179
        }
180
181
        $productAttribute = $this->createProductAttribute(SelectAttributeType::TYPE, $name);
182
        $productAttribute->setConfiguration([
183
            'multiple' => true,
184
            'choices' => $choices,
185
            'min' => null,
186
            'max' => null,
187
        ]);
188
189
        $this->saveProductAttribute($productAttribute);
190
    }
191
192
    /**
193
     * @Given /^(this product attribute) has set min value as (\d+) and max value as (\d+)$/
194
     */
195
    public function thisAttributeHasSetMinValueAsAndMaxValueAs(ProductAttributeInterface $attribute, $min, $max)
196
    {
197
        $attribute->setConfiguration(['min' => $min, 'max' => $max]);
198
199
        $this->objectManager->flush();
200
    }
201
202
    /**
203
     * @Given /^(this product) has(?:| also)(?:| a) select attribute "([^"]+)" with value "([^"]+)"$/
204
     * @Given /^(this product) has(?:| also)(?:| a) select attribute "([^"]+)" with values "([^"]+)" and "([^"]+)"$/
205
     */
206
    public function thisProductHasSelectAttributeWithValues(
207
        ProductInterface $product,
208
        string $productAttributeName,
209
        string ...$productAttributeValues
210
    ): void {
211
        $this->createSelectProductAttributeValue($product, $productAttributeName, $productAttributeValues);
212
    }
213
214
    /**
215
     * @Given /^(this product) has(?:| also)(?:| a) select attribute "([^"]+)" with value "([^"]+)" in ("[^"]+" locale)$/
216
     */
217
    public function thisProductHasSelectAttributeWithValueInLocale(
218
        ProductInterface $product,
219
        string $productAttributeName,
220
        string $productAttributeValue,
221
        string $localeCode
222
    ): void {
223
        $this->createSelectProductAttributeValue($product, $productAttributeName, [$productAttributeValue], $localeCode);
224
    }
225
226
    /**
227
     * @Given /^(this product) has (text|textarea) attribute "([^"]+)" with value "([^"]+)"$/
228
     * @Given /^(this product) has (text|textarea) attribute "([^"]+)" with value "([^"]+)" in ("[^"]+" locale)$/
229
     */
230
    public function thisProductHasAttributeWithValue(
231
        ProductInterface $product,
232
        string $productAttributeType,
233
        string $productAttributeName,
234
        string $value,
235
        string $language = 'en_US'
236
    ): void {
237
        $attribute = $this->provideProductAttribute($productAttributeType, $productAttributeName);
238
        $attributeValue = $this->createProductAttributeValue($value, $attribute, $language);
239
        $product->addAttribute($attributeValue);
240
241
        $this->objectManager->flush();
242
    }
243
244
    /**
245
     * @Given /^(this product) has percent attribute "([^"]+)" with value ([^"]+)%$/
246
     */
247
    public function thisProductHasPercentAttributeWithValue(ProductInterface $product, $productAttributeName, $value)
248
    {
249
        $attribute = $this->provideProductAttribute('percent', $productAttributeName);
250
        $attributeValue = $this->createProductAttributeValue($value / 100, $attribute);
251
        $product->addAttribute($attributeValue);
252
253
        $this->objectManager->flush();
254
    }
255
256
    /**
257
     * @Given /^(this product) has ([^"]+) attribute "([^"]+)" set to "([^"]+)"$/
258
     */
259
    public function thisProductHasCheckboxAttributeWithValue(
260
        ProductInterface $product,
261
        $productAttributeType,
262
        $productAttributeName,
263
        $value
264
    ) {
265
        $attribute = $this->provideProductAttribute($productAttributeType, $productAttributeName);
266
        $booleanValue = ('Yes' === $value);
267
        $attributeValue = $this->createProductAttributeValue($booleanValue, $attribute);
268
        $product->addAttribute($attributeValue);
269
270
        $this->objectManager->flush();
271
    }
272
273
    /**
274
     * @Given /^(this product) has percent attribute "([^"]+)" at position (\d+)$/
275
     */
276
    public function thisProductHasPercentAttributeWithValueAtPosition(
277
        ProductInterface $product,
278
        $productAttributeName,
279
        $position
280
    ) {
281
        $attribute = $this->provideProductAttribute('percent', $productAttributeName);
282
        $attribute->setPosition((int) $position);
283
        $attributeValue = $this->createProductAttributeValue(rand(1, 100) / 100, $attribute);
284
285
        $product->addAttribute($attributeValue);
286
287
        $this->objectManager->flush();
288
    }
289
290
    /**
291
     * @Given /^(this product) has ([^"]+) attribute "([^"]+)" with date "([^"]+)"$/
292
     */
293
    public function thisProductHasDateTimeAttributeWithDate(
294
        ProductInterface $product,
295
        $productAttributeType,
296
        $productAttributeName,
297
        $date
298
    ) {
299
        $attribute = $this->provideProductAttribute($productAttributeType, $productAttributeName);
300
        $attributeValue = $this->createProductAttributeValue(new \DateTime($date), $attribute);
301
302
        $product->addAttribute($attributeValue);
303
304
        $this->objectManager->flush();
305
    }
306
307
    /**
308
     * @param string $type
309
     * @param string $name
310
     * @param string|null $code
311
     *
312
     * @return ProductAttributeInterface
313
     */
314
    private function createProductAttribute($type, $name, $code = null)
315
    {
316
        $productAttribute = $this->productAttributeFactory->createTyped($type);
317
318
        $code = $code ?: StringInflector::nameToCode($name);
319
320
        $productAttribute->setCode($code);
321
        $productAttribute->setName($name);
322
323
        return $productAttribute;
324
    }
325
326
    /**
327
     * @param string $type
328
     * @param string $name
329
     * @param string|null $code
330
     *
331
     * @return ProductAttributeInterface
332
     */
333
    private function provideProductAttribute($type, $name, $code = null)
334
    {
335
        $code = $code ?: StringInflector::nameToCode($name);
336
337
        /** @var ProductAttributeInterface $productAttribute */
338
        $productAttribute = $this->productAttributeRepository->findOneBy(['code' => $code]);
339
        if (null !== $productAttribute) {
340
            return $productAttribute;
341
        }
342
343
        $productAttribute = $this->createProductAttribute($type, $name, $code);
344
        $this->saveProductAttribute($productAttribute);
345
346
        return $productAttribute;
347
    }
348
349
    /**
350
     * @param mixed $value
351
     * @param ProductAttributeInterface $attribute
352
     * @param string $localeCode
353
     *
354
     * @return ProductAttributeValueInterface
355
     */
356
    private function createProductAttributeValue(
357
        $value,
358
        ProductAttributeInterface $attribute,
359
        string $localeCode = 'en_US'
360
    ): ProductAttributeValueInterface {
361
        /** @var ProductAttributeValueInterface $attributeValue */
362
        $attributeValue = $this->productAttributeValueFactory->createNew();
363
        $attributeValue->setAttribute($attribute);
364
        $attributeValue->setValue($value);
365
        $attributeValue->setLocaleCode($localeCode);
366
367
        $this->objectManager->persist($attributeValue);
368
369
        return $attributeValue;
370
    }
371
372
    /**
373
     * @param ProductAttributeInterface $productAttribute
374
     */
375
    private function saveProductAttribute(ProductAttributeInterface $productAttribute)
376
    {
377
        $this->productAttributeRepository->add($productAttribute);
378
        $this->sharedStorage->set('product_attribute', $productAttribute);
379
    }
380
381
    /**
382
     * @param ProductInterface $product
383
     * @param string $productAttributeName
384
     * @param array $values
385
     * @param string $localeCode
386
     */
387
    private function createSelectProductAttributeValue(
388
        ProductInterface $product,
389
        string $productAttributeName,
390
        array $values,
391
        string $localeCode = 'en_US'
392
    ): void {
393
        $attribute = $this->provideProductAttribute(SelectAttributeType::TYPE, $productAttributeName);
394
395
        $choices = $attribute->getConfiguration()['choices'];
396
        $choiceKeys = [];
397
        foreach ($values as $value) {
398
            foreach ($choices as $choiceKey => $choiceValues) {
399
                $key = array_search($value, $choiceValues);
400
                if ($localeCode === $key) {
401
                    $choiceKeys[] = $choiceKey;
402
                }
403
            }
404
        }
405
406
        $attributeValue = $this->createProductAttributeValue($choiceKeys, $attribute, $localeCode);
407
        $product->addAttribute($attributeValue);
408
409
        $this->objectManager->flush();
410
    }
411
}
412