Completed
Push — master ( 32d5c7...38a92b )
by Kamil
103:05 queued 77:43
created

ProductContext::__construct()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 35
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 35
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 33
nc 1
nop 16

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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 Behat\Gherkin\Node\TableNode;
18
use Behat\Mink\Element\NodeElement;
19
use Doctrine\Common\Persistence\ObjectManager;
20
use Sylius\Behat\Service\SharedStorageInterface;
21
use Sylius\Component\Core\Formatter\StringInflector;
22
use Sylius\Component\Core\Model\ChannelInterface;
23
use Sylius\Component\Core\Model\ChannelPricingInterface;
24
use Sylius\Component\Core\Model\ImageInterface;
25
use Sylius\Component\Core\Model\ProductInterface;
26
use Sylius\Component\Core\Model\ProductTranslationInterface;
27
use Sylius\Component\Core\Model\ProductVariantInterface;
28
use Sylius\Component\Core\Repository\ProductRepositoryInterface;
29
use Sylius\Component\Core\Uploader\ImageUploaderInterface;
30
use Sylius\Component\Product\Factory\ProductFactoryInterface;
31
use Sylius\Component\Product\Generator\ProductVariantGeneratorInterface;
32
use Sylius\Component\Product\Generator\SlugGeneratorInterface;
33
use Sylius\Component\Product\Model\ProductOptionInterface;
34
use Sylius\Component\Product\Model\ProductOptionValueInterface;
35
use Sylius\Component\Product\Model\ProductVariantTranslationInterface;
36
use Sylius\Component\Product\Resolver\ProductVariantResolverInterface;
37
use Sylius\Component\Resource\Factory\FactoryInterface;
38
use Sylius\Component\Resource\Model\TranslationInterface;
39
use Sylius\Component\Shipping\Model\ShippingCategoryInterface;
40
use Sylius\Component\Taxation\Model\TaxCategoryInterface;
41
use Symfony\Component\HttpFoundation\File\UploadedFile;
42
use Webmozart\Assert\Assert;
43
44
/**
45
 * @author Arkadiusz Krakowiak <[email protected]>
46
 * @author Mateusz Zalewski <[email protected]>
47
 * @author Magdalena Banasiak <[email protected]>
48
 */
