Completed
Push — 1.3 ( 2923d8...a36271 )
by Kamil
32:20
created

ProductVariantGenerator::generate()   B

Complexity

Conditions 6
Paths 12

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 28
rs 8.8497
c 0
b 0
f 0
cc 6
nc 12
nop 1
1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Sylius\Component\Product\Generator;
15
16
use Sylius\Component\Product\Checker\ProductVariantsParityCheckerInterface;
17
use Sylius\Component\Product\Factory\ProductVariantFactoryInterface;
18
use Sylius\Component\Product\Model\ProductInterface;
19
use Sylius\Component\Product\Model\ProductVariantInterface;
20
use Sylius\Component\Resource\Exception\VariantWithNoOptionsValuesException;
21
use Webmozart\Assert\Assert;
22
23
final class ProductVariantGenerator implements ProductVariantGeneratorInterface
24
{
25
    /** @var ProductVariantFactoryInterface */
26
    private $productVariantFactory;
27
28
    /** @var CartesianSetBuilder */
29
    private $setBuilder;
30
31
    /** @var ProductVariantsParityCheckerInterface */
32
    private $variantsParityChecker;
33
34
    public function __construct(
35
        ProductVariantFactoryInterface $productVariantFactory,
36
        ProductVariantsParityCheckerInterface $variantsParityChecker
37
    ) {
38
        $this->productVariantFactory = $productVariantFactory;
39
        $this->setBuilder = new CartesianSetBuilder();
40
        $this->variantsParityChecker = $variantsParityChecker;
41
    }
42
43
    /**
44
     * {@inheritdoc}
45
     */
46
    public function generate(ProductInterface $product): void
47
    {
48
        Assert::true($product->hasOptions(), 'Cannot generate variants for an object without options.');
49
50
        $optionSet = [];
51
        $optionMap = [];
52
53
        foreach ($product->getOptions() as $key => $option) {
54
            foreach ($option->getValues() as $value) {
55
                $optionSet[$key][] = $value->getCode();
56
                $optionMap[$value->getCode()] = $value;
57
            }
58
        }
59
60
        if (empty($optionSet)) {
61
            throw new VariantWithNoOptionsValuesException();
62
        }
63
64
        $permutations = $this->setBuilder->build($optionSet);
65
66
        foreach ($permutations as $permutation) {
67
            $variant = $this->createVariant($product, $optionMap, $permutation);
68
69
            if (!$this->variantsParityChecker->checkParity($variant, $product)) {
70
                $product->addVariant($variant);
71
            }
72
        }
73
    }
74
75
    private function createVariant(ProductInterface $product, array $optionMap, $permutation): ProductVariantInterface
76
    {
77
        /** @var ProductVariantInterface $variant */
78
        $variant = $this->productVariantFactory->createForProduct($product);
79
        $this->addOptionValue($variant, $optionMap, $permutation);
80
81
        return $variant;
82
    }
83
84
    private function addOptionValue(ProductVariantInterface $variant, array $optionMap, $permutation): void
85
    {
86
        if (!is_array($permutation)) {
87
            $variant->addOptionValue($optionMap[$permutation]);
88
89
            return;
90
        }
91
92
        foreach ($permutation as $code) {
93
            $variant->addOptionValue($optionMap[$code]);
94
        }
95
    }
96
}
97