Completed
Push — symfony3-fqcn-sylius-2 ( 026c63...c92ad2 )
by Kamil
31:21 queued 13:20
created

thereIsProductAvailableInGivenChannel()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 5
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
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\Component\Attribute\Factory\AttributeFactoryInterface;
19
use Sylius\Component\Core\Formatter\StringInflector;
20
use Sylius\Component\Core\Model\ChannelInterface;
21
use Sylius\Component\Core\Model\ImageInterface;
22
use Sylius\Component\Core\Model\ProductInterface;
23
use Sylius\Component\Core\Model\ProductTranslationInterface;
24
use Sylius\Component\Core\Model\ProductVariantInterface;
25
use Sylius\Component\Core\Pricing\Calculators;
26
use Sylius\Component\Core\Repository\ProductRepositoryInterface;
27
use Sylius\Behat\Service\SharedStorageInterface;
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\ProductAttributeInterface;
32
use Sylius\Component\Product\Model\ProductAttributeValueInterface;
33
use Sylius\Component\Product\Model\ProductOptionInterface;
34
use Sylius\Component\Product\Model\ProductOptionValueInterface;
35
use Sylius\Component\Resource\Factory\FactoryInterface;
36
use Sylius\Component\Shipping\Model\ShippingCategoryInterface;
37
use Sylius\Component\Resource\Model\TranslationInterface;
38
use Sylius\Component\Taxation\Model\TaxCategoryInterface;
39
use Sylius\Component\Product\Resolver\ProductVariantResolverInterface;
40
use Symfony\Component\HttpFoundation\File\UploadedFile;
41
42
/**
43
 * @author Arkadiusz Krakowiak <[email protected]>
44
 * @author Mateusz Zalewski <[email protected]>
45
 * @author Magdalena Banasiak <[email protected]>
46
 */
