Completed
Push — remove-content-bundle ( 201341...8d07b3 )
by Kamil
52:29 queued 32:39
created

ProductContext   D

Complexity

Total Complexity 44

Size/Duplication

Total Lines 657
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 21

Importance

Changes 0
Metric Value
wmc 44
c 0
b 0
f 0
lcom 1
cbo 21
dl 0
loc 657
rs 4.5401

36 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 33 1
A storeHasAProductPricedAt() 0 12 2
A storeHasProductWithCode() 0 12 2
A storeHasAProductPricedAtAvailableInChannels() 0 12 2
A thisProductIsNamedIn() 0 12 1
A storeHasAConfigurableProduct() 0 18 2
A theStoreHasProducts() 0 6 2
A theProductHasVariantPricedAt() 0 17 1
A thereIsProductAvailableInGivenChannel() 0 9 1
A productBelongsToTaxCategory() 0 8 1
A itComesInTheFollowingVariations() 0 15 2
A productVariantBelongsToTaxCategory() 0 7 1
A thisProductHasAttributeWithValue() 0 8 1
A thisProductHasPercentAttributeWithValue() 0 8 1
A thisProductHasCheckboxAttributeWithValue() 0 9 1
A thisProductHasDateTimeAttributeWithDate() 0 9 1
A thisProductHasOptionWithValues() 0 21 2
A thereIsQuantityOfProducts() 0 8 1
A theProductIsOutOfStock() 0 9 1
A otherCustomerHasBoughtProductsByThisTime() 0 8 1
A thisProductIsTrackedByTheInventory() 0 8 1
A thisProductIsAvailableInSize() 0 14 1
A thisProductHasThisProductOption() 0 6 1
A thereAreItemsOfProductInVariantAvailableInTheInventory() 0 7 1
A theProductVariantIsTrackedByTheInventory() 0 6 1
A theProductChangedItsPriceTo() 0 8 1
A thisProductHasAnImageWithACode() 0 14 1
A itHasDifferentPricesForDifferentChannelsAndCurrencies() 0 7 1
A itHasPriceForChannelAndCurrency() 0 16 1
A createProductAttribute() 0 10 1
A createProductAttributeValue() 0 11 1
A getPriceFromString() 0 4 1
A createProduct() 0 17 1
A addProductOption() 0 13 1
A saveProduct() 0 5 1
A getParameter() 0 4 2

How to fix   Complexity   

Complex Class

Complex classes like ProductContext often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ProductContext, and based on these observations, apply Extract Interface, too.

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
namespace Sylius\Behat\Context\Setup;
13
14
use Behat\Behat\Context\Context;
15
use Behat\Behat\Tester\Exception\PendingException;
16
use Behat\Gherkin\Node\TableNode;
17
use Behat\Mink\Element\NodeElement;
18
use Doctrine\Common\Persistence\ObjectManager;
19
use Sylius\Component\Attribute\Factory\AttributeFactoryInterface;
20
use Sylius\Component\Core\Formatter\StringInflector;
21
use Sylius\Component\Core\Model\ChannelInterface;
22
use Sylius\Component\Core\Model\ImageInterface;
23
use Sylius\Component\Core\Model\ProductInterface;
24
use Sylius\Component\Core\Model\ProductTranslationInterface;
25
use Sylius\Component\Core\Model\ProductVariantInterface;
26
use Sylius\Component\Core\Pricing\Calculators;
27
use Sylius\Component\Core\Repository\ProductRepositoryInterface;
28
use Sylius\Behat\Service\SharedStorageInterface;
29
use Sylius\Component\Core\Uploader\ImageUploaderInterface;
30
use Sylius\Component\Product\Factory\ProductFactoryInterface;
31
use Sylius\Component\Product\Generator\SlugGeneratorInterface;
32
use Sylius\Component\Product\Model\ProductAttributeInterface;
33
use Sylius\Component\Product\Model\ProductAttributeValueInterface;
34
use Sylius\Component\Product\Model\ProductOptionInterface;
35
use Sylius\Component\Product\Model\ProductOptionValueInterface;
36
use Sylius\Component\Resource\Factory\FactoryInterface;
37
use Sylius\Component\Taxation\Model\TaxCategoryInterface;
38
use Sylius\Component\Product\Resolver\ProductVariantResolverInterface;
39
use Symfony\Component\HttpFoundation\File\UploadedFile;
40
41
/**
42
 * @author Arkadiusz Krakowiak <[email protected]>
43
 * @author Mateusz Zalewski <[email protected]>
44
 * @author Magdalena Banasiak <[email protected]>
45
 */
