Completed
Push — queries ( 779e6b...06f228 )
by Kamil
25:25
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
200
        /** @var ChannelPricingInterface $channelPricing */
201
        $channelPricing = $this->channelPricingFactory->createNew();
202
        $channelPricing->setPrice($price);
203
        $channelPricing->setChannel($channel);
204
205
        $productVariant->addChannelPricing($channelPricing);
206
207
        $this->objectManager->flush();
208
    }
209
210
    /**
211
     * @Given the store( also) has a product :productName with code :code
212
     * @Given the store( also) has a product :productName with code :code, created at :date
213
     */
214
    public function storeHasProductWithCode($productName, $code, $date = null)
215
    {
216
        $product = $this->createProduct($productName);
217
        $product->setCreatedAt(new \DateTime($date));
218
        $product->setCode($code);
219
220
        $this->saveProduct($product);
221
    }
222
223
    /**
224
     * @Given /^the store(?:| also) has a product "([^"]+)" priced at ("[^"]+") available in (channel "[^"]+") and (channel "[^"]+")$/
225
     */
226
    public function storeHasAProductPricedAtAvailableInChannels($productName, $price = 100, ...$channels)
227
    {
228
        $product = $this->createProduct($productName, $price);
229
        /** @var ProductVariantInterface $productVariant */
230
        $productVariant = $this->defaultVariantResolver->getVariant($product);
231
232
        foreach ($channels as $channel) {
233
            $product->addChannel($channel);
234
            if (!$productVariant->hasChannelPricingForChannel($channel)) {
235
                $productVariant->addChannelPricing($this->createChannelPricingForChannel($price, $channel));
236
            }
237
        }
238
239
        $this->saveProduct($product);
240
    }
241
242
    /**
243
     * @Given /^(this product) is named "([^"]+)" (in the "([^"]+)" locale)$/
244
     * @Given /^the (product "[^"]+") is named "([^"]+)" (in the "([^"]+)" locale)$/
245
     */
246
    public function thisProductIsNamedIn(ProductInterface $product, $name, $locale)
247
    {
248
        $this->addProductTranslation($product, $name, $locale);
249
250
        $this->objectManager->flush();
251
    }
252
253
    /**
254
     * @Given /^the store has a product named "([^"]+)" in ("[^"]+" locale) and "([^"]+)" in ("[^"]+" locale)$/
255
     */
256
    public function theStoreHasProductNamedInAndIn($firstName, $firstLocale, $secondName, $secondLocale)
257
    {
258
        $product = $this->createProduct($firstName);
259
260
        $names = [$firstName => $firstLocale, $secondName => $secondLocale];
261
        foreach ($names as $name => $locale) {
262
            $this->addProductTranslation($product, $name, $locale);
263
        }
264
265
        $this->saveProduct($product);
266
    }
267
268
    /**
269
     * @Given /^the store has(?:| a| an) "([^"]+)" configurable product$/
270
     * @Given /^the store has(?:| a| an) "([^"]+)" configurable product with "([^"]+)" slug$/
271
     */
272
    public function storeHasAConfigurableProduct($productName, $slug = null)
273
    {
274
        /** @var ChannelInterface|null $channel */
275
        $channel = null;
276
        if ($this->sharedStorage->has('channel')) {
277
            $channel = $this->sharedStorage->get('channel');
278
        }
279
280
        /** @var ProductInterface $product */
281
        $product = $this->productFactory->createNew();
282
        $product->setCode(StringInflector::nameToUppercaseCode($productName));
283
284
        if (null !== $channel) {
285
            $product->addChannel($channel);
286
287
            foreach ($channel->getLocales() as $locale) {
288
                $product->setFallbackLocale($locale->getCode());
289
                $product->setCurrentLocale($locale->getCode());
290
291
                $product->setName($productName);
292
                $product->setSlug($slug ?: $this->slugGenerator->generate($productName));
293
            }
294
        }
295
296
        $this->saveProduct($product);
297
    }
298
299
    /**
300
     * @Given the store has( also) :firstProductName and :secondProductName products
301
     * @Given the store has( also) :firstProductName, :secondProductName and :thirdProductName products
302
     * @Given the store has( also) :firstProductName, :secondProductName, :thirdProductName and :fourthProductName products
303
     */