49
final class ProductContext implements Context
50
{
51
    /**
52
     * @var SharedStorageInterface
53
     */
54
    private $sharedStorage;
55
56
    /**
57
     * @var ProductRepositoryInterface
58
     */
59
    private $productRepository;
60
61
    /**
62
     * @var ProductFactoryInterface
63
     */
64
    private $productFactory;
65
66
    /**
67
     * @var FactoryInterface
68
     */
69
    private $productTranslationFactory;
70
71
    /**
72
     * @var FactoryInterface
73
     */
74
    private $productVariantFactory;
75
76
    /**
77
     * @var FactoryInterface
78
     */
79
    private $productVariantTranslationFactory;
80
81
    /**
82
     * @var FactoryInterface
83
     */
84
    private $channelPricingFactory;
85
86
    /**
87
     * @var FactoryInterface
88
     */
89
    private $productOptionFactory;
90
91
    /**
92
     * @var FactoryInterface
93
     */
94
    private $productOptionValueFactory;
95
96
    /**
97
     * @var FactoryInterface
98
     */
99
    private $productImageFactory;
100
101
    /**
102
     * @var ObjectManager
103
     */
104
    private $objectManager;
105
106
    /**
107
     * @var ProductVariantGeneratorInterface
108
     */
109
    private $productVariantGenerator;
110
111
    /**
112
     * @var ProductVariantResolverInterface
113
     */
114
    private $defaultVariantResolver;
115
116
    /**
117
     * @var ImageUploaderInterface
118
     */
119
    private $imageUploader;
120
121
    /**
122
     * @var SlugGeneratorInterface
123
     */
124
    private $slugGenerator;
125
126
    /**
127
     * @var array
128
     */
129
    private $minkParameters;
130
131
    /**
132
     * @param SharedStorageInterface $sharedStorage
133
     * @param ProductRepositoryInterface $productRepository
134
     * @param ProductFactoryInterface $productFactory
135
     * @param FactoryInterface $productTranslationFactory
136
     * @param FactoryInterface $productVariantFactory
137
     * @param FactoryInterface $productVariantTranslationFactory
138
     * @param FactoryInterface $channelPricingFactory
139
     * @param FactoryInterface $productOptionFactory
140
     * @param FactoryInterface $productOptionValueFactory
141
     * @param FactoryInterface $productImageFactory
142
     * @param ObjectManager $objectManager
143
     * @param ProductVariantGeneratorInterface $productVariantGenerator
144
     * @param ProductVariantResolverInterface $defaultVariantResolver
145
     * @param ImageUploaderInterface $imageUploader
146
     * @param SlugGeneratorInterface $slugGenerator
147
     * @param array $minkParameters
148
     */
149
    public function __construct(
150
        SharedStorageInterface $sharedStorage,
151
        ProductRepositoryInterface $productRepository,
152
        ProductFactoryInterface $productFactory,
153
        FactoryInterface $productTranslationFactory,
154
        FactoryInterface $productVariantFactory,
155
        FactoryInterface $productVariantTranslationFactory,
156
        FactoryInterface $channelPricingFactory,
157
        FactoryInterface $productOptionFactory,
158
        FactoryInterface $productOptionValueFactory,
159
        FactoryInterface $productImageFactory,
160
        ObjectManager $objectManager,
161
        ProductVariantGeneratorInterface $productVariantGenerator,
162
        ProductVariantResolverInterface $defaultVariantResolver,
163
        ImageUploaderInterface $imageUploader,
164
        SlugGeneratorInterface $slugGenerator,
165
        array $minkParameters
166
    ) {
167
        $this->sharedStorage = $sharedStorage;
168
        $this->productRepository = $productRepository;
169
        $this->productFactory = $productFactory;
170
        $this->productTranslationFactory = $productTranslationFactory;
171
        $this->productVariantFactory = $productVariantFactory;
172
        $this->productVariantTranslationFactory = $productVariantTranslationFactory;
173
        $this->channelPricingFactory = $channelPricingFactory;
174
        $this->productOptionFactory = $productOptionFactory;
175
        $this->productOptionValueFactory = $productOptionValueFactory;
176
        $this->productImageFactory = $productImageFactory;
177
        $this->objectManager = $objectManager;
178
        $this->productVariantGenerator = $productVariantGenerator;
179
        $this->defaultVariantResolver = $defaultVariantResolver;
180
        $this->imageUploader = $imageUploader;
181
        $this->slugGenerator = $slugGenerator;
182
        $this->minkParameters = $minkParameters;
183
    }
184
185
    /**
186
     * @Given the store has a product :productName
187
     * @Given the store has a :productName product
188
     * @Given I added a product :productName
189
     * @Given /^the store(?:| also) has a product "([^"]+)" priced at ("[^"]+")$/
190
     * @Given /^the store(?:| also) has a product "([^"]+)" priced at ("[^"]+") in ("[^"]+" channel)$/
191
     */
192
    public function storeHasAProductPricedAt($productName, $price = 100, ChannelInterface $channel = null)
193
    {
194
        $product = $this->createProduct($productName, $price, $channel);
195
196
        $this->saveProduct($product);
197
    }
198
199
    /**
200
     * @Given /^(this product) is(?:| also) priced at ("[^"]+") in ("[^"]+" channel)$/
201
     */
202
    public function thisProductIsAlsoPricedAtInChannel(ProductInterface $product, $price, ChannelInterface $channel)
203
    {
204
        $product->addChannel($channel);
205
206
        /** @var ProductVariantInterface $productVariant */
207
        $productVariant = $this->defaultVariantResolver->getVariant($product);
208
        $productVariant->addChannelPricing($this->createChannelPricingForChannel($price, $channel));
209
210
        $this->objectManager->flush();
211
    }
212
213
    /**
214
     * @Given /^(this product) is(?:| also) available in ("[^"]+" channel)$/
215
     */
216
    public function thisProductIsAlsoAvailableInChannel(ProductInterface $product, ChannelInterface $channel): void
217
    {
218
        $this->thisProductIsAlsoPricedAtInChannel($product, 0, $channel);
219
    }
220
221
    /**
222
     * @Given the store( also) has a product :productName with code :code
223
     * @Given the store( also) has a product :productName with code :code, created at :date
224
     */
225
    public function storeHasProductWithCode($productName, $code, $date = 'now')
226
    {
227
        $product = $this->createProduct($productName);
228
        $product->setCreatedAt(new \DateTime($date));
229
        $product->setCode($code);
230
231
        $this->saveProduct($product);
232
    }
233
234
    /**
235
     * @Given /^the store(?:| also) has a product "([^"]+)" priced at ("[^"]+") available in (channel "[^"]+") and (channel "[^"]+")$/
236
     */
237
    public function storeHasAProductPricedAtAvailableInChannels($productName, $price = 100, ...$channels)
238
    {
239
        $product = $this->createProduct($productName, $price);
240
        /** @var ProductVariantInterface $productVariant */
241
        $productVariant = $this->defaultVariantResolver->getVariant($product);
242
243
        foreach ($channels as $channel) {
244
            $product->addChannel($channel);
245
            if (!$productVariant->hasChannelPricingForChannel($channel)) {
246
                $productVariant->addChannelPricing($this->createChannelPricingForChannel($price, $channel));
247
            }
248
        }
249
250
        $this->saveProduct($product);
251
    }
252
253
    /**
254
     * @Given /^(this product) is named "([^"]+)" (in the "([^"]+)" locale)$/
255
     * @Given /^the (product "[^"]+") is named "([^"]+)" (in the "([^"]+)" locale)$/
256
     */
257
    public function thisProductIsNamedIn(ProductInterface $product, $name, $locale)
258
    {
259
        $this->addProductTranslation($product, $name, $locale);
260
261
        $this->objectManager->flush();
262
    }
263
264
    /**
265
     * @Given /^the store has a product named "([^"]+)" in ("[^"]+" locale) and "([^"]+)" in ("[^"]+" locale)$/
266
     */
267
    public function theStoreHasProductNamedInAndIn($firstName, $firstLocale, $secondName, $secondLocale)
268
    {
269
        $product = $this->createProduct($firstName);
270
271
        $names = [$firstName => $firstLocale, $secondName => $secondLocale];
272
        foreach ($names as $name => $locale) {
273
            $this->addProductTranslation($product, $name, $locale);
274
        }
275
276
        $this->saveProduct($product);
277
    }
278
279
    /**
280
     * @Given /^the store has(?:| a| an) "([^"]+)" configurable product$/
281
     * @Given /^the store has(?:| a| an) "([^"]+)" configurable product with "([^"]+)" slug$/
282
     */
283
    public function storeHasAConfigurableProduct($productName, $slug = null)
284
    {
285
        /** @var ChannelInterface|null $channel */
286
        $channel = null;
287
        if ($this->sharedStorage->has('channel')) {
288
            $channel = $this->sharedStorage->get('channel');
289
        }
290
291
        /** @var ProductInterface $product */
292
        $product = $this->productFactory->createNew();
293
        $product->setCode(StringInflector::nameToUppercaseCode($productName));
294
295
        if (null !== $channel) {
296
            $product->addChannel($channel);
297
298
            foreach ($channel->getLocales() as $locale) {
299
                $product->setFallbackLocale($locale->getCode());
300
                $product->setCurrentLocale($locale->getCode());
301
302
                $product->setName($productName);
303
                $product->setSlug($slug ?: $this->slugGenerator->generate($productName));
304
            }
305
        }
306
307
        $this->saveProduct($product);
308
    }
309
310
    /**
311
     * @Given the store has( also) :firstProductName and :secondProductName products
312
     * @Given the store has( also) :firstProductName, :secondProductName and :thirdProductName products
313
     * @Given the store has( also) :firstProductName, :secondProductName, :thirdProductName and :fourthProductName products
314
     */
315
    public function theStoreHasProducts(...$productsNames)
316
    {
317
        foreach ($productsNames as $productName) {
318
            $this->saveProduct($this->createProduct($productName));
319
        }
320
    }
321
322
    /**
323
     * @Given /^(this channel) has "([^"]+)", "([^"]+)", "([^"]+)" and "([^"]+)" products$/
324
     */
325
    public function thisChannelHasProducts(ChannelInterface $channel, ...$productsNames)
326
    {
327
        foreach ($productsNames as $productName) {
328
            $product = $this->createProduct($productName, 0, $channel);
329
330
            $this->saveProduct($product);
331
        }
332
    }
333
334
    /**
335
     * @Given /^the (product "[^"]+") has(?:| a) "([^"]+)" variant priced at ("[^"]+")$/
336
     * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+")$/
337
     * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+") in ("([^"]+)" channel)$/
338
     */
339
    public function theProductHasVariantPricedAt(
340
        ProductInterface $product,
341
        $productVariantName,
342
        $price,
343
        ChannelInterface $channel = null
344
    ) {
345
        $this->createProductVariant(
346
            $product,
347
            $productVariantName,
348
            $price,
349
            StringInflector::nameToUppercaseCode($productVariantName),
350
            (null !== $channel) ? $channel : $this->sharedStorage->get('channel')
351
        );
352
    }
353
354
    /**
355
     * @Given /^the (product "[^"]+") has(?:| a| an) "([^"]+)" variant$/
356
     * @Given /^(this product) has(?:| a| an) "([^"]+)" variant$/
357
     * @Given /^(this product) has "([^"]+)", "([^"]+)" and "([^"]+)" variants$/
358
     */
359
    public function theProductHasVariants(ProductInterface $product, ...$variantNames)
360
    {
361
        $channel = $this->sharedStorage->get('channel');
362
363
        foreach ($variantNames as $name) {
364
            $this->createProductVariant(
365
                $product,
366
                $name,
367
                0,
368
                StringInflector::nameToUppercaseCode($name),
369
                $channel
370
            );
371
        }
372
    }
373
374
    /**
375
     * @Given /^the (product "[^"]+")(?:| also) has a nameless variant with code "([^"]+)"$/
376
     * @Given /^(this product)(?:| also) has a nameless variant with code "([^"]+)"$/
377
     * @Given /^(it)(?:| also) has a nameless variant with code "([^"]+)"$/
378
     */
379
    public function theProductHasNamelessVariantWithCode(ProductInterface $product, $variantCode)
380
    {
381
        $channel = $this->sharedStorage->get('channel');
382
383
        $this->createProductVariant($product, null, 0, $variantCode, $channel);
384
    }
385
386
    /**
387
     * @Given /^the (product "[^"]+")(?:| also) has(?:| a| an) "([^"]+)" variant with code "([^"]+)"$/
388
     * @Given /^(this product)(?:| also) has(?:| a| an) "([^"]+)" variant with code "([^"]+)"$/
389
     * @Given /^(it)(?:| also) has(?:| a| an) "([^"]+)" variant with code "([^"]+)"$/
390
     */
391
    public function theProductHasVariantWithCode(ProductInterface $product, $variantName, $variantCode)
392
    {
393
        $channel = $this->sharedStorage->get('channel');
394
395
        $this->createProductVariant($product, $variantName, 0, $variantCode, $channel);
396
    }
397
398
    /**
399
     * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+") which does not require shipping$/
400
     */
401
    public function theProductHasVariantWhichDoesNotRequireShipping(
402
        ProductInterface $product,
403
        $productVariantName,
404
        $price
405
    ) {
406
        $this->createProductVariant(
407
            $product,
408
            $productVariantName,
409
            $price,
410
            StringInflector::nameToUppercaseCode($productVariantName),
411
            $this->sharedStorage->get('channel'),
412
            null,
413
            false
414
        );
415
    }
416
417
    /**
418
     * @Given /^the (product "[^"]+") has(?:| also)(?:| a| an) "([^"]+)" variant$/
419
     * @Given /^the (product "[^"]+") has(?:| also)(?:| a| an) "([^"]+)" variant at position ([^"]+)$/
420
     * @Given /^(this product) has(?:| also)(?:| a| an) "([^"]+)" variant at position ([^"]+)$/
421
     */
422
    public function theProductHasVariantAtPosition(
423
        ProductInterface $product,
424
        $productVariantName,
425
        $position = null
426
    ) {
427
        $this->createProductVariant(
428
            $product,
429
            $productVariantName,
430
            0,
431
            StringInflector::nameToUppercaseCode($productVariantName),
432
            $this->sharedStorage->get('channel'),
433
            $position
434
        );
435
    }
436
437
    /**
438
     * @Given /^(this variant) is also priced at ("[^"]+") in ("([^"]+)" channel)$/
439
     */
440
    public function thisVariantIsAlsoPricedAtInChannel(ProductVariantInterface $productVariant, $price, ChannelInterface $channel)
441
    {
442
        $productVariant->addChannelPricing($this->createChannelPricingForChannel(
443
            $this->getPriceFromString(str_replace(['$', '€', '£'], '', $price)),
444
            $channel
445
        ));
446
447
        $this->objectManager->flush();
448
    }
449
450
    /**
451
     * @Given /^(it|this product) has(?:| also) variant named "([^"]+)" in ("[^"]+" locale) and "([^"]+)" in ("[^"]+" locale)$/
452
     */
453
    public function itHasVariantNamedInAndIn(ProductInterface $product, $firstName, $firstLocale, $secondName, $secondLocale)
454
    {
455
        $productVariant = $this->createProductVariant(
456
            $product,
457
            $firstName,
458
            100,
459
            StringInflector::nameToUppercaseCode($firstName),
460
            $this->sharedStorage->get('channel')
461
        );
462
463
        $names = [$firstName => $firstLocale, $secondName => $secondLocale];
464
        foreach ($names as $name => $locale) {
465
            $this->addProductVariantTranslation($productVariant, $name, $locale);
466
        }
467
468
        $this->objectManager->flush();
469
    }
470
471
    /**
472
     * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+") identified by "([^"]+)"$/
473
     */
474
    public function theProductHasVariantPricedAtIdentifiedBy(
475
        ProductInterface $product,
476
        $productVariantName,
477
        $price,
478
        $code
479
    ) {
480
        $this->createProductVariant($product, $productVariantName, $price, $code, $this->sharedStorage->get('channel'));
481
    }
482
483
    /**
484
     * @Given /^(this product) only variant was renamed to "([^"]+)"$/
485
     */
486
    public function productOnlyVariantWasRenamed(ProductInterface $product, $variantName)
487
    {
488
        Assert::true($product->isSimple());
489
490
        /** @var ProductVariantInterface $productVariant */
491
        $productVariant = $product->getVariants()->first();
492
        $productVariant->setName($variantName);
493
494
        $this->objectManager->flush();
495
    }
496
497
    /**
498
     * @Given /^there is product "([^"]+)" available in ((?:this|that|"[^"]+") channel)$/
499
     * @Given /^the store has a product "([^"]+)" available in ("([^"]+)" channel)$/
500
     */
501
    public function thereIsProductAvailableInGivenChannel($productName, ChannelInterface $channel)
502
    {
503
        $product = $this->createProduct($productName, 0, $channel);
504
505
        $this->saveProduct($product);
506
    }
507
508
    /**
509
     * @Given /^([^"]+) belongs to ("[^"]+" tax category)$/
510
     */
511
    public function productBelongsToTaxCategory(ProductInterface $product, TaxCategoryInterface $taxCategory)
512
    {
513
        /** @var ProductVariantInterface $variant */
514
        $variant = $this->defaultVariantResolver->getVariant($product);
515
        $variant->setTaxCategory($taxCategory);
516
517
        $this->objectManager->flush();
518
    }
519
520
    /**
521
     * @Given /^(it) comes in the following variations:$/
522
     */
523
    public function itComesInTheFollowingVariations(ProductInterface $product, TableNode $table)
524
    {
525
        $channel = $this->sharedStorage->get('channel');
526
527
        foreach ($table->getHash() as $variantHash) {
528
            /** @var ProductVariantInterface $variant */
529
            $variant = $this->productVariantFactory->createNew();
530
531
            $variant->setName($variantHash['name']);
532
            $variant->setCode(StringInflector::nameToUppercaseCode($variantHash['name']));
533
            $variant->addChannelPricing($this->createChannelPricingForChannel(
534
                $this->getPriceFromString(str_replace(['$', '€', '£'], '', $variantHash['price'])),
535
                $channel
536
            ));
537
538
            $variant->setProduct($product);
539
            $product->addVariant($variant);
540
        }
541
542
        $this->objectManager->flush();
543
    }
544
545
    /**
546
     * @Given /^("[^"]+" variant of product "[^"]+") belongs to ("[^"]+" tax category)$/
547
     */
548
    public function productVariantBelongsToTaxCategory(
549
        ProductVariantInterface $productVariant,
550
        TaxCategoryInterface $taxCategory
551
    ) {
552
        $productVariant->setTaxCategory($taxCategory);
553
554
        $this->objectManager->persist($productVariant);
555
        $this->objectManager->flush();
556
    }
557
558
    /**
559
     * @Given /^(this product) has option "([^"]+)" with values "([^"]+)" and "([^"]+)"$/
560
     * @Given /^(this product) has option "([^"]+)" with values "([^"]+)", "([^"]+)" and "([^"]+)"$/
561
     */
562
    public function thisProductHasOptionWithValues(ProductInterface $product, $optionName, ...$values)
563
    {
564
        /** @var ProductOptionInterface $option */
565
        $option = $this->productOptionFactory->createNew();
566
567
        $option->setName($optionName);
568
        $option->setCode(StringInflector::nameToUppercaseCode($optionName));
569
570
        $this->sharedStorage->set(sprintf('%s_option', $optionName), $option);
571
572
        foreach ($values as $key => $value) {
573
            $optionValue = $this->addProductOption($option, $value, StringInflector::nameToUppercaseCode($value));
574
            $this->sharedStorage->set(sprintf('%s_option_%s_value', $value, strtolower($optionName)), $optionValue);
575
        }
576
577
        $product->addOption($option);
578
        $product->setVariantSelectionMethod(ProductInterface::VARIANT_SELECTION_MATCH);
579
580
        $this->objectManager->persist($option);
581
        $this->objectManager->flush();
582
    }
583
584
    /**
585
     * @Given /^there (?:is|are) (\d+) unit(?:|s) of (product "([^"]+)") available in the inventory$/
586
     */
587
    public function thereIsQuantityOfProducts($quantity, ProductInterface $product)
588
    {
589
        /** @var ProductVariantInterface $productVariant */
590
        $productVariant = $this->defaultVariantResolver->getVariant($product);
591
        $productVariant->setOnHand((int) $quantity);
592
593
        $this->objectManager->flush();
594
    }
595
596
    /**
597
     * @Given /^the (product "([^"]+)") is out of stock$/
598
     */
599
    public function theProductIsOutOfStock(ProductInterface $product)
600
    {
601
        /** @var ProductVariantInterface $productVariant */
602
        $productVariant = $this->defaultVariantResolver->getVariant($product);
603
        $productVariant->setTracked(true);
604
        $productVariant->setOnHand(0);
605
606
        $this->objectManager->flush();
607
    }
608
609
    /**
610
     * @When other customer has bought :quantity :product products by this time
611
     */
612
    public function otherCustomerHasBoughtProductsByThisTime($quantity, ProductInterface $product)
613
    {
614
        /** @var ProductVariantInterface $productVariant */
615
        $productVariant = $this->defaultVariantResolver->getVariant($product);
616
        $productVariant->setOnHand($productVariant->getOnHand() - $quantity);
617
618
        $this->objectManager->flush();
619
    }
620
621
    /**
622
     * @Given /^(this product) is tracked by the inventory$/
623
     * @Given /^(?:|the )("[^"]+" product) is(?:| also) tracked by the inventory$/
624
     */
625
    public function thisProductIsTrackedByTheInventory(ProductInterface $product)
626
    {
627
        /** @var ProductVariantInterface $productVariant */
628
        $productVariant = $this->defaultVariantResolver->getVariant($product);
629
        $productVariant->setTracked(true);
630
631
        $this->objectManager->flush();
632
    }
633
634
    /**
635
     * @Given /^(this product) is available in "([^"]+)" ([^"]+) priced at ("[^"]+")$/
636
     */
637
    public function thisProductIsAvailableInSize(ProductInterface $product, $optionValueName, $optionName, $price)
638
    {
639
        /** @var ProductVariantInterface $variant */
640
        $variant = $this->productVariantFactory->createNew();
641
642
        $optionValue = $this->sharedStorage->get(sprintf('%s_option_%s_value', $optionValueName, $optionName));
643
644
        $variant->addOptionValue($optionValue);
645
        $variant->addChannelPricing($this->createChannelPricingForChannel($price, $this->sharedStorage->get('channel')));
646
        $variant->setCode(sprintf('%s_%s', $product->getCode(), $optionValueName));
647
        $variant->setName($product->getName());
648
649
        $product->addVariant($variant);
650
        $this->objectManager->flush();
651
    }
652
653
    /**
654
     * @Given the :product product's :optionValueName size belongs to :shippingCategory shipping category
655
     */
656
    public function thisProductSizeBelongsToShippingCategory(ProductInterface $product, $optionValueName, ShippingCategoryInterface $shippingCategory)
657
    {
658
        $code = sprintf('%s_%s', $product->getCode(), $optionValueName);
659
        /** @var ProductVariantInterface $productVariant */
660
        $productVariant = $product->getVariants()->filter(function ($variant) use ($code) {
661
            return $code === $variant->getCode();
662
        })->first();
663
664
        Assert::notNull($productVariant, sprintf('Product variant with given code %s not exists!', $code));
665
666
        $productVariant->setShippingCategory($shippingCategory);
667
        $this->objectManager->flush();
668
    }
669
670
    /**
671
     * @Given /^(this product) has (this product option)$/
672
     * @Given /^(this product) has (?:a|an) ("[^"]+" option)$/
673
     */
674
    public function thisProductHasThisProductOption(ProductInterface $product, ProductOptionInterface $option)
675
    {
676
        $product->addOption($option);
677
678
        $this->objectManager->flush();
679
    }
680
681
    /**
682
     * @Given /^(this product) has all possible variants$/
683
     */
684
    public function thisProductHasAllPossibleVariants(ProductInterface $product)
685
    {
686
        try {
687
            foreach ($product->getVariants() as $productVariant) {
688
                $product->removeVariant($productVariant);
689
            }
690
691
            $this->productVariantGenerator->generate($product);
692
        } catch (\InvalidArgumentException $exception) {
693
            /** @var ProductVariantInterface $productVariant */
694
            $productVariant = $this->productVariantFactory->createNew();
695
696
            $product->addVariant($productVariant);
697
        }
698
699
        $i = 0;
700
        /** @var ProductVariantInterface $productVariant */
701
        foreach ($product->getVariants() as $productVariant) {
702
            $productVariant->setCode(sprintf('%s-variant-%d', $product->getCode(), $i));
703
704
            foreach ($product->getChannels() as $channel) {
705
                $productVariant->addChannelPricing($this->createChannelPricingForChannel(1000, $channel));
706
            }
707
708
            ++$i;
709
        }
710
711
        $this->objectManager->flush();
712
    }
713
714
    /**
715
     * @Given /^there are ([^"]+) units of ("[^"]+" variant of product "[^"]+") available in the inventory$/
716
     */
717
    public function thereAreItemsOfProductInVariantAvailableInTheInventory($quantity, ProductVariantInterface $productVariant)
718
    {
719
        $productVariant->setTracked(true);
720
        $productVariant->setOnHand((int) $quantity);
721
722
        $this->objectManager->flush();
723
    }
724
725
    /**
726
     * @Given /^the ("[^"]+" product variant) is tracked by the inventory$/
727
     */
728
    public function theProductVariantIsTrackedByTheInventory(ProductVariantInterface $productVariant)
729
    {
730
        $productVariant->setTracked(true);
731
732
        $this->objectManager->flush();
733
    }
734
735
    /**
736
     * @Given /^(this product)'s price is ("[^"]+")$/
737
     * @Given /^the (product "[^"]+") changed its price to ("[^"]+")$/
738
     * @Given /^(this product) price has been changed to ("[^"]+")$/
739
     */
740
    public function theProductChangedItsPriceTo(ProductInterface $product, $price)
741
    {
742
        /** @var ProductVariantInterface $productVariant */
743
        $productVariant = $this->defaultVariantResolver->getVariant($product);
744
        $channelPricing = $productVariant->getChannelPricingForChannel($this->sharedStorage->get('channel'));
745
        $channelPricing->setPrice($price);
746
747
        $this->objectManager->flush();
748
    }
749
750
    /**
751
     * @Given /^(this product)(?:| also) has an image "([^"]+)" with "([^"]+)" type$/
752
     * @Given /^the ("[^"]+" product)(?:| also) has an image "([^"]+)" with "([^"]+)" type$/
753
     * @Given /^(it)(?:| also) has an image "([^"]+)" with "([^"]+)" type$/
754
     */
755
    public function thisProductHasAnImageWithType(ProductInterface $product, $imagePath, $imageType)
756
    {
757
        $filesPath = $this->getParameter('files_path');
758
759
        /** @var ImageInterface $productImage */
760
        $productImage = $this->productImageFactory->createNew();
761
        $productImage->setFile(new UploadedFile($filesPath . $imagePath, basename($imagePath)));
762
        $productImage->setType($imageType);
763
        $this->imageUploader->upload($productImage);
764
765
        $product->addImage($productImage);
766
767
        $this->objectManager->persist($product);
768
        $this->objectManager->flush();
769
    }
770
771
    /**
772
     * @Given /^(this product) belongs to ("([^"]+)" shipping category)$/
773
     * @Given product :product shipping category has been changed to :shippingCategory
774
     */
775
    public function thisProductBelongsToShippingCategory(ProductInterface $product, ShippingCategoryInterface $shippingCategory)
776
    {
777
        $product->getVariants()->first()->setShippingCategory($shippingCategory);
778
        $this->objectManager->flush();
779
    }
780
781
    /**
782
     * @Given /^(this product) has been disabled$/
783
     */
784
    public function thisProductHasBeenDisabled(ProductInterface $product)
785
    {
786
        $product->disable();
787
        $this->objectManager->flush();
788
    }
789
790
    /**
791
     * @param string $price
792
     *
793
     * @return int
794
     */
795
    private function getPriceFromString($price)
796
    {
797
        return (int) round($price * 100, 2);
798
    }
799
800
    /**
801
     * @param string $productName
802
     * @param int $price
803
     * @param ChannelInterface|null $channel
804
     *
805
     * @return ProductInterface
806
     */
807
    private function createProduct($productName, $price = 100, ChannelInterface $channel = null)
808
    {
809
        if (null === $channel && $this->sharedStorage->has('channel')) {
810
            $channel = $this->sharedStorage->get('channel');
811
        }
812
813
        /** @var ProductInterface $product */
814
        $product = $this->productFactory->createWithVariant();
815
816
        $product->setCode(StringInflector::nameToUppercaseCode($productName));
817
        $product->setName($productName);
818
        $product->setSlug($this->slugGenerator->generate($productName));
819
820
        if (null !== $channel) {
821
            $product->addChannel($channel);
822
823
            foreach ($channel->getLocales() as $locale) {
824
                $product->setFallbackLocale($locale->getCode());
825
                $product->setCurrentLocale($locale->getCode());
826
827
                $product->setName($productName);
828
                $product->setSlug($this->slugGenerator->generate($productName));
829
            }
830
        }
831
832
        /** @var ProductVariantInterface $productVariant */
833
        $productVariant = $this->defaultVariantResolver->getVariant($product);
834
835
        if (null !== $channel) {
836
            $productVariant->addChannelPricing($this->createChannelPricingForChannel($price, $channel));
837
        }
838
839
        $productVariant->setCode($product->getCode());
840
        $productVariant->setName($product->getName());
841
842
        return $product;
843
    }
844
845
    /**
846
     * @param ProductOptionInterface $option
847
     * @param string $value
848
     * @param string $code
849
     *
850
     * @return ProductOptionValueInterface
851
     */
852
    private function addProductOption(ProductOptionInterface $option, $value, $code)
853
    {
854
        /** @var ProductOptionValueInterface $optionValue */
855
        $optionValue = $this->productOptionValueFactory->createNew();
856
857
        $optionValue->setValue($value);
858
        $optionValue->setCode($code);
859
        $optionValue->setOption($option);
860
861
        $option->addValue($optionValue);
862
863
        return $optionValue;
864
    }
865
866
    /**
867
     * @param ProductInterface $product
868
     */
869
    private function saveProduct(ProductInterface $product)
870
    {
871
        $this->productRepository->add($product);
872
        $this->sharedStorage->set('product', $product);
873
    }
874
875
    /**
876
     * @param string $name
877
     *
878
     * @return NodeElement
879
     */
880
    private function getParameter($name)
881
    {
882
        return isset($this->minkParameters[$name]) ? $this->minkParameters[$name] : null;
883
    }
884
885
    /**
886
     * @param ProductInterface $product
887
     * @param $productVariantName
888
     * @param int $price
889
     * @param string $code
890
     * @param ChannelInterface $channel
0 ignored issues
show
Documentation introduced by
Should the type for parameter $channel not be null|ChannelInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
891
     * @param int $position
0 ignored issues
show
Documentation introduced by
Should the type for parameter $position not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
892
     * @param bool $shippingRequired
893
     *
894
     * @return ProductVariantInterface
895
     */
896
    private function createProductVariant(
897
        ProductInterface $product,
898
        $productVariantName,
899
        $price,
900
        $code,
901
        ChannelInterface $channel = null,
902
        $position = null,
903
        $shippingRequired = true
904
    ) {
905
        $product->setVariantSelectionMethod(ProductInterface::VARIANT_SELECTION_CHOICE);
906
907
        /** @var ProductVariantInterface $variant */
908
        $variant = $this->productVariantFactory->createNew();
909
910
        $variant->setName($productVariantName);
911
        $variant->setCode($code);
912
        $variant->setProduct($product);
913
        $variant->addChannelPricing($this->createChannelPricingForChannel($price, $channel));
914
        $variant->setPosition((null === $position) ? null : (int) $position);
915
        $variant->setShippingRequired($shippingRequired);
916
917
        $product->addVariant($variant);
918
919
        $this->objectManager->flush();
920
        $this->sharedStorage->set('variant', $variant);
921
922
        return $variant;
923
    }
924
925
    /**
926
     * @param ProductInterface $product
927
     * @param string $name
928
     * @param string $locale
929
     */
930
    private function addProductTranslation(ProductInterface $product, $name, $locale)
931
    {
932
        /** @var ProductTranslationInterface|TranslationInterface $translation */
933
        $translation = $product->getTranslation($locale);
934
        if ($translation->getLocale() !== $locale) {
935
            $translation = $this->productTranslationFactory->createNew();
936
        }
937
938
        $translation->setLocale($locale);
939
        $translation->setName($name);
940
        $translation->setSlug($this->slugGenerator->generate($name));
941
942
        $product->addTranslation($translation);
943
    }
944
945
    /**
946
     * @param ProductVariantInterface $productVariant
947
     * @param string $name
948
     * @param string $locale
949
     */
950
    private function addProductVariantTranslation(ProductVariantInterface $productVariant, $name, $locale)
951
    {
952
        /** @var ProductVariantTranslationInterface|TranslationInterface $translation */
953
        $translation = $this->productVariantTranslationFactory->createNew();
954
        $translation->setLocale($locale);
955
        $translation->setName($name);
956
957
        $productVariant->addTranslation($translation);
958
    }
959
960
    /**
961
     * @param int $price
962
     * @param ChannelInterface|null $channel
963
     *
964
     * @return ChannelPricingInterface
965
     */
966
    private function createChannelPricingForChannel($price, ChannelInterface $channel = null)
967
    {
968
        /** @var ChannelPricingInterface $channelPricing */
969
        $channelPricing = $this->channelPricingFactory->createNew();
970
        $channelPricing->setPrice($price);
971
        $channelPricing->setChannelCode($channel->getCode());
0 ignored issues
show
Bug introduced by
It seems like $channel is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
972
973
        return $channelPricing;
974
    }
975
}
976