46
final class ProductContext implements Context
47
{
48
    /**
49
     * @var SharedStorageInterface
50
     */
51
    private $sharedStorage;
52
53
    /**
54
     * @var ProductRepositoryInterface
55
     */
56
    private $productRepository;
57
58
    /**
59
     * @var ProductFactoryInterface
60
     */
61
    private $productFactory;
62
63
    /**
64
     * @var FactoryInterface
65
     */
66
    private $productTranslationFactory;
67
68
    /**
69
     * @var AttributeFactoryInterface
70
     */
71
    private $productAttributeFactory;
72
73
    /**
74
     * @var FactoryInterface
75
     */
76
    private $productVariantFactory;
77
78
    /**
79
     * @var FactoryInterface
80
     */
81
    private $attributeValueFactory;
82
83
    /**
84
     * @var FactoryInterface
85
     */
86
    private $productOptionFactory;
87
88
    /**
89
     * @var FactoryInterface
90
     */
91
    private $productOptionValueFactory;
92
93
    /**
94
     * @var FactoryInterface
95
     */
96
    private $productImageFactory;
97
98
    /**
99
     * @var ObjectManager
100
     */
101
    private $objectManager;
102
103
    /**
104
     * @var ProductVariantResolverInterface
105
     */
106
    private $defaultVariantResolver;
107
108
    /**
109
     * @var ImageUploaderInterface
110
     */
111
    private $imageUploader;
112
113
    /**
114
     * @var SlugGeneratorInterface
115
     */
116
    private $slugGenerator;
117
118
    /**
119
     * @var array
120
     */
121
    private $minkParameters;
122
123
    /**
124
     * @param SharedStorageInterface $sharedStorage
125
     * @param ProductRepositoryInterface $productRepository
126
     * @param ProductFactoryInterface $productFactory
127
     * @param FactoryInterface $productTranslationFactory
128
     * @param AttributeFactoryInterface $productAttributeFactory
129
     * @param FactoryInterface $attributeValueFactory
130
     * @param FactoryInterface $productVariantFactory
131
     * @param FactoryInterface $productOptionFactory
132
     * @param FactoryInterface $productOptionValueFactory
133
     * @param FactoryInterface $productImageFactory
134
     * @param ObjectManager $objectManager
135
     * @param ProductVariantResolverInterface $defaultVariantResolver
136
     * @param ImageUploaderInterface $imageUploader
137
     * @param SlugGeneratorInterface $slugGenerator
138
     * @param array $minkParameters
139
     */
140
    public function __construct(
141
        SharedStorageInterface $sharedStorage,
142
        ProductRepositoryInterface $productRepository,
143
        ProductFactoryInterface $productFactory,
144
        FactoryInterface $productTranslationFactory,
145
        AttributeFactoryInterface $productAttributeFactory,
146
        FactoryInterface $attributeValueFactory,
147
        FactoryInterface $productVariantFactory,
148
        FactoryInterface $productOptionFactory,
149
        FactoryInterface $productOptionValueFactory,
150
        FactoryInterface $productImageFactory,
151
        ObjectManager $objectManager,
152
        ProductVariantResolverInterface $defaultVariantResolver,
153
        ImageUploaderInterface $imageUploader,
154
        SlugGeneratorInterface $slugGenerator,
155
        array $minkParameters
156
    ) {
157
        $this->sharedStorage = $sharedStorage;
158
        $this->productRepository = $productRepository;
159
        $this->productFactory = $productFactory;
160
        $this->productTranslationFactory = $productTranslationFactory;
161
        $this->productAttributeFactory = $productAttributeFactory;
162
        $this->attributeValueFactory = $attributeValueFactory;
163
        $this->productVariantFactory = $productVariantFactory;
164
        $this->productOptionFactory = $productOptionFactory;
165
        $this->productOptionValueFactory = $productOptionValueFactory;
166
        $this->productImageFactory = $productImageFactory;
167
        $this->objectManager = $objectManager;
168
        $this->defaultVariantResolver = $defaultVariantResolver;
169
        $this->imageUploader = $imageUploader;
170
        $this->slugGenerator = $slugGenerator;
171
        $this->minkParameters = $minkParameters;
172
    }
173
174
    /**
175
     * @Given the store has a product :productName
176
     * @Given the store has a :productName product
177
     * @Given /^the store(?:| also) has a product "([^"]+)" priced at ("[^"]+")$/
178
     */
179
    public function storeHasAProductPricedAt($productName, $price = 0)
180
    {
181
        $product = $this->createProduct($productName, $price);
182
183
        $product->setDescription('Awesome '.$productName);
184
185
        if ($this->sharedStorage->has('channel')) {
186
            $product->addChannel($this->sharedStorage->get('channel'));
187
        }
188
189
        $this->saveProduct($product);
190
    }
191
192
    /**
193
     * @Given the store( also) has a product :productName with code :code
194
     * @Given the store( also) has a product :productName with code :code, created at :date
195
     */
196
    public function storeHasProductWithCode($productName, $code, $date = null)
197
    {
198
        $product = $this->createProduct($productName, 0, $date);
199
200
        $product->setCode($code);
201
202
        if ($this->sharedStorage->has('channel')) {
203
            $product->addChannel($this->sharedStorage->get('channel'));
204
        }
205
206
        $this->saveProduct($product);
207
    }
208
209
    /**
210
     * @Given /^the store(?:| also) has a product "([^"]+)" priced at ("[^"]+") available in (channel "[^"]+") and (channel "[^"]+")$/
211
     */
212
    public function storeHasAProductPricedAtAvailableInChannels($productName, $price = 0, ...$channels)
213
    {
214
        $product = $this->createProduct($productName, $price);
215
216
        $product->setDescription('Awesome '.$productName);
217
218
        foreach ($channels as $channel) {
219
            $product->addChannel($channel);
220
        }
221
222
        $this->saveProduct($product);
223
    }
224
225
    /**
226
     * @Given /^(this product) is named "([^"]+)" (in the "([^"]+)" locale)$/
227
     */
228
    public function thisProductIsNamedIn(ProductInterface $product, $name, $locale)
229
    {
230
        /** @var ProductTranslationInterface $translation */
231
        $translation = $this->productTranslationFactory->createNew();
232
        $translation->setLocale($locale);
233
        $translation->setName($name);
234
        $translation->setSlug($this->slugGenerator->generate($name));
235
236
        $product->addTranslation($translation);
0 ignored issues
show
Documentation introduced by
$translation is of type object<Sylius\Component\...ctTranslationInterface>, but the function expects a object<Sylius\Component\...l\TranslationInterface>.

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...
237
238
        $this->objectManager->flush();
239
    }
240
241
    /**
242
     * @Given the store has a :productName configurable product
243
     */
244
    public function storeHasAConfigurableProduct($productName)
245
    {
246
        /** @var ProductInterface $product */
247
        $product = $this->productFactory->createNew();
248
249
        $product->setName($productName);
250
        $product->setCode(StringInflector::nameToUppercaseCode($productName));
251
        $product->setSlug($this->slugGenerator->generate($productName));
252
253
        $product->setDescription('Awesome '.$productName);
254
255
        if ($this->sharedStorage->has('channel')) {
256
            $channel = $this->sharedStorage->get('channel');
257
            $product->addChannel($channel);
258
        }
259
260
        $this->saveProduct($product);
261
    }
262
263
    /**
264
     * @Given the store has( also) :firstProductName and :secondProductName products
265
     * @Given the store has( also) :firstProductName, :secondProductName and :thirdProductName products
266
     * @Given the store has( also) :firstProductName, :secondProductName, :thirdProductName and :fourthProductName products
267
     */
268
    public function theStoreHasProducts(...$productsNames)
269
    {
270
        foreach ($productsNames as $productName) {
271
            $this->saveProduct($this->createProduct($productName));
272
        }
273
    }
274
275
    /**
276
     * @Given /^the (product "[^"]+") has(?:| a) "([^"]+)" variant priced at ("[^"]+")$/
277
     * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+")$/
278
     */
279
    public function theProductHasVariantPricedAt(ProductInterface $product, $productVariantName, $price)
280
    {
281
        $product->setVariantSelectionMethod(ProductInterface::VARIANT_SELECTION_CHOICE);
282
283
        /** @var ProductVariantInterface $variant */
284
        $variant = $this->productVariantFactory->createNew();
285
286
        $variant->setName($productVariantName);
287
        $variant->setCode(StringInflector::nameToUppercaseCode($productVariantName));
288
        $variant->setPrice($price);
289
        $variant->setProduct($product);
290
        $product->addVariant($variant);
291
292
        $this->objectManager->flush();
293
294
        $this->sharedStorage->set('variant', $variant);
295
    }
296
297
    /**
298
     * @Given /^there is product "([^"]+)" available in ((?:this|that|"[^"]+") channel)$/
299
     * @Given /^the store has a product "([^"]+)" available in ("([^"]+)" channel)$/
300
     */
301
    public function thereIsProductAvailableInGivenChannel($productName, ChannelInterface $channel)
302
    {
303
        $product = $this->createProduct($productName);
304
305
        $product->setDescription('Awesome ' . $productName);
306
        $product->addChannel($channel);
307
308
        $this->saveProduct($product);
309
    }
310
311
    /**
312
     * @Given /^([^"]+) belongs to ("[^"]+" tax category)$/
313
     */
314
    public function productBelongsToTaxCategory(ProductInterface $product, TaxCategoryInterface $taxCategory)
315
    {
316
        /** @var ProductVariantInterface $variant */
317
        $variant = $this->defaultVariantResolver->getVariant($product);
318
        $variant->setTaxCategory($taxCategory);
319
320
        $this->objectManager->flush();
321
    }
322
323
    /**
324
     * @Given /^(it) comes in the following variations:$/
325
     */
326
    public function itComesInTheFollowingVariations(ProductInterface $product, TableNode $table)
327
    {
328
        foreach ($table->getHash() as $variantHash) {
329
            /** @var ProductVariantInterface $variant */
330
            $variant = $this->productVariantFactory->createNew();
331
332
            $variant->setName($variantHash['name']);
333
            $variant->setCode(StringInflector::nameToUppercaseCode($variantHash['name']));
334
            $variant->setPrice($this->getPriceFromString(str_replace(['$', '€', '£'], '', $variantHash['price'])));
335
            $variant->setProduct($product);
336
            $product->addVariant($variant);
337
        }
338
339
        $this->objectManager->flush();
340
    }
341
342
    /**
343
     * @Given /^("[^"]+" variant of product "[^"]+") belongs to ("[^"]+" tax category)$/
344
     */
345
    public function productVariantBelongsToTaxCategory(
346
        ProductVariantInterface $productVariant,
347
        TaxCategoryInterface $taxCategory
348
    ) {
349
        $productVariant->setTaxCategory($taxCategory);
350
        $this->objectManager->flush($productVariant);
351
    }
352
353
    /**
354
     * @Given /^(this product) has ([^"]+) attribute "([^"]+)" with value "([^"]+)"$/
355
     */
356
    public function thisProductHasAttributeWithValue(ProductInterface $product, $productAttributeType, $productAttributeName, $value)
357
    {
358
        $attribute = $this->createProductAttribute($productAttributeType,$productAttributeName);
359
        $attributeValue = $this->createProductAttributeValue($value, $attribute);
360
        $product->addAttribute($attributeValue);
361
362
        $this->objectManager->flush();
363
    }
364
365
    /**
366
     * @Given /^(this product) has percent attribute "([^"]+)" with value ([^"]+)%$/
367
     */
368
    public function thisProductHasPercentAttributeWithValue(ProductInterface $product, $productAttributeName, $value)
369
    {
370
        $attribute = $this->createProductAttribute('percent',$productAttributeName);
371
        $attributeValue = $this->createProductAttributeValue($value/100, $attribute);
372
        $product->addAttribute($attributeValue);
373
374
        $this->objectManager->flush();
375
    }
376
377
    /**
378
     * @Given /^(this product) has ([^"]+) attribute "([^"]+)" set to "([^"]+)"$/
379
     */
380
    public function thisProductHasCheckboxAttributeWithValue(ProductInterface $product, $productAttributeType, $productAttributeName, $value)
381
    {
382
        $attribute = $this->createProductAttribute($productAttributeType, $productAttributeName);
383
        $booleanValue = ('Yes' === $value);
384
        $attributeValue = $this->createProductAttributeValue($booleanValue, $attribute);
0 ignored issues
show
Documentation introduced by
$booleanValue is of type boolean, but the function expects a string.

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...
385
        $product->addAttribute($attributeValue);
386
387
        $this->objectManager->flush();
388
    }
389
390
    /**
391
     * @Given /^(this product) has ([^"]+) attribute "([^"]+)" with date "([^"]+)"$/
392
     */
393
    public function thisProductHasDateTimeAttributeWithDate(ProductInterface $product, $productAttributeType, $productAttributeName, $date)
394
    {
395
        $attribute = $this->createProductAttribute($productAttributeType, $productAttributeName);
396
        $attributeValue = $this->createProductAttributeValue(new \DateTime($date), $attribute);
0 ignored issues
show
Documentation introduced by
new \DateTime($date) is of type object<DateTime>, but the function expects a string.

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...
397
398
        $product->addAttribute($attributeValue);
399
400
        $this->objectManager->flush();
401
    }
402
403
    /**
404
     * @Given /^(this product) has option "([^"]+)" with values "([^"]+)" and "([^"]+)"$/
405
     * @Given /^(this product) has option "([^"]+)" with values "([^"]+)", "([^"]+)" and "([^"]+)"$/
406
     */
407
    public function thisProductHasOptionWithValues(ProductInterface $product, $optionName, ...$values)
408
    {
409
        /** @var ProductOptionInterface $option */
410
        $option = $this->productOptionFactory->createNew();
411
412
        $option->setName($optionName);
413
        $option->setCode(StringInflector::nameToUppercaseCode($optionName));
414
415
        $this->sharedStorage->set(sprintf('%s_option', $optionName), $option);
416
417
        foreach ($values as $key => $value) {
418
            $optionValue = $this->addProductOption($option, $value, StringInflector::nameToUppercaseCode($value));
419
            $this->sharedStorage->set(sprintf('%s_option_%s_value', $value, strtolower($optionName)), $optionValue);
420
        }
421
422
        $product->addOption($option);
423
        $product->setVariantSelectionMethod(ProductInterface::VARIANT_SELECTION_MATCH);
424
425
        $this->objectManager->persist($option);
426
        $this->objectManager->flush();
427
    }
428
429
    /**
430
     * @Given /^there (?:is|are) (\d+) unit(?:|s) of (product "([^"]+)") available in the inventory$/
431
     * @When product :product quantity is changed to :quantity
432
     */
433
    public function thereIsQuantityOfProducts($quantity, ProductInterface $product)
434
    {
435
        /** @var ProductVariantInterface $productVariant */
436
        $productVariant = $this->defaultVariantResolver->getVariant($product);
437
        $productVariant->setOnHand($quantity);
438
439
        $this->objectManager->flush();
440
    }
441
442
    /**
443
     * @Given /^the (product "([^"]+)") is out of stock$/
444
     */
445
    public function theProductIsOutOfStock(ProductInterface $product)
446
    {
447
        /** @var ProductVariantInterface $productVariant */
448
        $productVariant = $this->defaultVariantResolver->getVariant($product);
449
        $productVariant->setTracked(true);
450
        $productVariant->setOnHand(0);
451
452
        $this->objectManager->flush();
453
    }
454
455
    /**
456
     * @When other customer has bought :quantity :product products by this time
457
     */
458
    public function otherCustomerHasBoughtProductsByThisTime($quantity, ProductInterface $product)
459
    {
460
        /** @var ProductVariantInterface $productVariant */
461
        $productVariant = $this->defaultVariantResolver->getVariant($product);
462
        $productVariant->setOnHand($productVariant->getOnHand() - $quantity);
463
464
        $this->objectManager->flush();
465
    }
466
467
    /**
468
     * @Given /^(this product) is tracked by the inventory$/
469
     * @Given /^(?:|the )("[^"]+" product) is(?:| also) tracked by the inventory$/
470
     */
471
    public function thisProductIsTrackedByTheInventory(ProductInterface $product)
472
    {
473
        /** @var ProductVariantInterface $productVariant */
474
        $productVariant = $this->defaultVariantResolver->getVariant($product);
475
        $productVariant->setTracked(true);
476
477
        $this->objectManager->flush();
478
    }
479
480
    /**
481
     * @Given /^(this product) is available in "([^"]+)" ([^"]+) priced at ("[^"]+")$/
482
     */
483
    public function thisProductIsAvailableInSize(ProductInterface $product, $optionValueName, $optionName, $price)
484
    {
485
        /** @var ProductVariantInterface $variant */
486
        $variant = $this->productVariantFactory->createNew();
487
488
        $optionValue = $this->sharedStorage->get(sprintf('%s_option_%s_value', $optionValueName, $optionName));
489
490
        $variant->addOptionValue($optionValue);
491
        $variant->setPrice($price);
492
        $variant->setCode(sprintf("%s_%s", $product->getCode(), $optionValueName));
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal %s_%s does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
493
494
        $product->addVariant($variant);
495
        $this->objectManager->flush();
496
    }
497
498
    /**
499
     * @Given /^(this product) has (this product option)$/
500
     * @Given /^(this product) has a ("[^"]+" option)$/
501
     * @Given /^(this product) has an ("[^"]+" option)$/
502
     */
503
    public function thisProductHasThisProductOption(ProductInterface $product, ProductOptionInterface $option)
504
    {
505
        $product->addOption($option);
506
507
        $this->objectManager->flush();
508
    }
509
510
    /**
511
     * @Given /^there are ([^"]+) units of ("[^"]+" variant of product "[^"]+") available in the inventory$/
512
     */
513
    public function thereAreItemsOfProductInVariantAvailableInTheInventory($quantity, ProductVariantInterface $productVariant)
514
    {
515
        $productVariant->setTracked(true);
516
        $productVariant->setOnHand($quantity);
517
518
        $this->objectManager->flush();
519
    }
520
521
    /**
522
     * @Given /^the ("[^"]+" product variant) is tracked by the inventory$/
523
     */
524
    public function theProductVariantIsTrackedByTheInventory(ProductVariantInterface $productVariant)
525
    {
526
        $productVariant->setTracked(true);
527
528
        $this->objectManager->flush();
529
    }
530
531
    /**
532
     * @Given /^(this product)'s price is ("[^"]+")$/
533
     * @Given /^the (product "[^"]+") changed its price to ("[^"]+")$/
534
     */
535
    public function theProductChangedItsPriceTo(ProductInterface $product, $price)
536
    {
537
        /** @var ProductVariantInterface $productVariant */
538
        $productVariant = $this->defaultVariantResolver->getVariant($product);
539
        $productVariant->setPrice($price);
540
541
        $this->objectManager->flush();
542
    }
543
544
    /**
545
     * @Given /^(this product) has(?:| also) an image "([^"]+)" with a code "([^"]+)"$/
546
     * @Given /^the ("[^"]+" product) has(?:| also) an image "([^"]+)" with a code "([^"]+)"$/
547
     */
548
    public function thisProductHasAnImageWithACode(ProductInterface $product, $imagePath, $imageCode)
549
    {
550
        $filesPath = $this->getParameter('files_path');
551
552
        /** @var ImageInterface $productImage */
553
        $productImage = $this->productImageFactory->createNew();
554
        $productImage->setFile(new UploadedFile($filesPath.$imagePath, basename($imagePath)));
555
        $productImage->setCode($imageCode);
556
        $this->imageUploader->upload($productImage);
557
558
        $product->addImage($productImage);
559
560
        $this->objectManager->flush($product);
561
    }
562
563
    /**
564
     * @Given /^(it) has different prices for different channels and currencies$/
565
     */
566
    public function itHasDifferentPricesForDifferentChannelsAndCurrencies(ProductInterface $product)
567
    {
568
        /** @var ProductVariantInterface $variant */
569
        $variant = $this->defaultVariantResolver->getVariant($product);
570
571
        $variant->setPricingCalculator(Calculators::CHANNEL_AND_CURRENCY_BASED);
572
    }
573
574
    /**
575
     * @Given /^(it) has price ("[^"]+") for ("[^"]+" channel) and "([^"]+)" currency$/
576
     */
577
    public function itHasPriceForChannelAndCurrency(
578
        ProductInterface $product,
579
        $price,
580
        ChannelInterface $channel,
581
        $currency
582
    ) {
583
        /** @var ProductVariantInterface $variant */
584
        $variant = $this->defaultVariantResolver->getVariant($product);
585
586
        $pricingConfiguration = $variant->getPricingConfiguration();
587
        $pricingConfiguration[$channel->getCode()][$currency] = $price;
588
589
        $variant->setPricingConfiguration($pricingConfiguration);
590
591
        $this->objectManager->flush();
592
    }
593
594
    /**
595
     * @param string $type
596
     * @param string $name
597
     * @param string $code
598
     *
599
     * @return ProductAttributeInterface
600
     */
601
    private function createProductAttribute($type, $name, $code = 'PA112')
602
    {
603
        $productAttribute = $this->productAttributeFactory->createTyped($type);
604
        $productAttribute->setCode($code);
605
        $productAttribute->setName($name);
606
607
        $this->objectManager->persist($productAttribute);
608
609
        return $productAttribute;
610
    }
611
612
    /**
613
     * @param string $value
614
     *
615
     * @return ProductAttributeValueInterface
616
     */
617
    private function createProductAttributeValue($value, ProductAttributeInterface $attribute)
618
    {
619
        /** @var ProductAttributeValueInterface $attributeValue */
620
        $attributeValue = $this->attributeValueFactory->createNew();
621
        $attributeValue->setAttribute($attribute);
622
        $attributeValue->setValue($value);
623
624
        $this->objectManager->persist($attributeValue);
625
626
        return $attributeValue;
627
    }
628
629
    /**
630
     * @param string $price
631
     *
632
     * @return int
633
     */
634
    private function getPriceFromString($price)
635
    {
636
        return (int) round(($price * 100), 2);
637
    }
638
639
    /**
640
     * @param string $productName
641
     * @param int $price
642
     *
643
     * @return ProductInterface
644
     */
645
    private function createProduct($productName, $price = 0, $date = null)
646
    {
647
        /** @var ProductInterface $product */
648
        $product = $this->productFactory->createWithVariant();
649
650
        $product->setName($productName);
651
        $product->setCode(StringInflector::nameToUppercaseCode($productName));
652
        $product->setSlug($this->slugGenerator->generate($productName));
653
        $product->setCreatedAt(new \DateTime($date));
654
655
        /** @var ProductVariantInterface $productVariant */
656
        $productVariant = $this->defaultVariantResolver->getVariant($product);
657
        $productVariant->setPrice($price);
658
        $productVariant->setCode($product->getCode());
659
660
        return $product;
661
    }
662
663
    /**
664
     * @param ProductOptionInterface $option
665
     * @param string $value
666
     * @param string $code
667
     *
668
     * @return ProductOptionValueInterface
669
     */
670
    private function addProductOption(ProductOptionInterface $option, $value, $code)
671
    {
672
        /** @var ProductOptionValueInterface $optionValue */
673
        $optionValue = $this->productOptionValueFactory->createNew();
674
675
        $optionValue->setValue($value);
676
        $optionValue->setCode($code);
677
        $optionValue->setOption($option);
678
679
        $option->addValue($optionValue);
680
681
        return $optionValue;
682
    }
683
684
    /**
685
     * @param ProductInterface $product
686
     */
687
    private function saveProduct(ProductInterface $product)
688
    {
689
        $this->productRepository->add($product);
690
        $this->sharedStorage->set('product', $product);
691
    }
692
693
    /**
694
     * @param string $name
695
     *
696
     * @return NodeElement
697
     */
698
    private function getParameter($name)
699
    {
700
        return isset($this->minkParameters[$name]) ? $this->minkParameters[$name] : null;
701
    }
702
}
703