304
    public function theStoreHasProducts(...$productsNames)
305
    {
306
        foreach ($productsNames as $productName) {
307
            $this->saveProduct($this->createProduct($productName));
308
        }
309
    }
310
311
    /**
312
     * @Given /^(this channel) has "([^"]+)", "([^"]+)", "([^"]+)" and "([^"]+)" products$/
313
     */
314
    public function thisChannelHasProducts(ChannelInterface $channel, ...$productsNames)
315
    {
316
        foreach ($productsNames as $productName) {
317
            $product = $this->createProduct($productName, 0, $channel);
318
319
            $this->saveProduct($product);
320
        }
321
    }
322
323
    /**
324
     * @Given /^the (product "[^"]+") has(?:| a) "([^"]+)" variant priced at ("[^"]+")$/
325
     * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+")$/
326
     * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+") in ("([^"]+)" channel)$/
327
     */
328
    public function theProductHasVariantPricedAt(
329
        ProductInterface $product,
330
        $productVariantName,
331
        $price,
332
        ChannelInterface $channel = null
333
    ) {
334
        $this->createProductVariant(
335
            $product,
336
            $productVariantName,
337
            $price,
338
            StringInflector::nameToUppercaseCode($productVariantName),
339
            (null !== $channel) ? $channel : $this->sharedStorage->get('channel')
340
        );
341
    }
342
343
    /**
344
     * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+") which does not require shipping$/
345
     */
346
    public function theProductHasVariantWhichDoesNotRequireShipping(
347
        ProductInterface $product,
348
        $productVariantName,
349
        $price
350
    ) {
351
        $this->createProductVariant(
352
            $product,
353
            $productVariantName,
354
            $price,
355
            StringInflector::nameToUppercaseCode($productVariantName),
356
            $this->sharedStorage->get('channel'),
357
            null,
358
            false
359
        );
360
    }
361
362
    /**
363
     * @Given /^the (product "[^"]+") has(?:| also)(?:| a| an) "([^"]+)" variant$/
364
     * @Given /^the (product "[^"]+") has(?:| also)(?:| a| an) "([^"]+)" variant at position ([^"]+)$/
365
     * @Given /^(this product) has(?:| also)(?:| a| an) "([^"]+)" variant at position ([^"]+)$/
366
     */
367
    public function theProductHasVariantAtPosition(
368
        ProductInterface $product,
369
        $productVariantName,
370
        $position = null
371
    ) {
372
        $this->createProductVariant(
373
            $product,
374
            $productVariantName,
375
            0,
376
            StringInflector::nameToUppercaseCode($productVariantName),
377
            $this->sharedStorage->get('channel'),
378
            $position
379
        );
380
    }
381
382
    /**
383
     * @Given /^(this variant) is also priced at ("[^"]+") in ("([^"]+)" channel)$/
384
     */
385
    public function thisVariantIsAlsoPricedAtInChannel(ProductVariantInterface $productVariant, $price, ChannelInterface $channel)
386
    {
387
        $productVariant->addChannelPricing($this->createChannelPricingForChannel(
388
            $this->getPriceFromString(str_replace(['$', '€', '£'], '', $price)),
389
            $channel
390
        ));
391
392
        $this->objectManager->flush();
393
    }
394
395
    /**
396
     * @Given /^(it|this product) has(?:| also) variant named "([^"]+)" in ("[^"]+" locale) and "([^"]+)" in ("[^"]+" locale)$/
397
     */
398
    public function itHasVariantNamedInAndIn(ProductInterface $product, $firstName, $firstLocale, $secondName, $secondLocale)
399
    {
400
        $productVariant = $this->createProductVariant(
401
            $product,
402
            $firstName,
403
            100,
404
            StringInflector::nameToUppercaseCode($firstName),
405
            $this->sharedStorage->get('channel')
406
        );
407
408
        $names = [$firstName => $firstLocale, $secondName => $secondLocale];
409
        foreach ($names as $name => $locale) {
410
            $this->addProductVariantTranslation($productVariant, $name, $locale);
411
        }
412
413
        $this->objectManager->flush();
414
    }
415
416
    /**
417
     * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+") identified by "([^"]+)"$/
418
     */
