Test Setup Failed
Push — master ( 0810c7...109fad )
by Carlos
40s queued 10s
created

Cart::clean()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
/*
4
 * This file is part of the overtrue/laravel-shopping-cart.
5
 *
6
 * (c) 2016 overtrue <[email protected]>
7
 */
8
9
namespace Overtrue\LaravelShoppingCart;
10
11
use Illuminate\Contracts\Events\Dispatcher;
12
use Illuminate\Session\SessionManager;
13
use Illuminate\Support\Collection;
14
15
/**
16
 * Main class of Overtrue\LaravelShoppingCart package.
17
 */
18
class Cart
19
{
20
    /**
21
     * Session manager.
22
     *
23
     * @var \Illuminate\Session\SessionManager
24
     */
25
    protected $session;
26
27
    /**
28
     * Event dispatcher.
29
     *
30
     * @var \Illuminate\Contracts\Events\Dispatcher
31
     */
32
    protected $event;
33
34
    /**
35
     * Current cart name.
36
     *
37
     * @var string
38
     */
39
    protected $name = 'shopping_cart.default';
40
41
    /**
42
     * Associated model name.
43
     *
44
     * @var string
45
     */
46
    protected $model;
47
48
    /**
49
     * Constructor.
50
     *
51
     * @param \Illuminate\Session\SessionManager      $session Session class name
52
     * @param \Illuminate\Contracts\Events\Dispatcher $event   Event class name
53
     */
54 13
    public function __construct(SessionManager $session, Dispatcher $event)
55
    {
56 13
        $this->session = $session;
57 13
        $this->event   = $event;
58 13
    }
59
60
    public function dispatchEvent($event, $payload = [], $halt = false)
61
    {
62
        if (method_exists($this->event, 'fire')) {
63
            return $this->event->fire($event, $payload, $halt);
0 ignored issues
show
Bug introduced by
The method fire() does not seem to exist on object<Illuminate\Contracts\Events\Dispatcher>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
64
        }
65
66
        return $this->event->dispatch($event, $payload, $halt);
67 1
    }
68
69 1
    /**
70
     * Set the current cart name.
71 1
     *
72
     * @param string $name Cart name name
73
     *
74
     * @return Cart
75
     */
76
    public function name($name)
77
    {
78
        $this->name = 'shopping_cart.' . $name;
79
80
        return $this;
81 2
    }
82
83 2
    /**
84 1
     * Associated model.
85
     *
86 1
     * @param string $model The name of the model
87
     *
88 1
     * @return Cart
89
     */
90
    public function associate($model)
91
    {
92
        if (!class_exists($model)) {
93
            throw new Exception("Invalid model name '$model'.");
94
        }
95
        $this->model = $model;
96 2
97
        return $this;
98 2
    }
99
100
    /**
101
     * Get all items.
102
     *
103
     * @return \Illuminate\Support\Collection
104
     */
105
    public function all()
106
    {
107
        return $this->getCart();
108
    }
109
110
    /**
111
     * Add a row to the cart.
112 10
     *
113
     * @param int|string $id         Unique ID of the item
114 10
     * @param string     $name       Name of the item
115
     * @param int        $qty        Item qty to add to the cart
116 10
     * @param float      $price      Price of one item
117
     * @param array      $attributes Array of additional attributes, such as 'size' or 'color'...
118 10
     *
119
     * @return string
120 8
     */
121
    public function add($id, $name = null, $qty = null, $price = null, array $attributes = [])
122 8
    {
123
        $cart = $this->getCart();
124 8
125
        $this->dispatchEvent('shopping_cart.adding', [$attributes, $cart]);
126
127
        $row = $this->addRow($id, $name, $qty, $price, $attributes);
128
129
        $cart = $this->getCart();
130
131
        $this->dispatchEvent('shopping_cart.added', [$attributes, $cart]);
132
133
        return $row;
134
    }
135 3
136
    /**
137 3
     * Update the quantity of one row of the cart.
138 1
     *
139
     * @param string    $rawId     The __raw_id of the item you want to update
140
     * @param int|array $attribute New quantity of the item|Array of attributes to update
141 2
     *
142
     * @return Item|bool
143 2
     */
144
    public function update($rawId, $attribute)
145 2
    {
146 1
        if (!$row = $this->get($rawId)) {
147
            throw new Exception('Item not found.');
148 2
        }
149
150
        $cart = $this->getCart();
151 2
152
        $this->dispatchEvent('shopping_cart.updating', [$row, $cart]);
153 2
154
        if (is_array($attribute)) {
155
            $raw = $this->updateAttribute($rawId, $attribute);
156
        } else {
157
            $raw = $this->updateQty($rawId, $attribute);
158
        }
159
160
        $this->dispatchEvent('shopping_cart.updated', [$row, $cart]);
161
162
        return $raw;
163 3
    }
164
165 3
    /**
166 1
     * Remove a row from the cart.
167
     *
168
     * @param string $rawId The __raw_id of the item
169 3
     *
170
     * @return bool
171 3
     */
172
    public function remove($rawId)
173 3
    {
174
        if (!$row = $this->get($rawId)) {
175 3
            return true;
176
        }
177 3
178
        $cart = $this->getCart();
179 3
180
        $this->dispatchEvent('shopping_cart.removing', [$row, $cart]);
181
182
        $cart->forget($rawId);
183
184
        $this->dispatchEvent('shopping_cart.removed', [$row, $cart]);
185
186
        $this->save($cart);
187
188
        return true;
189 5
    }
190
191 5
    /**
192
     * Get a row of the cart by its ID.
193 5
     *
194
     * @param string $rawId The ID of the row to fetch
195
     *
196
     * @return Item
197
     */
198
    public function get($rawId)
199
    {
200
        $row = $this->getCart()->get($rawId);
201 5
202
        return $row === null ? null : new Item($row);
203 5
    }
204
205 5
    /**
206
     * Clean the cart.
207 5
     *
208
     * @return bool
209 5
     */
210
    public function destroy()
211 5
    {
212
        $cart = $this->getCart();
213
214
        $this->dispatchEvent('shopping_cart.destroying', $cart);
0 ignored issues
show
Documentation introduced by
$cart is of type object<Illuminate\Support\Collection>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
215
216
        $this->save(null);
217
218
        $this->dispatchEvent('shopping_cart.destroyed', $cart);
0 ignored issues
show
Documentation introduced by
$cart is of type object<Illuminate\Support\Collection>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
219 1
220
        return true;
221 1
    }
222 1
223
    /**
224
     * Alias of destory().
225
     *
226
     * @return bool
227
     */
228
    public function clean()
229 2
    {
230
        $this->destroy();
231 2
    }
232
233
    /**
234
     * Get the price total.
235
     *
236
     * @return float
237
     */
238
    public function total()
239 2
    {
240
        return $this->totalPrice();
241 2
    }
242
243 2
    /**
244
     * Return total price of cart.
245 2
     *
246 1
     * @return
247
     */
248
    public function totalPrice()
249 2
    {
250 2
        $total = 0;
251
252
        $cart = $this->getCart();
253 2
254
        if ($cart->isEmpty()) {
255
            return $total;
256
        }
257
258
        foreach ($cart as $row) {
259
            $total += $row->qty * $row->price;
260
        }
261
262
        return $total;
263 2
    }
264
265 2
    /**
266
     * Get the number of items in the cart.
267 2
     *
268 2
     * @param bool $totalItems Get all the items (when false, will return the number of rows)
269
     *
270
     * @return int
271 2
     */
272
    public function count($totalItems = true)
273 2
    {
274 2
        $items = $this->getCart();
275
276
        if (!$totalItems) {
277 2
            return $items->count();
278
        }
279
280
        $count = 0;
281
282
        foreach ($items as $row) {
283
            $count += $row->qty;
284
        }
285 2
286
        return $count;
287 2
    }
288
289
    /**
290
     * Get rows count.
291
     *
292
     * @return int
293
     */
294
    public function countRows()
295
    {
296
        return $this->count(false);
297 1
    }
298
299 1
    /**
300
     * Search if the cart has a item.
301 1
     *
302 1
     * @param array $search An array with the item ID and optional options
303
     *
304
     * @return array|Collection
305 1
     */
306 1
    public function search(array $search)
307 1
    {
308
        $rows = new Collection();
309
310
        if (empty($search)) {
311 1
            return $rows;
312
        }
313
314
        foreach ($this->getCart() as $item) {
315
            if (array_intersect_assoc($item->intersect($search)->toArray(), $search)) {
316
                $rows->put($item->__raw_id, $item);
317
            }
318
        }
319 1
320
        return $rows;
321 1
    }
322
323
    /**
324
     * Get current cart name.
325
     *
326
     * @return string
327
     */
328
    public function getName()
329 1
    {
330
        return $this->name;
331 1
    }
332
333
    /**
334
     * Get current associated model.
335
     *
336
     * @return string
337
     */
338
    public function getModel()
339 1
    {
340
        return $this->model;
341 1
    }
342
343
    /**
344
     * Return whether the shopping cart is empty.
345
     *
346
     * @return bool
347
     */
348
    public function isEmpty()
349
    {
350
        return $this->count() <= 0;
351
    }
352
353
    /**
354
     * Add row to the cart.
355 10
     *
356
     * @param string $id         Unique ID of the item
357 10
     * @param string $name       Name of the item
358 1
     * @param int    $qty        Item qty to add to the cart
359
     * @param float  $price      Price of one item
360
     * @param array  $attributes Array of additional options, such as 'size' or 'color'
361 9
     *
362 1
     * @return string
363
     */
364
    protected function addRow($id, $name, $qty, $price, array $attributes = [])
365 8
    {
366
        if (!is_numeric($qty) || $qty < 1) {
367 8
            throw new Exception('Invalid quantity.');
368
        }
369 8
370 1
        if (!is_numeric($price) || $price < 0) {
371
            throw new Exception('Invalid price.');
372 8
        }
373
374
        $cart = $this->getCart();
375 8
376
        $rawId = $this->generateRawId($id, $attributes);
377
378
        if ($row = $cart->get($rawId)) {
379
            $row = $this->updateQty($rawId, $row->qty + $qty);
380
        } else {
381
            $row = $this->insertRow($rawId, $id, $name, $qty, $price, $attributes);
382
        }
383
384
        return $row;
385
    }
386 8
387
    /**
388 8
     * Generate a unique id for the new row.
389
     *
390 8
     * @param string $id         Unique ID of the item
391
     * @param array  $attributes Array of additional options, such as 'size' or 'color'
392
     *
393
     * @return string
394
     */
395
    protected function generateRawId($id, $attributes)
396
    {
397
        ksort($attributes);
398
399
        return md5($id . serialize($attributes));
400 8
    }
401
402 8
    /**
403
     * Sync the cart to session.
404 8
     *
405
     * @param \Illuminate\Support\Collection|null $cart The new cart content
406
     *
407
     * @return \Illuminate\Support\Collection
408
     */
409
    protected function save($cart)
410
    {
411
        $this->session->put($this->name, $cart);
412 11
413
        return $cart;
414 11
    }
415
416 11
    /**
417
     * Get the carts content.
418
     *
419
     * @return \Illuminate\Support\Collection
420
     */
421
    protected function getCart()
422
    {
423
        $cart = $this->session->get($this->name);
424
425
        return $cart instanceof Collection ? $cart : new Collection();
426
    }
427 3
428
    /**
429 3
     * Update a row if the rawId already exists.
430
     *
431 3
     * @param string $rawId      The ID of the row to update
432
     * @param array  $attributes The quantity to add to the row
433 3
     *
434 3
     * @return Item
435
     */
436
    protected function updateRow($rawId, array $attributes)
437 3
    {
438 3
        $cart = $this->getCart();
439
440
        $row = $cart->get($rawId);
441 3
442
        foreach ($attributes as $key => $value) {
443 3
            $row->put($key, $value);
444
        }
445
446
        if (count(array_intersect(array_keys($attributes), ['qty', 'price']))) {
447
            $row->put('total', $row->qty * $row->price);
448
        }
449
450
        $cart->put($rawId, $row);
451
452
        return $row;
453
    }
454
455
    /**
456
     * Create a new row Object.
457
     *
458 8
     * @param string $rawId      The ID of the new row
459
     * @param string $id         Unique ID of the item
460 8
     * @param string $name       Name of the item
461
     * @param int    $qty        Item qty to add to the cart
462 8
     * @param float  $price      Price of one item
463
     * @param array  $attributes Array of additional options, such as 'size' or 'color'
464 8
     *
465
     * @return Item
466 8
     */
467
    protected function insertRow($rawId, $id, $name, $qty, $price, $attributes = [])
468 8
    {
469
        $newRow = $this->makeRow($rawId, $id, $name, $qty, $price, $attributes);
470
471
        $cart = $this->getCart();
472
473
        $cart->put($rawId, $newRow);
474
475
        $this->save($cart);
476
477
        return $newRow;
478
    }
479
480
    /**
481
     * Make a row item.
482
     *
483 8
     * @param string $rawId      raw id
484
     * @param mixed  $id         item id
485 8
     * @param string $name       item name
486 8
     * @param int    $qty        quantity
487 8
     * @param float  $price      price
488 8
     * @param array  $attributes other attributes
489 8
     *
490 8
     * @return Item
491 8
     */
492 8
    protected function makeRow($rawId, $id, $name, $qty, $price, array $attributes = [])
493 8
    {
494
        return new Item(array_merge([
495
            '__raw_id' => $rawId,
496
            'id'       => $id,
497
            'name'     => $name,
498
            'qty'      => $qty,
499
            'price'    => $price,
500
            'total'    => $qty * $price,
501
            '__model'  => $this->model,
502
        ], $attributes));
503
    }
504 3
505
    /**
506 3
     * Update the quantity of a row.
507 1
     *
508
     * @param string $rawId The ID of the row
509
     * @param int    $qty   The qty to add
510 3
     *
511
     * @return Item|bool
512
     */
513
    protected function updateQty($rawId, $qty)
514
    {
515
        if ($qty <= 0) {
516
            return $this->remove($rawId);
517
        }
518
519
        return $this->updateRow($rawId, ['qty' => $qty]);
520
    }
521 1
522
    /**
523 1
     * Update an attribute of the row.
524
     *
525
     * @param string $rawId      The ID of the row
526
     * @param array  $attributes An array of attributes to update
527
     *
528
     * @return Item
529
     */
530
    protected function updateAttribute($rawId, $attributes)
531
    {
532
        return $this->updateRow($rawId, $attributes);
533
    }
534
}
535