47
final class ProductContext implements Context
48
{
49
    /**
50
     * @var SharedStorageInterface
51
     */
52
    private $sharedStorage;
53
54
    /**
55
     * @var ProductRepositoryInterface
56
     */
57
    private $productRepository;
58
59
    /**
60
     * @var ProductFactoryInterface
61
     */
62
    private $productFactory;
63
64
    /**
65
     * @var FactoryInterface
66
     */
67
    private $productTranslationFactory;
68
69
    /**
70
     * @var AttributeFactoryInterface
71
     */
72
    private $productAttributeFactory;
73
74
    /**
75
     * @var FactoryInterface
76
     */
77
    private $productVariantFactory;
78
79
    /**
80
     * @var FactoryInterface
81
     */
82
    private $attributeValueFactory;
83
84
    /**
85
     * @var FactoryInterface
86
     */
87
    private $productOptionFactory;
88
89
    /**
90
     * @var FactoryInterface
91
     */
92
    private $productOptionValueFactory;
93
94
    /**
95
     * @var FactoryInterface
96
     */
97
    private $productImageFactory;
98
99
    /**
100
     * @var ObjectManager
101
     */
102
    private $objectManager;
103
104
    /**
105
     * @var ProductVariantResolverInterface
106
     */
107
    private $defaultVariantResolver;
108
109
    /**
110
     * @var ImageUploaderInterface
111
     */
112
    private $imageUploader;
113
114
    /**
115
     * @var SlugGeneratorInterface
116
     */
117
    private $slugGenerator;
118
119
    /**
120
     * @var array
121
     */
122
    private $minkParameters;
123
124
    /**
125
     * @param SharedStorageInterface $sharedStorage
126
     * @param ProductRepositoryInterface $productRepository
127
     * @param ProductFactoryInterface $productFactory
128
     * @param FactoryInterface $productTranslationFactory
129
     * @param AttributeFactoryInterface $productAttributeFactory
130
     * @param FactoryInterface $attributeValueFactory
131
     * @param FactoryInterface $productVariantFactory
132
     * @param FactoryInterface $productOptionFactory
133
     * @param FactoryInterface $productOptionValueFactory
134
     * @param FactoryInterface $productImageFactory
135
     * @param ObjectManager $objectManager
136
     * @param ProductVariantResolverInterface $defaultVariantResolver
137
     * @param ImageUploaderInterface $imageUploader
138
     * @param SlugGeneratorInterface $slugGenerator
139
     * @param array $minkParameters
140
     */
141
    public function __construct(
142
        SharedStorageInterface $sharedStorage,
143
        ProductRepositoryInterface $productRepository,
144
        ProductFactoryInterface $productFactory,
145
        FactoryInterface $productTranslationFactory,
146
        AttributeFactoryInterface $productAttributeFactory,
147
        FactoryInterface $attributeValueFactory,
148
        FactoryInterface $productVariantFactory,
149
        FactoryInterface $productOptionFactory,
150
        FactoryInterface $productOptionValueFactory,
151
        FactoryInterface $productImageFactory,
152
        ObjectManager $objectManager,
153
        ProductVariantResolverInterface $defaultVariantResolver,
154
        ImageUploaderInterface $imageUploader,
155
        SlugGeneratorInterface $slugGenerator,
156
        array $minkParameters
157
    ) {
158
        $this->sharedStorage = $sharedStorage;
159
        $this->productRepository = $productRepository;
160
        $this->productFactory = $productFactory;
161
        $this->productTranslationFactory = $productTranslationFactory;
162
        $this->productAttributeFactory = $productAttributeFactory;
163
        $this->attributeValueFactory = $attributeValueFactory;
164
        $this->productVariantFactory = $productVariantFactory;
165
        $this->productOptionFactory = $productOptionFactory;
166
        $this->productOptionValueFactory = $productOptionValueFactory;
167
        $this->productImageFactory = $productImageFactory;
168
        $this->objectManager = $objectManager;
169
        $this->defaultVariantResolver = $defaultVariantResolver;
170
        $this->imageUploader = $imageUploader;
171
        $this->slugGenerator = $slugGenerator;
172
        $this->minkParameters = $minkParameters;
173
    }
174
175
    /**
176
     * @Given the store has a product :productName
177
     * @Given the store has a :productName product
178
     * @Given I added a product :productName
179
     * @Given /^the store(?:| also) has a product "([^"]+)" priced at ("[^"]+")$/
180
     */
181
    public function storeHasAProductPricedAt($productName, $price = 0)
182
    {
183
        $product = $this->createProduct($productName, $price);
184
185
        $product->setDescription('Awesome '.$productName);
186
187
        if ($this->sharedStorage->has('channel')) {
188
            $product->addChannel($this->sharedStorage->get('channel'));
189
        }
190
191
        $this->saveProduct($product);
192
    }
193
194
    /**
195
     * @Given the store( also) has a product :productName with code :code
196
     * @Given the store( also) has a product :productName with code :code, created at :date
197
     */
198
    public function storeHasProductWithCode($productName, $code, $date = null)
199
    {
200
        $product = $this->createProduct($productName, 0, $date);
201
202
        $product->setCode($code);
203
204
        if ($this->sharedStorage->has('channel')) {
205
            $product->addChannel($this->sharedStorage->get('channel'));
206
        }
207
208
        $this->saveProduct($product);
209
    }
210
211
    /**
212
     * @Given /^the store(?:| also) has a product "([^"]+)" priced at ("[^"]+") available in (channel "[^"]+") and (channel "[^"]+")$/
213
     */
214
    public function storeHasAProductPricedAtAvailableInChannels($productName, $price = 0, ...$channels)
215
    {
216
        $product = $this->createProduct($productName, $price);
217
218
        $product->setDescription('Awesome '.$productName);
219
220
        foreach ($channels as $channel) {
221
            $product->addChannel($channel);
222
        }
223
224
        $this->saveProduct($product);
225
    }
226
227
    /**
228
     * @Given /^(this product) is named "([^"]+)" (in the "([^"]+)" locale)$/
229
     * @Given /^the (product "[^"]+") is named "([^"]+)" (in the "([^"]+)" locale)$/
230
     */
231
    public function thisProductIsNamedIn(ProductInterface $product, $name, $locale)
232
    {
233
        $this->addProductTranslation($product, $name, $locale);
234
235
        $this->objectManager->flush();
236
    }
237
238
    /**
239
     * @Given /^the store has a product named "([^"]+)" in ("[^"]+" locale) and "([^"]+)" in ("[^"]+" locale)$/
240
     */
241
    public function theStoreHasProductNamedInAndIn($firstName, $firstLocale, $secondName, $secondLocale)
242
    {
243
        $product = $this->createProduct($firstName);
244
245
        $names = [$firstName => $firstLocale, $secondName => $secondLocale];
246
        foreach ($names as $name => $locale) {
247
            $this->addProductTranslation($product, $name, $locale);
248
        }
249
250
        $this->saveProduct($product);
251
    }
252
253
    /**
254
     * @Given the store has a :productName configurable product
255
     */
256
    public function storeHasAConfigurableProduct($productName)
257
    {
258
        /** @var ProductInterface $product */
259
        $product = $this->productFactory->createNew();
260
261
        $product->setName($productName);
262
        $product->setCode(StringInflector::nameToUppercaseCode($productName));
263
        $product->setSlug($this->slugGenerator->generate($productName));
264
265
        $product->setDescription('Awesome '.$productName);
266
267
        if ($this->sharedStorage->has('channel')) {
268
            $channel = $this->sharedStorage->get('channel');
269
            $product->addChannel($channel);
270
        }
271
272
        $this->saveProduct($product);
273
    }
274
275
    /**
276
     * @Given the store has( also) :firstProductName and :secondProductName products
277
     * @Given the store has( also) :firstProductName, :secondProductName and :thirdProductName products
278
     * @Given the store has( also) :firstProductName, :secondProductName, :thirdProductName and :fourthProductName products
279
     */
280
    public function theStoreHasProducts(...$productsNames)
281
    {
282
        foreach ($productsNames as $productName) {
283
            $this->saveProduct($this->createProduct($productName));
284
        }
285
    }
286
287
    /**
288
     * @Given /^(this channel) has "([^"]+)", "([^"]+)", "([^"]+)" and "([^"]+)" products$/
289
     */
290
    public function thisChannelHasProducts(ChannelInterface $channel, ...$productsNames)
291
    {
292
        foreach ($productsNames as $productName) {
293
            $product = $this->createProduct($productName);
294
            $product->addChannel($channel);
295
296
            $this->saveProduct($product);
297
        }
298
    }
299
300
    /**
301
     * @Given /^the (product "[^"]+") has(?:| a) "([^"]+)" variant priced at ("[^"]+")$/
302
     * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+")$/
303
     */
304
    public function theProductHasVariantPricedAt(ProductInterface $product, $productVariantName, $price)
305
    {
306
        $this->createProductVariant(
307
            $product,
308
            $productVariantName,
309
            $price,
310
            StringInflector::nameToUppercaseCode($productVariantName)
311
        );
312
    }
313
314
    /**
315
     * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+") identified by "([^"]+)"$/
316
     */
317
    public function theProductHasVariantPricedAtIdentifiedBy(
318
        ProductInterface $product,
319
        $productVariantName,
320
        $price,
321
        $code
322
    ) {
323
        $this->createProductVariant($product, $productVariantName, $price, $code);
324
    }
325
326
    /**
327
     * @Given /^there is product "([^"]+)" available in ((?:this|that|"[^"]+") channel)$/
328
     * @Given /^the store has a product "([^"]+)" available in ("([^"]+)" channel)$/
329
     */
330
    public function thereIsProductAvailableInGivenChannel($productName, ChannelInterface $channel)
331
    {
332
        $product = $this->createProduct($productName);
333
334
        $product->setDescription('Awesome ' . $productName);
335
        $product->addChannel($channel);
336
337
        $this->saveProduct($product);
338
    }
339
340
    /**
341
     * @Given /^([^"]+) belongs to ("[^"]+" tax category)$/
342
     */
343
    public function productBelongsToTaxCategory(ProductInterface $product, TaxCategoryInterface $taxCategory)
344
    {
345
        /** @var ProductVariantInterface $variant */
346
        $variant = $this->defaultVariantResolver->getVariant($product);
347
        $variant->setTaxCategory($taxCategory);
348
349
        $this->objectManager->flush();
350
    }
351
352
    /**
353
     * @Given /^(it) comes in the following variations:$/
354
     */
355
    public function itComesInTheFollowingVariations(ProductInterface $product, TableNode $table)
356
    {
357
        foreach ($table->getHash() as $variantHash) {
358
            /** @var ProductVariantInterface $variant */
359
            $variant = $this->productVariantFactory->createNew();
360
361
            $variant->setName($variantHash['name']);
362
            $variant->setCode(StringInflector::nameToUppercaseCode($variantHash['name']));
363
            $variant->setPrice($this->getPriceFromString(str_replace(['$', '€', '£'], '', $variantHash['price'])));
364
            $variant->setProduct($product);
365
            $product->addVariant($variant);
366
        }
367
368
        $this->objectManager->flush();
369
    }
370
371
    /**
372
     * @Given /^("[^"]+" variant of product "[^"]+") belongs to ("[^"]+" tax category)$/
373
     */
374
    public function productVariantBelongsToTaxCategory(
375
        ProductVariantInterface $productVariant,
376
        TaxCategoryInterface $taxCategory
377
    ) {
378
        $productVariant->setTaxCategory($taxCategory);
379
        $this->objectManager->flush($productVariant);
380
    }
381
382
    /**
383
     * @Given /^(this product) has ([^"]+) attribute "([^"]+)" with value "([^"]+)"$/
384
     */
385
    public function thisProductHasAttributeWithValue(ProductInterface $product, $productAttributeType, $productAttributeName, $value)
386
    {
387
        $attribute = $this->createProductAttribute($productAttributeType,$productAttributeName);
388
        $attributeValue = $this->createProductAttributeValue($value, $attribute);
389
        $product->addAttribute($attributeValue);
390
391
        $this->objectManager->flush();
392
    }
393
394
    /**
395
     * @Given /^(this product) has percent attribute "([^"]+)" with value ([^"]+)%$/
396
     */
397
    public function thisProductHasPercentAttributeWithValue(ProductInterface $product, $productAttributeName, $value)
398
    {
399
        $attribute = $this->createProductAttribute('percent',$productAttributeName);
400
        $attributeValue = $this->createProductAttributeValue($value/100, $attribute);
401
        $product->addAttribute($attributeValue);
402
403
        $this->objectManager->flush();
404
    }
405
406
    /**
407
     * @Given /^(this product) has ([^"]+) attribute "([^"]+)" set to "([^"]+)"$/
408
     */
409
    public function thisProductHasCheckboxAttributeWithValue(ProductInterface $product, $productAttributeType, $productAttributeName, $value)
410
    {
411
        $attribute = $this->createProductAttribute($productAttributeType, $productAttributeName);
412
        $booleanValue = ('Yes' === $value);
413
        $attributeValue = $this->createProductAttributeValue($booleanValue, $attribute);
0 ignored issues
show
Documentation introduced by
$booleanValue is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
414
        $product->addAttribute($attributeValue);
415
416
        $this->objectManager->flush();
417
    }
418
419
    /**
420
     * @Given /^(this product) has percent attribute "([^"]+)" at position (\d+)$/
421
     */
422
    public function thisProductHasPercentAttributeWithValueAtPosition(ProductInterface $product, $productAttributeName, $position)
423
    {
424
        $attribute = $this->createProductAttribute('percent',$productAttributeName);
425
        $attribute->setPosition($position);
426
        $attributeValue = $this->createProductAttributeValue(rand(1,100)/100, $attribute);
427
428
        $product->addAttribute($attributeValue);
429
430
        $this->objectManager->flush();
431
    }
432
433
    /**
434
     * @Given /^(this product) has ([^"]+) attribute "([^"]+)" with date "([^"]+)"$/
435
     */
436
    public function thisProductHasDateTimeAttributeWithDate(ProductInterface $product, $productAttributeType, $productAttributeName, $date)
437
    {
438
        $attribute = $this->createProductAttribute($productAttributeType, $productAttributeName);
439
        $attributeValue = $this->createProductAttributeValue(new \DateTime($date), $attribute);
0 ignored issues
show
Documentation introduced by
new \DateTime($date) is of type object<DateTime>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
440
441
        $product->addAttribute($attributeValue);
442
443
        $this->objectManager->flush();
444
    }
445
446
    /**
447
     * @Given /^(this product) has option "([^"]+)" with values "([^"]+)" and "([^"]+)"$/
448
     * @Given /^(this product) has option "([^"]+)" with values "([^"]+)", "([^"]+)" and "([^"]+)"$/
449
     */
450
    public function thisProductHasOptionWithValues(ProductInterface $product, $optionName, ...$values)
451
    {
452
        /** @var ProductOptionInterface $option */
453
        $option = $this->productOptionFactory->createNew();
454
455
        $option->setName($optionName);
456
        $option->setCode(StringInflector::nameToUppercaseCode($optionName));
457
458
        $this->sharedStorage->set(sprintf('%s_option', $optionName), $option);
459
460
        foreach ($values as $key => $value) {
461
            $optionValue = $this->addProductOption($option, $value, StringInflector::nameToUppercaseCode($value));
462
            $this->sharedStorage->set(sprintf('%s_option_%s_value', $value, strtolower($optionName)), $optionValue);
463
        }
464
465
        $product->addOption($option);
466
        $product->setVariantSelectionMethod(ProductInterface::VARIANT_SELECTION_MATCH);
467
468
        $this->objectManager->persist($option);
469
        $this->objectManager->flush();
470
    }
471
472
    /**
473
     * @Given /^there (?:is|are) (\d+) unit(?:|s) of (product "([^"]+)") available in the inventory$/
474
     * @When product :product quantity is changed to :quantity
475
     */
476
    public function thereIsQuantityOfProducts($quantity, ProductInterface $product)
477
    {
478
        /** @var ProductVariantInterface $productVariant */
479
        $productVariant = $this->defaultVariantResolver->getVariant($product);
480
        $productVariant->setOnHand($quantity);
481
482
        $this->objectManager->flush();
483
    }
484
485
    /**
486
     * @Given /^the (product "([^"]+)") is out of stock$/
487
     */
488
    public function theProductIsOutOfStock(ProductInterface $product)
489
    {
490
        /** @var ProductVariantInterface $productVariant */
491
        $productVariant = $this->defaultVariantResolver->getVariant($product);
492
        $productVariant->setTracked(true);
493
        $productVariant->setOnHand(0);
494
495
        $this->objectManager->flush();
496
    }
497
498
    /**
499
     * @When other customer has bought :quantity :product products by this time
500
     */
501
    public function otherCustomerHasBoughtProductsByThisTime($quantity, ProductInterface $product)
502
    {
503
        /** @var ProductVariantInterface $productVariant */
504
        $productVariant = $this->defaultVariantResolver->getVariant($product);
505
        $productVariant->setOnHand($productVariant->getOnHand() - $quantity);
506
507
        $this->objectManager->flush();
508
    }
509
510
    /**
511
     * @Given /^(this product) is tracked by the inventory$/
512
     * @Given /^(?:|the )("[^"]+" product) is(?:| also) tracked by the inventory$/
513
     */
514
    public function thisProductIsTrackedByTheInventory(ProductInterface $product)
515
    {
516
        /** @var ProductVariantInterface $productVariant */
517
        $productVariant = $this->defaultVariantResolver->getVariant($product);
518
        $productVariant->setTracked(true);
519
520
        $this->objectManager->flush();
521
    }
522
523
    /**
524
     * @Given /^(this product) is available in "([^"]+)" ([^"]+) priced at ("[^"]+")$/
525
     */
526
    public function thisProductIsAvailableInSize(ProductInterface $product, $optionValueName, $optionName, $price)
527
    {
528
        /** @var ProductVariantInterface $variant */
529
        $variant = $this->productVariantFactory->createNew();
530
531
        $optionValue = $this->sharedStorage->get(sprintf('%s_option_%s_value', $optionValueName, $optionName));
532
533
        $variant->addOptionValue($optionValue);
534
        $variant->setPrice($price);
535
        $variant->setCode(sprintf("%s_%s", $product->getCode(), $optionValueName));
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal %s_%s does not require double quotes, as per coding-style, please use single quotes.

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

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

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

<?php

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

print $doubleQuoted;

will print an indented: Single is Value

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

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

Loading history...
536
537
        $product->addVariant($variant);
538
        $this->objectManager->flush();
539
    }
540
541
    /**
542
     * @Given /^(this product) has (this product option)$/
543
     * @Given /^(this product) has a ("[^"]+" option)$/
544
     * @Given /^(this product) has an ("[^"]+" option)$/
545
     */
546
    public function thisProductHasThisProductOption(ProductInterface $product, ProductOptionInterface $option)
547
    {
548
        $product->addOption($option);
549
550
        $this->objectManager->flush();
551
    }
552
553
    /**
554
     * @Given /^there are ([^"]+) units of ("[^"]+" variant of product "[^"]+") available in the inventory$/
555
     */
556
    public function thereAreItemsOfProductInVariantAvailableInTheInventory($quantity, ProductVariantInterface $productVariant)
557
    {
558
        $productVariant->setTracked(true);
559
        $productVariant->setOnHand($quantity);
560
561
        $this->objectManager->flush();
562
    }
563
564
    /**
565
     * @Given /^the ("[^"]+" product variant) is tracked by the inventory$/
566
     */
567
    public function theProductVariantIsTrackedByTheInventory(ProductVariantInterface $productVariant)
568
    {
569
        $productVariant->setTracked(true);
570
571
        $this->objectManager->flush();
572
    }
573
574
    /**
575
     * @Given /^(this product)'s price is ("[^"]+")$/
576
     * @Given /^the (product "[^"]+") changed its price to ("[^"]+")$/
577
     */
578
    public function theProductChangedItsPriceTo(ProductInterface $product, $price)
579
    {
580
        /** @var ProductVariantInterface $productVariant */
581
        $productVariant = $this->defaultVariantResolver->getVariant($product);
582
        $productVariant->setPrice($price);
583
584
        $this->objectManager->flush();
585
    }
586
587
    /**
588
     * @Given /^(this product) has(?:| also) an image "([^"]+)" with a code "([^"]+)"$/
589
     * @Given /^the ("[^"]+" product) has(?:| also) an image "([^"]+)" with a code "([^"]+)"$/
590
     */
591
    public function thisProductHasAnImageWithACode(ProductInterface $product, $imagePath, $imageCode)
592
    {
593
        $filesPath = $this->getParameter('files_path');
594
595
        /** @var ImageInterface $productImage */
596
        $productImage = $this->productImageFactory->createNew();
597
        $productImage->setFile(new UploadedFile($filesPath.$imagePath, basename($imagePath)));
598
        $productImage->setCode($imageCode);
599
        $this->imageUploader->upload($productImage);
600
601
        $product->addImage($productImage);
602
603
        $this->objectManager->flush($product);
604
    }
605
606
    /**
607
     * @Given /^(it) has different prices for different channels and currencies$/
608
     */
609
    public function itHasDifferentPricesForDifferentChannelsAndCurrencies(ProductInterface $product)
610
    {
611
        /** @var ProductVariantInterface $variant */
612
        $variant = $this->defaultVariantResolver->getVariant($product);
613
614
        $variant->setPricingCalculator(Calculators::CHANNEL_AND_CURRENCY_BASED);
615
    }
616
617
    /**
618
     * @Given /^(it) has price ("[^"]+") for ("[^"]+" channel) and "([^"]+)" currency$/
619
     */
620
    public function itHasPriceForChannelAndCurrency(
621
        ProductInterface $product,
622
        $price,
623
        ChannelInterface $channel,
624
        $currency
625
    ) {
626
        /** @var ProductVariantInterface $variant */
627
        $variant = $this->defaultVariantResolver->getVariant($product);
628
629
        $pricingConfiguration = $variant->getPricingConfiguration();
630
        $pricingConfiguration[$channel->getCode()][$currency] = $price;
631
632
        $variant->setPricingConfiguration($pricingConfiguration);
633
634
        $this->objectManager->flush();
635
    }
636
637
    /**
638
     * @Given /^(this product) belongs to ("([^"]+)" shipping category)$/
639
     */
640
    public function thisProductBelongsToShippingCategory(ProductInterface $product, ShippingCategoryInterface $shippingCategory)
641
    {
642
        $product->setShippingCategory($shippingCategory);
643
        $this->objectManager->flush();
644
    }
645
646
    /**
647
     * @param string $type
648
     * @param string $name
649
     * @param string|null $code
650
     *
651
     * @return ProductAttributeInterface
652
     */
653
    private function createProductAttribute($type, $name, $code = null)
654
    {
655
        $productAttribute = $this->productAttributeFactory->createTyped($type);
656
657
        if (null === $code) {
658
            $code = StringInflector::nameToCode($name);
659
        }
660
661
        $productAttribute->setCode($code);
662
        $productAttribute->setName($name);
663
664
        $this->objectManager->persist($productAttribute);
665
666
        return $productAttribute;
667
    }
668
669
    /**
670
     * @param string $value
671
     * @param ProductAttributeInterface $attribute
672
     *
673
     * @return ProductAttributeValueInterface
674
     */
675
    private function createProductAttributeValue($value, ProductAttributeInterface $attribute)
676
    {
677
        /** @var ProductAttributeValueInterface $attributeValue */
678
        $attributeValue = $this->attributeValueFactory->createNew();
679
        $attributeValue->setAttribute($attribute);
680
        $attributeValue->setValue($value);
681
682
        $this->objectManager->persist($attributeValue);
683
684
        return $attributeValue;
685
    }
686
687
    /**
688
     * @param string $price
689
     *
690
     * @return int
691
     */
692
    private function getPriceFromString($price)
693
    {
694
        return (int) round(($price * 100), 2);
695
    }
696
697
    /**
698
     * @param string $productName
699
     * @param int $price
700
     * @param string $date
0 ignored issues
show
Documentation introduced by
Should the type for parameter $date not be string|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...
701
     *
702
     * @return ProductInterface
703
     */
704
    private function createProduct($productName, $price = 0, $date = null)
705
    {
706
        /** @var ProductInterface $product */
707
        $product = $this->productFactory->createWithVariant();
708
709
        $product->setName($productName);
710
        $product->setCode(StringInflector::nameToUppercaseCode($productName));
711
        $product->setSlug($this->slugGenerator->generate($productName));
712
        $product->setCreatedAt(new \DateTime($date));
713
714
        /** @var ProductVariantInterface $productVariant */
715
        $productVariant = $this->defaultVariantResolver->getVariant($product);
716
        $productVariant->setPrice($price);
717
        $productVariant->setCode($product->getCode());
718
719
        return $product;
720
    }
721
722
    /**
723
     * @param ProductOptionInterface $option
724
     * @param string $value
725
     * @param string $code
726
     *
727
     * @return ProductOptionValueInterface
728
     */
729
    private function addProductOption(ProductOptionInterface $option, $value, $code)
730
    {
731
        /** @var ProductOptionValueInterface $optionValue */
732
        $optionValue = $this->productOptionValueFactory->createNew();
733
734
        $optionValue->setValue($value);
735
        $optionValue->setCode($code);
736
        $optionValue->setOption($option);
737
738
        $option->addValue($optionValue);
739
740
        return $optionValue;
741
    }
742
743
    /**
744
     * @param ProductInterface $product
745
     */
746
    private function saveProduct(ProductInterface $product)
747
    {
748
        $this->productRepository->add($product);
749
        $this->sharedStorage->set('product', $product);
750
    }
751
752
    /**
753
     * @param string $name
754
     *
755
     * @return NodeElement
756
     */
757
    private function getParameter($name)
758
    {
759
        return isset($this->minkParameters[$name]) ? $this->minkParameters[$name] : null;
760
    }
761
762
    /**
763
     * @param ProductInterface $product
764
     * @param $productVariantName
765
     * @param int $price
766
     * @param string $code
767
     */
768
    private function createProductVariant(ProductInterface $product, $productVariantName, $price, $code)
769
    {
770
        $product->setVariantSelectionMethod(ProductInterface::VARIANT_SELECTION_CHOICE);
771
772
        /** @var ProductVariantInterface $variant */
773
        $variant = $this->productVariantFactory->createNew();
774
775
        $variant->setName($productVariantName);
776
        $variant->setCode($code);
777
        $variant->setPrice($price);
778
        $variant->setProduct($product);
779
        $product->addVariant($variant);
780
781
        $this->objectManager->flush();
782
783
        $this->sharedStorage->set('variant', $variant);
784
    }
785
786
    /**
787
     * @param ProductInterface $product
788
     * @param string $name
789
     * @param string $locale
790
     */
791
    private function addProductTranslation(ProductInterface $product, $name, $locale)
792
    {
793
        /** @var ProductTranslationInterface|TranslationInterface $translation */
794
        $translation = $this->productTranslationFactory->createNew();
795
        $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\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...
796
        $translation->setName($name);
0 ignored issues
show
Bug introduced by
The method setName does only exist in Sylius\Component\Core\Mo...uctTranslationInterface, 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...
797
        $translation->setSlug($this->slugGenerator->generate($name));
0 ignored issues
show
Bug introduced by
The method setSlug does only exist in Sylius\Component\Core\Mo...uctTranslationInterface, 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...
798
799
        $product->addTranslation($translation);
0 ignored issues
show
Bug introduced by
It seems like $translation defined by $this->productTranslationFactory->createNew() on line 794 can also be of type object<Sylius\Component\...ctTranslationInterface>; 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...
800
    }
801
}
802