419
    public function theProductHasVariantPricedAtIdentifiedBy(
420
        ProductInterface $product,
421
        $productVariantName,
422
        $price,
423
        $code
424
    ) {
425
        $this->createProductVariant($product, $productVariantName, $price, $code, $this->sharedStorage->get('channel'));
426
    }
427
428
    /**
429
     * @Given /^there is product "([^"]+)" available in ((?:this|that|"[^"]+") channel)$/
430
     * @Given /^the store has a product "([^"]+)" available in ("([^"]+)" channel)$/
431
     */
432
    public function thereIsProductAvailableInGivenChannel($productName, ChannelInterface $channel)
433
    {
434
        $product = $this->createProduct($productName, 0, $channel);
435
436
        $this->saveProduct($product);
437
    }
438
439
    /**
440
     * @Given /^([^"]+) belongs to ("[^"]+" tax category)$/
441
     */
442
    public function productBelongsToTaxCategory(ProductInterface $product, TaxCategoryInterface $taxCategory)
443
    {
444
        /** @var ProductVariantInterface $variant */
445
        $variant = $this->defaultVariantResolver->getVariant($product);
446
        $variant->setTaxCategory($taxCategory);
447
448
        $this->objectManager->flush();
449
    }
450
451
    /**
452
     * @Given /^(it) comes in the following variations:$/
453
     */
454
    public function itComesInTheFollowingVariations(ProductInterface $product, TableNode $table)
455
    {
456
        foreach ($table->getHash() as $variantHash) {
457
            /** @var ProductVariantInterface $variant */
458
            $variant = $this->productVariantFactory->createNew();
459
460
            $variant->setName($variantHash['name']);
461
            $variant->setCode(StringInflector::nameToUppercaseCode($variantHash['name']));
462
            $variant->addChannelPricing($this->createChannelPricingForChannel(
463
                $this->getPriceFromString(str_replace(['$', '€', '£'], '', $variantHash['price'])),
464
                $this->sharedStorage->get('channel')
465
            ));
466
            $variant->setProduct($product);
467
            $product->addVariant($variant);
468
        }
469
470
        $this->objectManager->flush();
471
    }
472
473
    /**
474
     * @Given /^("[^"]+" variant of product "[^"]+") belongs to ("[^"]+" tax category)$/
475
     */
476
    public function productVariantBelongsToTaxCategory(
477
        ProductVariantInterface $productVariant,
478
        TaxCategoryInterface $taxCategory
479
    ) {
480
        $productVariant->setTaxCategory($taxCategory);
481
        $this->objectManager->flush($productVariant);
482
    }
483
484
    /**
485
     * @Given /^(this product) has option "([^"]+)" with values "([^"]+)" and "([^"]+)"$/
486
     * @Given /^(this product) has option "([^"]+)" with values "([^"]+)", "([^"]+)" and "([^"]+)"$/
487
     */
488
    public function thisProductHasOptionWithValues(ProductInterface $product, $optionName, ...$values)
489
    {
490
        /** @var ProductOptionInterface $option */
491
        $option = $this->productOptionFactory->createNew();
492
493
        $option->setName($optionName);
494
        $option->setCode(StringInflector::nameToUppercaseCode($optionName));
495
496
        $this->sharedStorage->set(sprintf('%s_option', $optionName), $option);
497
498
        foreach ($values as $key => $value) {
499
            $optionValue = $this->addProductOption($option, $value, StringInflector::nameToUppercaseCode($value));
500
            $this->sharedStorage->set(sprintf('%s_option_%s_value', $value, strtolower($optionName)), $optionValue);
501
        }
502
503
        $product->addOption($option);
504
        $product->setVariantSelectionMethod(ProductInterface::VARIANT_SELECTION_MATCH);
505
506
        $this->objectManager->persist($option);
507
        $this->objectManager->flush();
508
    }
509
510
    /**
511
     * @Given /^there (?:is|are) (\d+) unit(?:|s) of (product "([^"]+)") available in the inventory$/
512
     */
513
    public function thereIsQuantityOfProducts($quantity, ProductInterface $product)
514
    {
515
        /** @var ProductVariantInterface $productVariant */
516
        $productVariant = $this->defaultVariantResolver->getVariant($product);
517
        $productVariant->setOnHand($quantity);
518
519
        $this->objectManager->flush();
520
    }
