Completed
Push — master ( 47683b...970228 )
by Kamil
21s
created

ProductContext::__construct()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 33
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

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

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

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
882
            $translation = $this->productTranslationFactory->createNew();
883
        }
884
885
        $translation->setLocale($locale);
886
        $translation->setName($name);
887
        $translation->setSlug($this->slugGenerator->generate($name));
888
889
        $product->addTranslation($translation);
890
    }
891
892
    /**
893
     * @param ProductVariantInterface $productVariant
894
     * @param string $name
895
     * @param string $locale
896
     */
897
    private function addProductVariantTranslation(ProductVariantInterface $productVariant, $name, $locale)
898
    {
899
        /** @var ProductVariantTranslationInterface|TranslationInterface $translation */
900
        $translation = $this->productVariantTranslationFactory->createNew();
901
        $translation->setLocale($locale);
0 ignored issues
show
Bug introduced by
The method setLocale does only exist in Sylius\Component\Resourc...el\TranslationInterface, but not in Sylius\Component\Product...antTranslationInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
902
        $translation->setName($name);
0 ignored issues
show
Bug introduced by
The method setName does only exist in Sylius\Component\Product...antTranslationInterface, but not in Sylius\Component\Resourc...el\TranslationInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
903
904
        $productVariant->addTranslation($translation);
0 ignored issues
show
Bug introduced by
It seems like $translation defined by $this->productVariantTra...ionFactory->createNew() on line 900 can also be of type object<Sylius\Component\...ntTranslationInterface>; however, Sylius\Component\Resourc...rface::addTranslation() does only seem to accept object<Sylius\Component\...l\TranslationInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
905
    }
906
907
    /**
908
     * @param int $price
909
     * @param ChannelInterface|null $channel
910
     *
911
     * @return ChannelPricingInterface
912
     */
913
    private function createChannelPricingForChannel($price, ChannelInterface $channel = null)
914
    {
915
        /** @var ChannelPricingInterface $channelPricing */
916
        $channelPricing = $this->channelPricingFactory->createNew();
917
        $channelPricing->setPrice($price);
918
        $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...
919
920
        return $channelPricing;
921
    }
922
}
923