Completed
Branch master (5630d8)
by Michael
02:00
created

Cart::restoreCheckContents()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 3

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 6
ccs 2
cts 2
cp 1
rs 9.4285
cc 3
eloc 3
nc 2
nop 1
crap 3
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 = array();
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 19
    public function __construct($id, Store $store)
37
    {
38 19
        $this->id = $id;
39 19
        $this->store = $store;
40
    }
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 5
    public function add(CartItem $cartItem)
78
    {
79
        $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
        if ($this->has($itemId)) {
84
            $existingItem = $this->find($itemId);
85
            $existingItem->quantity += $cartItem->quantity;
86
        } else {
87 5
            $this->items[] = $cartItem;
88 1
        }
89
    }
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
        foreach ($items as $position => $item) {
101
            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
    public function update($itemId, $key, $value)
119
    {
120
        $item = $this->find($itemId);
121
122
        if (!$item) {
123
            throw new \InvalidArgumentException(sprintf('Item [%s] does not exist in cart.', $itemId));
124
        }
125
126
        $item->$key = $value;
127
128
        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
    public function get($itemId)
139
    {
140
        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
    public function has($itemId)
151
    {
152
        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 3
    public function find($itemId)
163
    {
164
        foreach ($this->items as $item) {
165
            if ($itemId === $item->id) {
166 3
                return $item;
167
            }
168
        }
169
170 2
        return;
171
    }
172
173
    /**
174
     * Get the total number of unique items in the cart.
175
     *
176
     * @return int
177
     */
178
    public function totalUniqueItems()
179
    {
180
        return count($this->items);
181
    }
182
183
    /**
184
     * Get the total number of items in the cart.
185
     *
186
     * @return int
187
     */
188
    public function totalItems()
189
    {
190
        return array_sum(
191
            array_map(function (CartItem $item) {
192
                return $item->quantity;
193
            }, $this->items)
194
        );
195
    }
196
197
    /**
198
     * Get the cart total including tax.
199
     *
200
     * @return float
201
     */
202
    public function total()
203
    {
204
        return (float) array_sum(
205
            array_map(function (CartItem $item) {
206
                return $item->getTotalPrice();
207
            }, $this->items)
208
        );
209
    }
210
211
    /**
212
     * Get the cart total excluding tax.
213
     *
214
     * @return float
215
     */
216
    public function totalExcludingTax()
217
    {
218
        return (float) array_sum(
219
            array_map(function (CartItem $item) {
220
                return $item->getTotalPriceExcludingTax();
221
            }, $this->items)
222
        );
223
    }
224
225
    /**
226
     * Get the cart tax.
227
     *
228
     * @return float
229
     */
230
    public function tax()
231
    {
232
        return (float) array_sum(
233
            array_map(function (CartItem $item) {
234
                return $item->getTotalTax();
235
            }, $this->items)
236
        );
237
    }
238
239
    /**
240
     * Remove all items from the cart.
241
     */
242 1
    public function clear()
243
    {
244 1
        $this->items = array();
245
246
        $this->store->flush($this->id);
247 1
    }
248
249
    /**
250
     * Save the cart state.
251
     */
252 1
    public function save()
253
    {
254
        $data = serialize($this->toArray());
255
256
        $this->store->put($this->id, $data);
257 1
    }
258
259
    /**
260
     * Restore the cart from its saved state.
261
     *
262
     * @throws CartRestoreException
263
     */
264 2
    public function restore()
265
    {
266
        $state = $this->store->get($this->id);
267
268 2
        if ($state == '') {
269 1
            return;
270
        }
271
272
        $data = @unserialize($state); // suppress unserializable error
273
274
        $this->restoreCheckType($data);
275
        $this->restoreCheckContents($data);
276
        $this->restoreCheckContentsType($data);
277
278 1
        $this->id = $data['id'];
279 1
        $this->items = array();
280
281 1
        foreach ($data['items'] as $itemArr) {
282
            $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 1
    private function restoreCheckType($data)
294
    {
295 1
        if ($data === false) {
296
            throw new CartRestoreException('Saved cart state is unserializable.');
297
        }
298
299
        if (!is_array($data)) {
300
            throw new CartRestoreException('Unserialized data is not an array.');
301
        }
302 1
    }
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 1
    private function restoreCheckContents(array $data)
312
    {
313 1
        if (!isset($data['id']) || !isset($data['items'])) {
314
            throw new CartRestoreException('Missing cart ID or cart items.');
315
        }
316
    }
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
    private function restoreCheckContentsType(array $data)
326
    {
327
        if (!is_string($data['id']) || !is_array($data['items'])) {
328
            throw new CartRestoreException('Cart ID not a string or cart items not an array.');
329
        }
330
    }
331
332
    /**
333
     * Export the cart as an array.
334
     *
335
     * @return array
336
     */
337 2
    public function toArray()
338
    {
339
        return array(
340 2
            'id' => $this->id,
341 2
            'items' => array_map(function (CartItem $item) {
342
                return $item->toArray();
343 2
            }, $this->items),
344 2
        );
345
    }
346
}
347