521
522
    /**
523
     * @Given /^the (product "([^"]+)") is out of stock$/
524
     */
525
    public function theProductIsOutOfStock(ProductInterface $product)
526
    {
527
        /** @var ProductVariantInterface $productVariant */
528
        $productVariant = $this->defaultVariantResolver->getVariant($product);
529
        $productVariant->setTracked(true);
530
        $productVariant->setOnHand(0);
531
532
        $this->objectManager->flush();
533
    }
534
535
    /**
536
     * @When other customer has bought :quantity :product products by this time
537
     */
538
    public function otherCustomerHasBoughtProductsByThisTime($quantity, ProductInterface $product)
539
    {
540
        /** @var ProductVariantInterface $productVariant */
541
        $productVariant = $this->defaultVariantResolver->getVariant($product);
542
        $productVariant->setOnHand($productVariant->getOnHand() - $quantity);
543
544
        $this->objectManager->flush();
545
    }
546
547
    /**
548
     * @Given /^(this product) is tracked by the inventory$/
549
     * @Given /^(?:|the )("[^"]+" product) is(?:| also) tracked by the inventory$/
550
     */
551
    public function thisProductIsTrackedByTheInventory(ProductInterface $product)
552
    {
553
        /** @var ProductVariantInterface $productVariant */
554
        $productVariant = $this->defaultVariantResolver->getVariant($product);
555
        $productVariant->setTracked(true);
556
557
        $this->objectManager->flush();
558
    }
559
560
    /**
561
     * @Given /^(this product) is available in "([^"]+)" ([^"]+) priced at ("[^"]+")$/
562
     */
563
    public function thisProductIsAvailableInSize(ProductInterface $product, $optionValueName, $optionName, $price)
564
    {
565
        /** @var ProductVariantInterface $variant */
566
        $variant = $this->productVariantFactory->createNew();
567
568
        $optionValue = $this->sharedStorage->get(sprintf('%s_option_%s_value', $optionValueName, $optionName));
569
570
        $variant->addOptionValue($optionValue);
571
        $variant->addChannelPricing($this->createChannelPricingForChannel($price, $this->sharedStorage->get('channel')));
572
        $variant->setCode(sprintf('%s_%s', $product->getCode(), $optionValueName));
573
        $variant->setName($product->getName());
574
575
        $product->addVariant($variant);
576
        $this->objectManager->flush();
577
    }
578
579
    /**
580
     * @Given the :product product's :optionValueName size belongs to :shippingCategory shipping category
581
     */
582
    public function thisProductSizeBelongsToShippingCategory(ProductInterface $product, $optionValueName, ShippingCategoryInterface $shippingCategory)
583
    {
584
        $code = sprintf('%s_%s', $product->getCode(), $optionValueName);
585
        /** @var ProductVariantInterface $productVariant */
586
        $productVariant = $product->getVariants()->filter(function ($variant) use ($code) {
587
            return $code === $variant->getCode();
588
        })->first();
589
590
        Assert::notNull($productVariant, sprintf('Product variant with given code %s not exists!', $code));
591
592
        $productVariant->setShippingCategory($shippingCategory);
593
        $this->objectManager->flush();
594
    }
595
596
    /**
597
     * @Given /^(this product) has (this product option)$/
598
     * @Given /^(this product) has (?:a|an) ("[^"]+" option)$/
599
     */
600
    public function thisProductHasThisProductOption(ProductInterface $product, ProductOptionInterface $option)
601
    {
602
        $product->addOption($option);
603
604
        $this->objectManager->flush();
605
    }
606
607
    /**
608
     * @Given /^there are ([^"]+) units of ("[^"]+" variant of product "[^"]+") available in the inventory$/
609
     */
610
    public function thereAreItemsOfProductInVariantAvailableInTheInventory($quantity, ProductVariantInterface $productVariant)
611
    {
612
        $productVariant->setTracked(true);
613
        $productVariant->setOnHand($quantity);
614
615
        $this->objectManager->flush();
616
    }
617
618
    /**
619
     * @Given /^the ("[^"]+" product variant) is tracked by the inventory$/
620
     */
