Completed
Push — master ( 60b5cc...359431 )
by Michał
458:10 queued 444:50
created

ProductContext::thereIsQuantityOfProducts()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
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 Doctrine\Common\Persistence\ObjectManager;
17
use Sylius\Component\Attribute\Factory\AttributeFactoryInterface;
18
use Sylius\Component\Core\Formatter\StringInflector;
19
use Sylius\Component\Core\Model\ChannelInterface;
20
use Sylius\Component\Core\Model\ProductInterface;
21
use Sylius\Component\Core\Model\ProductVariantInterface;
22
use Sylius\Component\Core\Repository\ProductRepositoryInterface;
23
use Sylius\Behat\Service\SharedStorageInterface;
24
use Sylius\Component\Product\Factory\ProductFactoryInterface;
25
use Sylius\Component\Product\Model\AttributeInterface;
26
use Sylius\Component\Product\Model\AttributeValueInterface;
27
use Sylius\Component\Product\Model\OptionInterface;
28
use Sylius\Component\Product\Model\OptionValueInterface;
29
use Sylius\Component\Resource\Factory\FactoryInterface;
30
use Sylius\Component\Taxation\Model\TaxCategoryInterface;
31
32
/**
33
 * @author Arkadiusz Krakowiak <[email protected]>
34
 * @author Mateusz Zalewski <[email protected]>
35
 * @author Magdalena Banasiak <[email protected]>
36
 */
