DatabaseDriver   A
last analyzed

Complexity

Total Complexity 29

Size/Duplication

Total Lines 274
Duplicated Lines 7.3 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 20
loc 274
ccs 96
cts 96
cp 1
rs 10
c 0
b 0
f 0
wmc 29

17 Methods

Rating   Name   Duplication   Size   Complexity  
A add() 19 19 4
A __construct() 0 4 1
A counterItem() 0 23 3
A addItem() 0 9 1
A clear() 0 3 1
B discount() 0 23 4
A addRow() 0 5 1
A change() 0 7 2
A remove() 0 21 4
A setTable() 0 3 1
A updateRow() 0 4 1
A existItem() 0 4 1
A deleteRow() 0 3 1
A existUser() 0 3 1
A incrementItem() 0 4 1
A getItems() 0 3 1
A get() 0 4 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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
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...
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);
0 ignored issues
show
Bug Best Practice introduced by
The expression return fromJson($row->toJson(), true) returns the type mixed which includes types incompatible with the type-hinted return array.
Loading history...
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
}