621
    public function theProductVariantIsTrackedByTheInventory(ProductVariantInterface $productVariant)
622
    {
623
        $productVariant->setTracked(true);
624
625
        $this->objectManager->flush();
626
    }
627
628
    /**
629
     * @Given /^(this product)'s price is ("[^"]+")$/
630
     * @Given /^the (product "[^"]+") changed its price to ("[^"]+")$/
631
     * @Given /^(this product) price has been changed to ("[^"]+")$/
632
     */
633
    public function theProductChangedItsPriceTo(ProductInterface $product, $price)
634
    {
635
        /** @var ProductVariantInterface $productVariant */
636
        $productVariant = $this->defaultVariantResolver->getVariant($product);
637
        $channelPricing = $productVariant->getChannelPricingForChannel($this->sharedStorage->get('channel'));
638
        $channelPricing->setPrice($price);
639
640
        $this->objectManager->flush();
641
    }
642
643
    /**
644
     * @Given /^(this product)(?:| also) has an image "([^"]+)" with "([^"]+)" type$/
645
     * @Given /^the ("[^"]+" product)(?:| also) has an image "([^"]+)" with "([^"]+)" type$/
646
     * @Given /^(it)(?:| also) has an image "([^"]+)" with "([^"]+)" type$/
647
     */
648
    public function thisProductHasAnImageWithType(ProductInterface $product, $imagePath, $imageType)
649
    {
650
        $filesPath = $this->getParameter('files_path');
651
652
        /** @var ImageInterface $productImage */
653
        $productImage = $this->productImageFactory->createNew();
654
        $productImage->setFile(new UploadedFile($filesPath.$imagePath, basename($imagePath)));
655
        $productImage->setType($imageType);
656
        $this->imageUploader->upload($productImage);
657
658
        $product->addImage($productImage);
659
660
        $this->objectManager->flush($product);
661
    }
662
663
    /**
664
     * @Given /^(this product) belongs to ("([^"]+)" shipping category)$/
665
     * @Given product :product shipping category has been changed to :shippingCategory
666
     */
667
    public function thisProductBelongsToShippingCategory(ProductInterface $product, ShippingCategoryInterface $shippingCategory)
668
    {
669
        $product->getVariants()->first()->setShippingCategory($shippingCategory);
670
        $this->objectManager->flush();
671
    }
672
673
    /**
674
     * @Given /^(this product) has been disabled$/
675
     */
676
    public function thisProductHasBeenDisabled(ProductInterface $product)
677
    {
678
        $product->disable();
679
        $this->objectManager->flush();
680
    }
681
682
    /**
683
     * @param string $price
684
     *
685
     * @return int
686
     */
687
    private function getPriceFromString($price)
688
    {
689
        return (int) round($price * 100, 2);
690
    }
691
692
    /**
693
     * @param string $productName
694
     * @param int $price
695
     * @param ChannelInterface|null $channel
696
     *
697
     * @return ProductInterface
698
     */
699
    private function createProduct($productName, $price = 100, ChannelInterface $channel = null)
700
    {
701
        if (null === $channel && $this->sharedStorage->has('channel')) {
702
            $channel = $this->sharedStorage->get('channel');
703
        }
704
705
        /** @var ProductInterface $product */
706
        $product = $this->productFactory->createWithVariant();
707
708
        $product->setCode(StringInflector::nameToUppercaseCode($productName));
709
        $product->setName($productName);
710
        $product->setSlug($this->slugGenerator->generate($productName));
711
712
        if (null !== $channel) {
713
            $product->addChannel($channel);
714
715
            foreach ($channel->getLocales() as $locale) {
716
                $product->setFallbackLocale($locale->getCode());
717
                $product->setCurrentLocale($locale->getCode());
718
719
                $product->setName($productName);
720
                $product->setSlug($this->slugGenerator->generate($productName));
721
            }
722
        }
723
724
        /** @var ProductVariantInterface $productVariant */
725
        $productVariant = $this->defaultVariantResolver->getVariant($product);
726
727
        if (null !== $channel) {
728
            $productVariant->addChannelPricing($this->createChannelPricingForChannel($price, $channel));
729
        }
730
731
        $productVariant->setCode($product->getCode());
732
        $productVariant->setName($product->getName());
733
734
        return $product;
735
    }
