Completed
Push — master ( 99e244...bf2eb3 )
by Paweł
204:07 queued 189:10
created

CouponGenerator::assertGenerationIsPossible()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 6
rs 9.4285
cc 2
eloc 3
nc 2
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
namespace Sylius\Component\Promotion\Generator;
13
14
use Doctrine\Common\Persistence\ObjectManager;
15
use Sylius\Component\Promotion\Exception\FailedGenerationException;
16
use Sylius\Component\Promotion\Model\CouponInterface;
17
use Sylius\Component\Promotion\Model\PromotionInterface;
18
use Sylius\Component\Promotion\Repository\CouponRepositoryInterface;
19
use Sylius\Component\Resource\Factory\FactoryInterface;
20
use Webmozart\Assert\Assert;
21
22
/**
23
 * @author Paweł Jędrzejewski <[email protected]>
24
 */
25
class CouponGenerator implements CouponGeneratorInterface
26
{
27
    /**
28
     * @var FactoryInterface
29
     */
30
    protected $couponFactory;
31
32
    /**
33
     * @var CouponRepositoryInterface
34
     */
35
    protected $couponRepository;
36
37
    /**
38
     * @var ObjectManager
39
     */
40
    protected $objectManager;
41
42
    /**
43
     * @var GenerationPolicyInterface
44
     */
45
    protected $generationPolicy;
46
47
    /**
48
     * @var CouponInterface[]
49
     */
50
    protected $generatedCoupons = [];
51
52
    /**
53
     * @param FactoryInterface $couponFactory
54
     * @param CouponRepositoryInterface $couponRepository
55
     * @param ObjectManager $objectManager
56
     * @param GenerationPolicyInterface $generationPolicy
57
     */
58
    public function __construct(
59
        FactoryInterface $couponFactory,
60
        CouponRepositoryInterface $couponRepository,
61
        ObjectManager $objectManager,
62
        GenerationPolicyInterface $generationPolicy
63
    ) {
64
        $this->couponFactory = $couponFactory;
65
        $this->couponRepository = $couponRepository;
66
        $this->objectManager = $objectManager;
67
        $this->generationPolicy = $generationPolicy;
68
    }
69
70
    /**
71
     * {@inheritdoc}
72
     */
73
    public function generate(PromotionInterface $promotion, InstructionInterface $instruction)
74
    {
75
        $this->assertGenerationIsPossible($instruction);
76
        for ($i = 0, $amount = $instruction->getAmount(); $i < $amount; ++$i) {
77
            $code = $this->generateUniqueCode($instruction->getCodeLength());
78
            $coupon = $this->couponFactory->createNew();
79
            $coupon->setPromotion($promotion);
80
            $coupon->setCode($code);
81
            $coupon->setUsageLimit($instruction->getUsageLimit());
82
            $coupon->setExpiresAt($instruction->getExpiresAt());
83
84
            $this->generatedCoupons[$code] = true;
85
86
            $this->objectManager->persist($coupon);
87
        }
88
89
        $this->objectManager->flush();
90
        $this->generatedCoupons = [];
91
    }
92
93
94
    /**
95
     * @param int $codeLength
96
     *
97
     * @return string
98
     */
99
    protected function generateUniqueCode($codeLength)
100
    {
101
        Assert::nullOrRange($codeLength, 1, 40, 'Invalid %d code length should be between %d and %d');
102
103
        do {
104
            $hash = sha1(microtime(true));
105
            $code = strtoupper(substr($hash, 0, $codeLength));
106
        } while ($this->isUsedCode($code));
107
108
        return $code;
109
    }
110
111
    /**
112
     * @param string $code
113
     *
114
     * @return bool
115
     */
116
    protected function isUsedCode($code)
117
    {
118
        if (isset($this->generatedCoupons[$code])) {
119
            return true;
120
        }
121
122
        return null !== $this->couponRepository->findOneBy(['code' => $code]);
123
    }
124
125
    /**
126
     * @param InstructionInterface $instruction
127
     *
128
     * @throws FailedGenerationException
129
     */
130
    private function assertGenerationIsPossible(InstructionInterface $instruction)
131
    {
132
        if (!$this->generationPolicy->isGenerationPossible($instruction)) {
133
            throw new FailedGenerationException($instruction);
134
        }
135
    }
136
}
137