Cart   B
last analyzed

Complexity

Total Complexity 36

Size/Duplication

Total Lines 340
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 94%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 36
c 2
b 0
f 0
lcom 1
cbo 3
dl 0
loc 340
ccs 94
cts 100
cp 0.94
rs 8.8

22 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A getStore() 0 4 1
A getId() 0 4 1
A all() 0 4 1
A update() 0 12 2
A totalItems() 0 8 1
A total() 0 8 1
A totalExcludingTax() 0 8 1
A tax() 0 8 1
A clear() 0 6 1
A restoreCheckType() 0 10 3
A restoreCheckContents() 0 6 3
A restoreCheckContentsType() 0 6 3
A add() 0 13 2
A remove() 0 10 3
A get() 0 4 1
A has() 0 4 1
A find() 0 10 3
A totalUniqueItems() 0 4 1
A save() 0 6 1
A restore() 0 21 3
A toArray() 0 9 1
1
<?php
2
3
namespace Cart;
4
5
use Cart\Storage\Store;
6
7
class Cart implements Arrayable
8
{
9
    /**
10
     * The cart id.
11
     *
12
     * @var string
13
     */
14
    private $id;
15
16
    /**
17
     * Items in the cart.
18
     *
19
     * @var CartItem[]
20
     */
21
    private $items = [];
22
23
    /**
24
     * Cart storage implementation.
25
     *
26
     * @var Store
27
     */
28
    private $store;
29
30
    /**
31
     * Create a new cart instance.
32
     *
33
     * @param string $id
34
     * @param Store  $store
35
     */
36 17
    public function __construct($id, Store $store)
37
    {
38 17
        $this->id = $id;
39 17
        $this->store = $store;
40 17
    }
41
42
    /**
43
     * Retrieve the cart storage implementation.
44
     *
45
     * @return Store
46
     */
47 1
    public function getStore()
48
    {
49 1
        return $this->store;
50
    }
51
52
    /**
53
     * Retrieve the cart id.
54
     *
55
     * @return string
56
     */
57 2
    public function getId()
58
    {
59 2
        return $this->id;
60
    }
61
62
    /**
63
     * Retrieve all of the items in the cart.
64
     *
65
     * @return CartItem[]
66
     */
67 2
    public function all()
68
    {
69 2
        return $this->items;
70
    }
71
72
    /**
73
     * Add an item to the cart.
74
     *
75
     * @param CartItem $cartItem
76
     */
77 12
    public function add(CartItem $cartItem)
78
    {
79 12
        $itemId = $cartItem->getId();
80
81
        // if item already exists in the cart, just update the quantity,
82
        // otherwise add it as a new item
83 12
        if ($this->has($itemId)) {
84 1
            $existingItem = $this->find($itemId);
85 1
            $existingItem->quantity += $cartItem->quantity;
86
        } else {
87 12
            $this->items[] = $cartItem;
88
        }
89 12
    }
90
91
    /**
92
     * Remove an item from the cart.
93
     *
94
     * @param string $itemId
95
     */
96 1
    public function remove($itemId)
97
    {
98 1
        $items = &$this->items;
99
100 1
        foreach ($items as $position => $item) {
101 1
            if ($itemId === $item->id) {
102 1
                unset($items[$position]);
103
            }
104
        }
105 1
    }
106
107
    /**
108
     * Update an item in the cart.
109
     *
110
     * @param string $itemId
111
     * @param string $key
112
     * @param mixed  $value
113
     *
114
     * @return string
115
     *
116
     * @throws \InvalidArgumentException
117
     */
118 1
    public function update($itemId, $key, $value)
119
    {
120 1
        $item = $this->find($itemId);
121
122 1
        if (!$item) {
123 1
            throw new \InvalidArgumentException(sprintf('Item [%s] does not exist in cart.', $itemId));
124
        }
125
126 1
        $item->$key = $value;
127
128 1
        return $item->id;
129
    }
130
131
    /**
132
     * Retrieve an item from the cart by its id.
133
     *
134
     * @param string $itemId
135
     *
136
     * @return CartItem|null
137
     */
138 2
    public function get($itemId)
139
    {
140 2
        return $this->find($itemId);
141
    }
142
143
    /**
144
     * Determine if an item exists in the cart.
145
     *
146
     * @param string $itemId
147
     *
148
     * @return bool
149
     */
150 13
    public function has($itemId)
151
    {
152 13
        return !is_null($this->find($itemId));
153
    }
154
155
    /**
156
     * Find an item in the cart.
157
     *
158
     * @param string $itemId
159
     *
160
     * @return CartItem|null
161
     */
162 13
    public function find($itemId)
163
    {
164 13
        foreach ($this->items as $item) {
165 13
            if ($itemId === $item->id) {
166 13
                return $item;
167
            }
168
        }
169
170 12
        return;
171
    }
172
173
    /**
174
     * Get the total number of unique items in the cart.
175
     *
176
     * @return int
177
     */
178 2
    public function totalUniqueItems()
179
    {
180 2
        return count($this->items);
181
    }
182
183
    /**
184
     * Get the total number of items in the cart.
185
     *
186
     * @return int
187
     */
188 1
    public function totalItems()
189
    {
190 1
        return array_sum(
191 1
            array_map(function (CartItem $item) {
192 1
                return $item->quantity;
193 1
            }, $this->items)
194
        );
195
    }
196
197
    /**
198
     * Get the cart total including tax.
199
     *
200
     * @return float
201
     */
202 1
    public function total()
203
    {
204 1
        return (float) array_sum(
205 1
            array_map(function (CartItem $item) {
206 1
                return $item->getTotalPrice();
207 1
            }, $this->items)
208
        );
209
    }
210
211
    /**
212
     * Get the cart total excluding tax.
213
     *
214
     * @return float
215
     */
216 1
    public function totalExcludingTax()
217
    {
218 1
        return (float) array_sum(
219 1
            array_map(function (CartItem $item) {
220 1
                return $item->getTotalPriceExcludingTax();
221 1
            }, $this->items)
222
        );
223
    }
224
225
    /**
226
     * Get the cart tax.
227
     *
228
     * @return float
229
     */
230 1
    public function tax()
231
    {
232 1
        return (float) array_sum(
233 1
            array_map(function (CartItem $item) {
234 1
                return $item->getTotalTax();
235 1
            }, $this->items)
236
        );
237
    }
238
239
    /**
240
     * Remove all items from the cart.
241
     */
242 1
    public function clear()
243
    {
244 1
        $this->items = [];
245
246 1
        $this->store->flush($this->id);
247 1
    }
248
249
    /**
250
     * Save the cart state.
251
     */
252
    public function save()
253
    {
254
        $data = serialize($this->toArray());
255
256
        $this->store->put($this->id, $data);
257
    }
258
259
    /**
260
     * Restore the cart from its saved state.
261
     *
262
     * @throws CartRestoreException
263
     */
264 2
    public function restore()
265
    {
266 2
        $state = $this->store->get($this->id);
267
268 2
        if ($state == '') {
269
            return;
270
        }
271
272 2
        $data = @unserialize($state); // suppress unserializable error
273
274 2
        $this->restoreCheckType($data);
275 2
        $this->restoreCheckContents($data);
276 2
        $this->restoreCheckContentsType($data);
277
278 1
        $this->id = $data['id'];
279 1
        $this->items = [];
280
281 1
        foreach ($data['items'] as $itemArr) {
282 1
            $this->items[] = new CartItem($itemArr);
283
        }
284 1
    }
285
286
    /**
287
     * Check the data to be restored is of the correct type.
288
     *
289
     * @param mixed $data
290
     *
291
     * @throws CartRestoreException
292
     */
293 2
    private function restoreCheckType($data)
294
    {
295 2
        if ($data === false) {
296 1
            throw new CartRestoreException('Saved cart state is unserializable.');
297
        }
298
299 2
        if (!is_array($data)) {
300 1
            throw new CartRestoreException('Unserialized data is not an array.');
301
        }
302 2
    }
303
304
    /**
305
     * Check the contents of the data to be restored contains the correct data.
306
     *
307
     * @param array $data
308
     *
309
     * @throws CartRestoreException
310
     */
311 2
    private function restoreCheckContents(array $data)
312
    {
313 2
        if (!isset($data['id']) || !isset($data['items'])) {
314 1
            throw new CartRestoreException('Missing cart ID or cart items.');
315
        }
316 2
    }
317
318
    /**
319
     * Check the contents of the data to be restored is of the correct type.
320
     *
321
     * @param array $data
322
     *
323
     * @throws CartRestoreException
324
     */
325 2
    private function restoreCheckContentsType(array $data)
326
    {
327 2
        if (!is_string($data['id']) || !is_array($data['items'])) {
328 1
            throw new CartRestoreException('Cart ID not a string or cart items not an array.');
329
        }
330 1
    }
331
332
    /**
333
     * Export the cart as an array.
334
     *
335
     * @return array
336
     */
337 1
    public function toArray()
338
    {
339
        return [
340 1
            'id' => $this->id,
341 1
            'items' => array_map(function (CartItem $item) {
342
                return $item->toArray();
343 1
            }, $this->items),
344
        ];
345
    }
346
}
347