Completed
Push — master ( b58657...5bf628 )
by Zura
02:02
created

Promocodes::generate()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 32
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
dl 0
loc 32
rs 8.8571
c 1
b 0
f 1
cc 3
eloc 15
nc 4
nop 0
1
<?php
2
3
namespace Gabievi\Promocodes;
4
5
use Gabievi\Promocodes\Model\Promocode;
6
7
class Promocodes
8
{
9
    /**
10
     * Generated codes will be saved here
11
     * to be validated later.
12
     *
13
     * @var array
14
     */
15
    private $codes = [];
16
17
    /**
18
     * Length of code will be calculated from asterisks you have
19
     * set as mask in your config file.
20
     *
21
     * @var int
22
     */
23
    private $length;
24
25
    /**
26
     * Promocodes constructor.
27
     */
28
    public function __construct()
29
    {
30
        $this->codes = Promocode::pluck('code')->toArray();
31
        $this->length = substr_count(config('promocodes.mask'), '*');
32
    }
33
34
    /**
35
     * Here will be generated single code using your parameters from config.
36
     *
37
     * @return string
38
     */
39
    private function generate()
40
    {
41
        $characters = config('promocodes.characters');
42
        $mask = config('promocodes.mask');
43
        $promocode = '';
44
        $random = [];
45
46
        // take needed length of string from characters and randomize it
47
        for ($i = 1; $i <= $this->length; $i++) {
48
            $character = $characters[rand(0, strlen($characters) - 1)];
49
            $random[] = $character;
50
        }
51
52
        // shuffle randomized characters
53
        shuffle($random);
54
55
        // set prefix for promocode
56
        $promocode .= $this->getPrefix();
57
58
        // loop through asterisks and change with random symbol
59
        for ($i = 0; $i < count($random); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
60
            $mask = preg_replace('/\*/', $random[$i], $mask, 1);
61
        }
62
63
        // set updated mask as code
64
        $promocode .= $mask;
65
66
        // set suffix for promocode
67
        $promocode .= $this->getSuffix();
68
69
        return $promocode;
70
    }
71
72
    /**
73
     * Generate prefix with separator for promocode.
74
     *
75
     * @return string
76
     */
77
    private function getPrefix()
78
    {
79
        return (bool) config('promocodes.prefix') ? config('promocodes.prefix').config('promocodes.separator') : '';
80
    }
81
82
    /**
83
     * Generate suffix with separator for promocode.
84
     *
85
     * @return string
86
     */
87
    private function getSuffix()
88
    {
89
        return (bool) config('promocodes.suffix') ? config('promocodes.separator').config('promocodes.suffix') : '';
90
    }
91
92
    /**
93
     * Your code will be validated to be unique for one request.
94
     *
95
     * @param $collection
96
     * @param $new
97
     *
98
     * @return bool
99
     */
100
    private function validate($collection, $new)
101
    {
102
        return !in_array($new, array_merge($collection, $this->codes));
103
    }
104
105
    /**
106
     * Generates promocodes as many as you wish.
107
     *
108
     * @param int $amount
109
     *
110
     * @return array
111
     */
112
    public function output($amount = 1)
113
    {
114
        $collection = [];
115
116
        for ($i = 1; $i <= $amount; $i++) {
117
            $random = $this->generate();
118
119
            while (!$this->validate($collection, $random)) {
120
                $random = $this->generate();
121
            }
122
123
            $collection[] = $random;
124
        }
125
126
        return $collection;
127
    }
128
129
    /**
130
     * Save promocodes into database
131
     * Successful insert returns generated promocodes
132
     * Fail will return NULL.
133
     *
134
     * @param int   $amount
135
     * @param null  $reward
136
     * @param array $data
137
     *
138
     * @return static
139
     */
140 View Code Duplication
    public function create($amount = 1, $reward = null, array $data = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
141
    {
142
        $records = [];
143
144
        // loop though each promocodes required
145
        foreach ($this->output($amount) as $code) {
146
            $records[] = [
147
                'code' => $code,
148
                'reward' => $reward,
149
                'data' => json_encode($data),
150
            ];
151
        }
152
153
        // check for insertion of record
154
        if (Promocode::insert($records)) {
0 ignored issues
show
Bug introduced by
The method insert() does not exist on Gabievi\Promocodes\Model\Promocode. Did you maybe mean insertAndSetId()?

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...
155
            return collect($records);
156
        }
157
158
        return collect([]);
159
    }
160
161
    /**
162
     * Check promocode in database if it is valid.
163
     *
164
     * @param $code
165
     *
166
     * @return bool
167
     */
168
    public function check($code)
169
    {
170
        return Promocode::byCode($code)->fresh()->exists();
0 ignored issues
show
Bug introduced by
The method byCode() does not exist on Gabievi\Promocodes\Model\Promocode. Did you maybe mean scopeByCode()?

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...
171
    }
172
173
    /**
174
     * Apply promocode to user that it's used from now.
175
     *
176
     * @param $code
177
     *
178
     * @return mixed
179
     */
180
    public function apply($code)
181
    {
182
        $promocode = Promocode::byCode($code)->fresh();
0 ignored issues
show
Bug introduced by
The method byCode() does not exist on Gabievi\Promocodes\Model\Promocode. Did you maybe mean scopeByCode()?

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...
183
184
        // check if exists not used code
185
        if ($promocode->exists()) {
186
            $record = $promocode->first();
187
            $record->is_used = true;
188
189
            // update promocode as it is used
190
            if ($record->save()) {
191
                return $record ?: true;
192
            }
193
        }
194
195
        return false;
196
    }
197
}
198