Completed
Push — master ( bb2d64...78fd01 )
by Paweł
24s
created

ProductContext::theProductWasRenamedTo()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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