37
final class ProductContext implements Context
38
{
39
    /**
40
     * @var SharedStorageInterface
41
     */
42
    private $sharedStorage;
43
44
    /**
45
     * @var ProductRepositoryInterface
46
     */
47
    private $productRepository;
48
49
    /**
50
     * @var ProductFactoryInterface
51
     */
52
    private $productFactory;
53
54
    /**
55
     * @var AttributeFactoryInterface
56
     */
57
    private $productAttributeFactory;
58
59
    /**
60
     * @var FactoryInterface
61
     */
62
    private $productVariantFactory;
63
64
    /**
65
     * @var FactoryInterface
66
     */
67
    private $attributeValueFactory;
68
69
    /**
70
     * @var FactoryInterface
71
     */
72
    private $productOptionFactory;
73
74
    /**
75
     * @var FactoryInterface
76
     */
77
    private $productOptionValueFactory;
78
79
    /**
80
     * @var ObjectManager
81
     */
82
    private $objectManager;
83
84
    /**
85
     * @param SharedStorageInterface $sharedStorage
86
     * @param ProductRepositoryInterface $productRepository
87
     * @param ProductFactoryInterface $productFactory
88
     * @param AttributeFactoryInterface $productAttributeFactory
89
     * @param FactoryInterface $productVariantFactory
90
     * @param FactoryInterface $attributeValueFactory
91
     * @param FactoryInterface $productOptionFactory
92
     * @param FactoryInterface $productOptionValueFactory
93
     * @param ObjectManager $objectManager
94
     */
95
    public function __construct(
96
        SharedStorageInterface $sharedStorage,
97
        ProductRepositoryInterface $productRepository,
98
        ProductFactoryInterface $productFactory,
99
        AttributeFactoryInterface $productAttributeFactory,
100
        FactoryInterface $attributeValueFactory,
101
        FactoryInterface $productVariantFactory,
102
        FactoryInterface $productOptionFactory,
103
        FactoryInterface $productOptionValueFactory,
104
        ObjectManager $objectManager
105
    ) {
106
        $this->sharedStorage = $sharedStorage;
107
        $this->productRepository = $productRepository;
108
        $this->productFactory = $productFactory;
109
        $this->productAttributeFactory = $productAttributeFactory;
110
        $this->attributeValueFactory = $attributeValueFactory;
111
        $this->productVariantFactory = $productVariantFactory;
112
        $this->productOptionFactory = $productOptionFactory;
113
        $this->productOptionValueFactory = $productOptionValueFactory;
114
        $this->objectManager = $objectManager;
115
    }
116
117
    /**
118
     * @Given the store has a product :productName
119
     * @Given the store has a :productName product
120
     * @Given /^the store has a product "([^"]+)" priced at ("[^"]+")$/
121
     */
122
    public function storeHasAProductPricedAt($productName, $price = 0)
123
    {
124
        $product = $this->createProduct($productName, $price);
125
126
        $product->setDescription('Awesome '.$productName);
127
128
        if ($this->sharedStorage->has('channel')) {
129
            $channel = $this->sharedStorage->get('channel');
130
            $product->addChannel($channel);
131
        }
132
133
        $this->saveProduct($product);
134
    }
135
136
    /**
137
     * @Given the store has a :productName configurable product
138
     */
139
    public function storeHasAConfigurableProduct($productName)
140
    {
141
        $product = $this->productFactory->createNew();
142
143
        $product->setName($productName);
144
        $product->setCode($this->convertToCode($productName));
145
        $product->setDescription('Awesome '.$productName);
146
147
        $this->saveProduct($product);
148
    }
149
150
    /**
151
     * @Given the store has :firstProductName and :secondProductName products
152
     */
153
    public function theStoreHasAProductAnd($firstProductName, $secondProductName)
154
    {
155
        $this->saveProduct($this->createProduct($firstProductName));
156
        $this->saveProduct($this->createProduct($secondProductName));
157
    }
158
159
    /**
160
     * @Given /^the (product "[^"]+") has "([^"]+)" variant priced at ("[^"]+")$/
161
     * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+")$/
162
     */
163
    public function theProductHasVariantPricedAt(ProductInterface $product, $productVariantName, $price)
164
    {
165
        /** @var ProductVariantInterface $variant */
166
        $variant = $this->productVariantFactory->createNew();
167
168
        $variant->setName($productVariantName);
169
        $variant->setCode($this->convertToCode($productVariantName));
170
        $variant->setPrice($price);
171
        $variant->setProduct($product);
172
        $product->addVariant($variant);
173
174
        $this->objectManager->flush();
175
176
        $this->sharedStorage->set('variant', $variant);
177
    }
178
179
    /**
180
     * @Given /^there is product "([^"]+)" available in ((?:this|that|"[^"]+") channel)$/
181
     * @Given /^the store has a product "([^"]+)" available in ("([^"]+)" channel)$/
182
     */
183
    public function thereIsProductAvailableInGivenChannel($productName, ChannelInterface $channel)
184
    {
185
        $product = $this->createProduct($productName);
186
187
        $product->setDescription('Awesome ' . $productName);
188
        $product->addChannel($channel);
189
190
        $this->saveProduct($product);
191
    }
192
193
    /**
194
     * @Given /^([^"]+) belongs to ("[^"]+" tax category)$/
195
     */
196
    public function productBelongsToTaxCategory(ProductInterface $product, TaxCategoryInterface $taxCategory)
197
    {
198
        $product->getFirstVariant()->setTaxCategory($taxCategory);
199
        $this->objectManager->flush();
200
    }
201
202
    /**
203
     * @Given /^(it) comes in the following variations:$/
204
     */
205
    public function itComesInTheFollowingVariations(ProductInterface $product, TableNode $table)
206
    {
207
        foreach ($table->getHash() as $variantHash) {
208
            /** @var ProductVariantInterface $variant */
209
            $variant = $this->productVariantFactory->createNew();
210
211
            $variant->setName($variantHash['name']);
212
            $variant->setCode($this->convertToCode($variantHash['name']));
213
            $variant->setPrice($this->getPriceFromString(str_replace(['$', '€', '£'], '', $variantHash['price'])));
214
            $variant->setProduct($product);
215
            $product->addVariant($variant);
216
        }
217
218
        $this->objectManager->flush();
219
    }
220
221
    /**
222
     * @Given /^("[^"]+" variant of product "[^"]+") belongs to ("[^"]+" tax category)$/
223
     */
224
    public function productVariantBelongsToTaxCategory(
225
        ProductVariantInterface $productVariant,
226
        TaxCategoryInterface $taxCategory
227
    ) {
228
        $productVariant->setTaxCategory($taxCategory);
229
        $this->objectManager->flush($productVariant);
230
    }
231
232
    /**
233
     * @Given /^(this product) has ([^"]+) attribute "([^"]+)" with value "([^"]+)"$/
234
     */
235
    public function thisProductHasAttributeWithValue(ProductInterface $product, $productAttributeType, $productAttributeName, $value)
236
    {
237
        $attribute = $this->createProductAttribute($productAttributeType,$productAttributeName);
238
        $attributeValue = $this->createProductAttributeValue($value, $attribute);
239
        $product->addAttribute($attributeValue);
240
241
        $this->objectManager->flush();
242
    }
243
244
    /**
245
     * @Given /^(this product) has percent attribute "([^"]+)" with value ([^"]+)%$/
246
     */
247
    public function thisProductHasPercentAttributeWithValue(ProductInterface $product, $productAttributeName, $value)
248
    {
249
        $attribute = $this->createProductAttribute('percent',$productAttributeName);
250
        $attributeValue = $this->createProductAttributeValue($value/100, $attribute);
251
        $product->addAttribute($attributeValue);
252
253
        $this->objectManager->flush();
254
    }
255
256
    /**
257
     * @Given /^(this product) has ([^"]+) attribute "([^"]+)" set to "([^"]+)"$/
258
     */
259
    public function thisProductHasCheckboxAttributeWithValue(ProductInterface $product, $productAttributeType, $productAttributeName, $value)
260
    {
261
        $attribute = $this->createProductAttribute($productAttributeType, $productAttributeName);
262
        $booleanValue = ('Yes' === $value);
263
        $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...
264
        $product->addAttribute($attributeValue);
265
266
        $this->objectManager->flush();
267
    }
268
269
    /**
270
     * @Given /^(this product) has ([^"]+) attribute "([^"]+)" with date "([^"]+)"$/
271
     */
272
    public function thisProductHasDateTimeAttributeWithDate(ProductInterface $product, $productAttributeType, $productAttributeName, $date)
273
    {
274
        $attribute = $this->createProductAttribute($productAttributeType, $productAttributeName);
275
        $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...
276
277
        $product->addAttribute($attributeValue);
278
279
        $this->objectManager->flush();
280
    }
281
282
    /**
283
     * @Given /^(this product) has option "([^"]+)" with values "([^"]+)" and "([^"]+)"$/
284
     */
285
    public function thisProductHasOptionWithValues(ProductInterface $product, $optionName, $firstValue, $secondValue)
286
    {
287
        /** @var OptionInterface $variant */
288
        $option = $this->productOptionFactory->createNew();
289
290
        $option->setName($optionName);
291
        $option->setCode('PO1');
292
293
        /** @var OptionValueInterface $optionValue */
294
        $firstOptionValue = $this->productOptionValueFactory->createNew();
295
296
        $firstOptionValue->setValue($firstValue);
297
        $firstOptionValue->setCode('POV1');
298
        $firstOptionValue->setOption($option);
299
300
        /** @var OptionValueInterface $optionValue */
301
        $secondOptionValue = $this->productOptionValueFactory->createNew();
302
303
        $secondOptionValue->setValue($secondValue);
304
        $secondOptionValue->setCode('POV2');
305
        $secondOptionValue->setOption($option);
306
307
        $option->addValue($firstOptionValue);
308
        $option->addValue($secondOptionValue);
309
310
        $product->addOption($option);
311
        $product->setVariantSelectionMethod(ProductInterface::VARIANT_SELECTION_MATCH);
312
313
        $this->sharedStorage->set(sprintf('%s_option',$optionName), $option);
314
        $this->sharedStorage->set(sprintf('%s_option_value',$firstValue), $firstOptionValue);
315
        $this->sharedStorage->set(sprintf('%s_option_value',$secondValue), $secondOptionValue);
316
317
        $this->objectManager->persist($option);
318
        $this->objectManager->persist($firstOptionValue);
319
        $this->objectManager->persist($secondOptionValue);
320
        $this->objectManager->flush();
321
    }
322
323
    /**
324
     * @Given /^there (?:is|are) (\d+) item(?:s) of (product "([^"]+)") available in the inventory$/
325
     */
326
    public function thereIsQuantityOfProducts($quantity, ProductInterface $product)
327
    {
328
        $this->setProductsQuantity($product, $quantity);
329
    }
330
331
    /**
332
     * @Given /^the (product "([^"]+)") is out of stock$/
333
     */
334
    public function theProductIsNotAvailable(ProductInterface $product)
335
    {
336
        $product->getFirstVariant()->setAvailableOnDemand(false);
0 ignored issues
show
Bug introduced by
The method setAvailableOnDemand() does not exist on Sylius\Component\Core\Mo...ProductVariantInterface. Did you maybe mean setAvailableOn()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
337
338
        $this->setProductsQuantity($product, 0);
339
    }
340
341
    /**
342
     * @Given /^(this product) is available in "([^"]+)" size priced at ("[^"]+")$/
343
     */
344
    public function thisProductIsAvailableInSize(ProductInterface $product, $optionValueName, $price)
345
    {
346
        /** @var ProductVariantInterface $variant */
347
        $variant = $this->productVariantFactory->createNew();
348
349
        $optionValue = $this->sharedStorage->get(sprintf('%s_option_value',$optionValueName));
350
351
        $variant->addOption($optionValue);
352
        $variant->setPrice($price);
353
        $variant->setCode(sprintf("%s_%s", $product->getCode(), $optionValueName));
354
355
        $product->addVariant($variant);
356
        $this->objectManager->flush();
357
    }
358
359
    /**
360
     * @Given /^(this product) has (this product option)$/
361
     * @Given /^(this product) has a ("[^"]+" option)$/
362
     * @Given /^(this product) has an ("[^"]+" option)$/
363
     */
364
    public function thisProductHasThisProductOption(ProductInterface $product, OptionInterface $option)
365
    {
366
        $product->addOption($option);
367
368
        $this->objectManager->flush();
369
    }
370
371
    /**
372
     * @param string $type
373
     * @param string $name
374
     * @param string $code
375
     *
376
     * @return AttributeInterface
377
     */
378
    private function createProductAttribute($type, $name, $code = 'PA112')
379
    {
380
        $productAttribute = $this->productAttributeFactory->createTyped($type);
381
        $productAttribute->setCode($code);
382
        $productAttribute->setName($name);
383
384
        $this->objectManager->persist($productAttribute);
385
386
        return $productAttribute;
387
    }
388
389
    /**
390
     * @param string $value
391
     *
392
     * @return AttributeValueInterface
393
     */
394
    private function createProductAttributeValue($value, AttributeInterface $attribute)
395
    {
396
        /** @var AttributeValueInterface $attributeValue */
397
        $attributeValue = $this->attributeValueFactory->createNew();
398
        $attributeValue->setAttribute($attribute);
399
        $attributeValue->setValue($value);
400
401
        $this->objectManager->persist($attributeValue);
402
403
        return $attributeValue;
404
    }
405
406
    /**
407
     * @param string $price
408
     *
409
     * @return int
410
     */
411
    private function getPriceFromString($price)
412
    {
413
        return (int) round(($price * 100), 2);
414
    }
415
416
    /**
417
     * @param string $productName
418
     * @param int $price
419
     *
420
     * @return ProductInterface
421
     */
422
    private function createProduct($productName, $price = 0)
423
    {
424
        /** @var ProductInterface $product */
425
        $product = $this->productFactory->createWithVariant();
426
427
        $product->setName($productName);
428
        $product->getFirstVariant()->setPrice($price);
429
        $product->setCode($this->convertToCode($productName));
430
        $product->getFirstVariant()->setCode($product->getCode());
431
432
        return $product;
433
    }
434
435
    /**
436
     * @param ProductInterface $product
437
     * @param int $quantity
438
     */
439
    private function setProductsQuantity(ProductInterface $product, $quantity)
440
    {
441
        $product->getFirstVariant()->setOnHand($quantity);
442
443
        $this->saveProduct($product);
444
    }
445
446
    /**
447
     * @param ProductInterface $product
448
     */
449
    private function saveProduct(ProductInterface $product)
450
    {
451
        $this->productRepository->add($product);
452
        $this->sharedStorage->set('product', $product);
453
    }
454
455
    /**
456
     * @param string $productName
457
     *
458
     * @return string
459
     */
460
    private function convertToCode($productName)
461
    {
462
        return StringInflector::nameToUpercaseCode($productName);
463
    }
464
}
465