736
737
    /**
738
     * @param ProductOptionInterface $option
739
     * @param string $value
740
     * @param string $code
741
     *
742
     * @return ProductOptionValueInterface
743
     */
744
    private function addProductOption(ProductOptionInterface $option, $value, $code)
745
    {
746
        /** @var ProductOptionValueInterface $optionValue */
747
        $optionValue = $this->productOptionValueFactory->createNew();
748
749
        $optionValue->setValue($value);
750
        $optionValue->setCode($code);
751
        $optionValue->setOption($option);
752
753
        $option->addValue($optionValue);
754
755
        return $optionValue;
756
    }
757
758
    /**
759
     * @param ProductInterface $product
760
     */
761
    private function saveProduct(ProductInterface $product)
762
    {
763
        $this->productRepository->add($product);
764
        $this->sharedStorage->set('product', $product);
765
    }
766
767
    /**
768
     * @param string $name
769
     *
770
     * @return NodeElement
771
     */
772
    private function getParameter($name)
773
    {
774
        return isset($this->minkParameters[$name]) ? $this->minkParameters[$name] : null;
775
    }
776
777
    /**
778
     * @param ProductInterface $product
779
     * @param $productVariantName
780
     * @param int $price
781
     * @param string $code
782
     * @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...
783
     * @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...
784
     * @param bool $shippingRequired
785
     *
786
     * @return ProductVariantInterface
787
     */
788
    private function createProductVariant(
789
        ProductInterface $product,
790
        $productVariantName,
791
        $price,
792
        $code,
793
        ChannelInterface $channel = null,
794
        $position = null,
795
        $shippingRequired = true
796
    ) {
797
        $product->setVariantSelectionMethod(ProductInterface::VARIANT_SELECTION_CHOICE);
798
799
        /** @var ProductVariantInterface $variant */
800
        $variant = $this->productVariantFactory->createNew();
801
802
        $variant->setName($productVariantName);
803
        $variant->setCode($code);
804
        $variant->setProduct($product);
805
        $variant->addChannelPricing($this->createChannelPricingForChannel($price, $channel));
806
        $variant->setPosition($position);
807
        $variant->setShippingRequired($shippingRequired);
808
809
        $product->addVariant($variant);
810
811
        $this->objectManager->flush();
812
        $this->sharedStorage->set('variant', $variant);
813
814
        return $variant;
815
    }
816
817
    /**
818
     * @param ProductInterface $product
819
     * @param string $name
820
     * @param string $locale
821
     */
822
    private function addProductTranslation(ProductInterface $product, $name, $locale)
823
    {
824
        /** @var ProductTranslationInterface|TranslationInterface $translation */
825
        $translation = $product->getTranslation($locale);
826
        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...
827
            $translation = $this->productTranslationFactory->createNew();
828
        }
829
830
        $translation->setLocale($locale);
831
        $translation->setName($name);
832
        $translation->setSlug($this->slugGenerator->generate($name));
833
834
        $product->addTranslation($translation);
835
    }
836
837
    /**
838
     * @param ProductVariantInterface $productVariant
839
     * @param string $name
840
     * @param string $locale
841
     */
842
    private function addProductVariantTranslation(ProductVariantInterface $productVariant, $name, $locale)
843
    {
844
        /** @var ProductVariantTranslationInterface|TranslationInterface $translation */
845
        $translation = $this->productVariantTranslationFactory->createNew();
846
        $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...
847
        $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...
848
849
        $productVariant->addTranslation($translation);
0 ignored issues
show
Bug introduced by
It seems like $translation defined by $this->productVariantTra...ionFactory->createNew() on line 845 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...
850
    }
851
852
    /**
853
     * @param int $price
854
     * @param ChannelInterface|null $channel
855
     *
856
     * @return ChannelPricingInterface
857
     */
858
    private function createChannelPricingForChannel($price, ChannelInterface $channel = null)
859
    {
860
        /** @var ChannelPricingInterface $channelPricing */
861
        $channelPricing = $this->channelPricingFactory->createNew();
862
        $channelPricing->setPrice($price);
863
        $channelPricing->setChannel($channel);
864
865
        return $channelPricing;
866
    }
867
}
868