1
|
|
|
<?php |
2
|
|
|
declare(strict_types=1); |
3
|
|
|
|
4
|
|
|
namespace Cart\Drivers; |
5
|
|
|
|
6
|
|
|
use Cart\Contracts\CartDriverContract; |
7
|
|
|
use Cart\Contracts\CounterItemContract; |
8
|
|
|
use Cart\Contracts\DiscountContract; |
9
|
|
|
use Cart\Contracts\DiscountDriverContract; |
10
|
|
|
use Cart\Contracts\SetTableDriver; |
11
|
|
|
use Cart\CountOperation\AdditionCount; |
12
|
|
|
use Cart\Traits\Validate; |
13
|
|
|
use Illuminate\Database\Capsule\Manager; |
14
|
|
|
use Illuminate\Support\Collection; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* Class DatabaseDriver |
18
|
|
|
* |
19
|
|
|
* @package Cart\Drivers |
20
|
|
|
*/ |
21
|
|
|
class DatabaseDriver implements CartDriverContract, SetTableDriver, DiscountDriverContract |
22
|
|
|
{ |
23
|
|
|
use Validate; |
24
|
|
|
/** |
25
|
|
|
* @var Manager |
26
|
|
|
*/ |
27
|
|
|
protected $manager; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @var string |
31
|
|
|
*/ |
32
|
|
|
protected $table; |
33
|
|
|
|
34
|
19 |
|
public function __construct(Manager $manager) |
35
|
|
|
{ |
36
|
19 |
|
$this->manager = $manager; |
37
|
19 |
|
$this->setTable(); |
38
|
19 |
|
} |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* Add new item in cart |
42
|
|
|
* @param array $item |
43
|
|
|
* @return bool |
44
|
|
|
*/ |
45
|
4 |
View Code Duplication |
public function add(array $item) : bool |
|
|
|
|
46
|
|
|
{ |
47
|
|
|
// validation structure |
48
|
4 |
|
if ($this->validate($item, ['id', 'user_id']) === false) { |
49
|
1 |
|
return false; |
50
|
|
|
} |
51
|
|
|
|
52
|
3 |
|
if ($this->existUser((int)$item['user_id'])) { |
53
|
2 |
|
if ($this->existItem($item)) { |
54
|
1 |
|
call_user_func([$this, 'incrementItem'], $item); |
55
|
|
|
} else { |
56
|
1 |
|
call_user_func([$this, 'addItem'], $item); |
57
|
|
|
} |
58
|
|
|
} else { |
59
|
1 |
|
$item['count'] = 1; |
60
|
1 |
|
$this->addRow((int)$item['user_id'], inJson([$item])); |
61
|
|
|
} |
62
|
|
|
|
63
|
3 |
|
return true; |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* Remove item from cart |
68
|
|
|
* @param array $item |
69
|
|
|
* @return bool |
70
|
|
|
*/ |
71
|
4 |
|
public function remove(array $item) : bool |
72
|
|
|
{ |
73
|
4 |
|
if ($this->validate($item, ['id', 'user_id']) === false) { |
74
|
1 |
|
return false; |
75
|
|
|
} |
76
|
|
|
|
77
|
3 |
|
$collection = $this->getItems($item['user_id']); |
78
|
|
|
|
79
|
3 |
|
if ($collection->isNotEmpty()) { |
80
|
|
|
$itemFilter = array_filter(fromJson($collection->first()->data, true), function ($value) use ($item) { |
81
|
2 |
|
return $value['id'] != $item['id']; |
82
|
2 |
|
}); |
83
|
|
|
|
84
|
2 |
|
if (count($itemFilter) > 0) { |
85
|
1 |
|
$this->updateRow($item['user_id'], inJson(array_values($itemFilter))); |
86
|
|
|
} else { |
87
|
1 |
|
$this->deleteRow($item['user_id']); |
88
|
|
|
} |
89
|
2 |
|
return true; |
90
|
|
|
} |
91
|
1 |
|
return false; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Clear cart for concrete relation entity |
96
|
|
|
* @param int $entityId |
97
|
|
|
* @return void |
98
|
|
|
*/ |
99
|
1 |
|
public function clear(int $entityId) : void |
100
|
|
|
{ |
101
|
1 |
|
$this->deleteRow($entityId); |
102
|
1 |
|
} |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* Change item(position) |
106
|
|
|
* @param array $item |
107
|
|
|
* @param CounterItemContract $itemContract |
108
|
|
|
* @return bool |
109
|
|
|
*/ |
110
|
4 |
|
public function change(array $item, CounterItemContract $itemContract) : bool |
111
|
|
|
{ |
112
|
4 |
|
if ($this->validate($item, ['id', 'user_id', 'count']) === false) { |
113
|
1 |
|
return false; |
114
|
|
|
} |
115
|
|
|
|
116
|
3 |
|
return $this->counterItem($item['id'], $item['user_id'], $item['count'], $itemContract); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* Get all items to user id |
121
|
|
|
* @param int $userId |
122
|
|
|
* @return array |
123
|
|
|
*/ |
124
|
1 |
|
public function get(int $userId): array |
125
|
|
|
{ |
126
|
1 |
|
$row = $this->getItems($userId); |
127
|
1 |
|
return fromJson($row->toJson(), true); |
|
|
|
|
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* Set custom name table |
132
|
|
|
* @param string $name |
133
|
|
|
*/ |
134
|
19 |
|
public function setTable(string $name = 'cart_items'): void |
135
|
|
|
{ |
136
|
19 |
|
$this->table = $name; |
137
|
19 |
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* @param DiscountContract $strategy |
141
|
|
|
* @param array $items |
142
|
|
|
* @return bool |
143
|
|
|
*/ |
144
|
4 |
|
public function discount(DiscountContract $strategy, array $items) : bool |
145
|
|
|
{ |
146
|
|
|
// validation structure |
147
|
4 |
|
if ($this->validate($items, ['id', 'user_id', 'price']) === false) { |
148
|
1 |
|
return false; |
149
|
|
|
} |
150
|
|
|
|
151
|
3 |
|
$newPrice = $strategy->make($items['price']); |
152
|
3 |
|
$row = $this->getItems($items['user_id']); |
153
|
|
|
|
154
|
3 |
|
if ($row->isNotEmpty()) { |
155
|
|
|
$transformItems = array_map(function ($value) use ($items, $newPrice) { |
156
|
2 |
|
if ($value['id'] == $items['id']) { |
157
|
1 |
|
$value['discount'] = $newPrice; |
158
|
1 |
|
return $value; |
159
|
|
|
} |
160
|
1 |
|
return $value; |
161
|
2 |
|
}, fromJson($row->first()->data, true)); |
162
|
|
|
|
163
|
2 |
|
$this->updateRow($items['user_id'], inJson($transformItems)); |
164
|
2 |
|
return true; |
165
|
|
|
} |
166
|
1 |
|
return false; |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* Check exist User in table cart_items |
171
|
|
|
* @param int $userId |
172
|
|
|
* @return bool |
173
|
|
|
*/ |
174
|
3 |
|
private function existUser(int $userId) : bool |
175
|
|
|
{ |
176
|
3 |
|
return $this->getItems($userId)->count() > 0; |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* Check exit item in json collection |
181
|
|
|
* |
182
|
|
|
* @param array $item |
183
|
|
|
* @return bool |
184
|
|
|
* @internal param int $itemId |
185
|
|
|
* @internal param int $user |
186
|
|
|
*/ |
187
|
2 |
|
private function existItem(array $item) : bool |
188
|
|
|
{ |
189
|
2 |
|
$collection = $this->getItems($item['user_id']); |
190
|
2 |
|
return $collection->make(fromJson($collection->first()->data))->contains('id', $item['id']); |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* Add new Item in collection |
195
|
|
|
* |
196
|
|
|
* @param array $item |
197
|
|
|
* @internal param int $user |
198
|
|
|
*/ |
199
|
1 |
|
private function addItem(array $item) :void |
200
|
|
|
{ |
201
|
1 |
|
$collection = $this->getItems($item['user_id'])->first(); |
202
|
1 |
|
$items = fromJson($collection->data); |
203
|
|
|
|
204
|
1 |
|
$item['count'] = 1; |
205
|
1 |
|
$items[] = $item; |
206
|
|
|
|
207
|
1 |
|
$this->updateRow((int)$item['user_id'], inJson($items)); |
208
|
1 |
|
} |
209
|
|
|
|
210
|
|
|
/** |
211
|
|
|
* Increment Item in json collection |
212
|
|
|
* |
213
|
|
|
* @param array $item |
214
|
|
|
* @internal param int $itemId |
215
|
|
|
* @internal param int $user |
216
|
|
|
*/ |
217
|
1 |
|
private function incrementItem(array $item) :void |
218
|
|
|
{ |
219
|
1 |
|
app()->bind(AdditionCount::class, AdditionCount::class); |
220
|
1 |
|
$this->counterItem($item['id'], $item['user_id'], 1, app()->make(AdditionCount::class)); |
221
|
1 |
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* @param int $itemId |
225
|
|
|
* @param int $userId |
226
|
|
|
* @param int $counterUp |
227
|
|
|
* @param CounterItemContract $typeOperation |
228
|
|
|
* @return bool |
229
|
|
|
*/ |
230
|
4 |
|
private function counterItem(int $itemId, int $userId, int $counterUp, CounterItemContract $typeOperation) : bool |
231
|
|
|
{ |
232
|
4 |
|
$collection = $this->getItems($userId); |
233
|
4 |
|
if ($collection->isEmpty()) { |
234
|
1 |
|
return false; |
235
|
|
|
} |
236
|
3 |
|
$items = fromJson($collection->first()->data, true); |
237
|
|
|
|
238
|
3 |
|
$targetItem = array_filter($items, function ($value) use ($itemId) { |
239
|
3 |
|
return $value['id'] == $itemId; |
240
|
3 |
|
}); |
241
|
|
|
|
242
|
3 |
|
$item = reset($targetItem); |
243
|
|
|
|
244
|
3 |
|
$item['count'] = $typeOperation->execute((int)$item['count'], $counterUp); |
245
|
|
|
|
246
|
3 |
|
if ($item['count'] == 0) { |
247
|
1 |
|
$this->remove(['id' => $itemId, 'user_id' => $userId]); |
248
|
|
|
} else { |
249
|
2 |
|
$this->updateRow((int)$userId, inJson([$item])); |
250
|
|
|
} |
251
|
|
|
|
252
|
3 |
|
return true; |
253
|
|
|
} |
254
|
|
|
/** |
255
|
|
|
* Empty fill row table |
256
|
|
|
* @param int $user |
257
|
|
|
* @param string $values |
258
|
|
|
*/ |
259
|
1 |
|
private function addRow(int $user, string $values) : void |
260
|
|
|
{ |
261
|
1 |
|
$this->manager->table($this->table)->insert([ |
262
|
1 |
|
'user_id' => $user, |
263
|
1 |
|
'data' => $values |
264
|
|
|
]); |
265
|
1 |
|
} |
266
|
|
|
|
267
|
|
|
/** |
268
|
|
|
* Update Row |
269
|
|
|
* @param int $userId |
270
|
|
|
* @param string $values |
271
|
|
|
*/ |
272
|
6 |
|
private function updateRow(int $userId, string $values) : void |
273
|
|
|
{ |
274
|
6 |
|
$this->manager->table($this->table)->where('user_id', $userId)->update([ |
275
|
6 |
|
'data' => $values |
276
|
|
|
]); |
277
|
6 |
|
} |
278
|
|
|
|
279
|
|
|
/** |
280
|
|
|
* Get collection items from database |
281
|
|
|
* @param int $userId |
282
|
|
|
* @return Collection |
283
|
|
|
*/ |
284
|
12 |
|
private function getItems(int $userId) |
285
|
|
|
{ |
286
|
12 |
|
return $this->manager->table($this->table)->where('user_id', $userId)->get(); |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
/** |
290
|
|
|
* @param int $userId |
291
|
|
|
*/ |
292
|
2 |
|
private function deleteRow(int $userId) : void |
293
|
|
|
{ |
294
|
2 |
|
$this->manager->table($this->table)->where('user_id', $userId)->delete(); |
295
|
|
|
} |
296
|
|
|
} |
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.