Completed
Push — master ( 1bb9df...f30c94 )
by Luke
8s
created

LaraCart::increment()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 8
rs 9.4285
cc 1
eloc 5
nc 1
nop 1
1
<?php
2
3
namespace LukePOLO\LaraCart;
4
5
use Illuminate\Contracts\Events\Dispatcher;
6
use Illuminate\Session\SessionManager;
7
use LukePOLO\LaraCart\Contracts\CouponContract;
8
use LukePOLO\LaraCart\Contracts\LaraCartContract;
9
10
/**
11
 * Class LaraCart
12
 *
13
 * @package LukePOLO\LaraCart
14
 */
15
class LaraCart implements LaraCartContract
16
{
17
    const QTY = 'qty';
18
    const HASH = 'generateCartHash';
19
    const PRICE = 'price';
20
    const SERVICE = 'laracart';
21
    const RANHASH = 'generateRandomCartItemHash';
22
23
    protected $events;
24
    protected $session;
25
26
    public $cart;
27
28
    /**
29
     * LaraCart constructor.
30
     *
31
     * @param SessionManager $session
32
     * @param Dispatcher $events
33
     */
34
    public function __construct(SessionManager $session, Dispatcher $events)
35
    {
36
        $this->session = $session;
37
        $this->events = $events;
38
39
        $this->setInstance($this->session->get('laracart.instance', 'default'));
40
    }
41
42
    /**
43
     * Sets and Gets the instance of the cart in the session we should be using
44
     *
45
     * @param string $instance
46
     *
47
     * @return LaraCart
48
     */
49
    public function setInstance($instance = 'default')
50
    {
51
        $this->get($instance);
52
53
        $this->session->set('laracart.instance', $instance);
54
55
        $this->events->fire('laracart.new');
56
57
        return $this;
58
    }
59
60
    /**
61
     * Gets the instance in the session
62
     *
63
     * @param string $instance
64
     *
65
     * @return $this cart instance
66
     */
67
    public function get($instance = 'default')
68
    {
69
        if (empty($this->cart = $this->session->get(config('laracart.cache_prefix', 'laracart') . '.' . $instance))) {
70
            $this->cart = new Cart($instance);
71
        }
72
73
        return $this;
74
    }
75
76
    /**
77
     * Gets an an attribute from the cart
78
     *
79
     * @param $attribute
80
     * @param $defaultValue
81
     *
82
     * @return mixed
83
     */
84
    public function getAttribute($attribute, $defaultValue = null)
85
    {
86
        return array_get($this->cart->attributes, $attribute, $defaultValue);
87
    }
88
89
    /**
90
     * Gets all the carts attributes
91
     *
92
     * @return mixed
93
     */
94
    public function getAttributes()
95
    {
96
        return $this->cart->attributes;
97
    }
98
99
    /**
100
     * Adds an Attribute to the cart
101
     *
102
     * @param $attribute
103
     * @param $value
104
     */
105
    public function setAttribute($attribute, $value)
106
    {
107
        array_set($this->cart->attributes, $attribute, $value);
108
109
        $this->update();
110
    }
111
112
    /**
113
     * Updates cart session
114
     */
115
    public function update()
116
    {
117
        $this->session->set(config('laracart.cache_prefix', 'laracart') . '.' . $this->cart->instance, $this->cart);
118
119
        $this->events->fire('laracart.update', $this->cart);
120
    }
121
122
    /**
123
     * Removes an attribute from the cart
124
     *
125
     * @param $attribute
126
     */
127
    public function removeAttribute($attribute)
128
    {
129
        array_forget($this->cart->attributes, $attribute);
130
131
        $this->update();
132
    }
133
134
    /**
135
     * Creates a CartItem and then adds it to cart
136
     *
137
     * @param string|int $itemID
138
     * @param null $name
139
     * @param int $qty
140
     * @param string $price
141
     * @param array $options
142
     * @param bool|true $taxable
143
     *
144
     * @return CartItem
145
     */
146
    public function addLine($itemID, $name = null, $qty = 1, $price = '0.00', $options = [], $taxable = true)
147
    {
148
        return $this->add($itemID, $name, $qty, $price, $options, $taxable, true);
149
    }
150
151
    /**
152
     * Creates a CartItem and then adds it to cart
153
     *
154
     * @param $itemID
155
     * @param null $name
156
     * @param int $qty
157
     * @param string $price
158
     * @param array $options
159
     * @param bool|false $taxable
160
     * @param bool|false $lineItem
161
     *
162
     * @return CartItem
163
     */
164
    public function add(
165
        $itemID,
166
        $name = null,
167
        $qty = 1,
168
        $price = '0.00',
169
        $options = [],
170
        $taxable = true,
171
        $lineItem = false
172
    ) {
173
        $item = $this->addItem(
174
            new CartItem(
175
                $itemID,
176
                $name,
177
                $qty,
178
                $price,
179
                $options,
180
                $taxable,
181
                $lineItem
182
            )
183
        );
184
185
        return $this->getItem($item->getHash());
186
    }
187
188
    /**
189
     * Adds the cartItem into the cart session
190
     *
191
     * @param CartItem $cartItem
192
     *
193
     * @return CartItem
194
     */
195
    public function addItem(CartItem $cartItem)
196
    {
197
        $itemHash = $cartItem->generateHash();
198
199
        if ($this->getItem($itemHash)) {
200
            $this->getItem($itemHash)->qty += $cartItem->qty;
0 ignored issues
show
Documentation introduced by
The property qty does not exist on object<LukePOLO\LaraCart\CartItem>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
201
        } else {
202
            $this->cart->items[] = $cartItem;
203
        }
204
205
        $this->events->fire('laracart.addItem', $cartItem);
206
207
        $this->update();
208
209
        return $cartItem;
210
    }
211
212
    /**
213
     * Increment the quantity of a cartItem based on the itemHash
214
     *
215
     * @param $itemHash
216
     *
217
     * @return CartItem | null
218
     */
219
    public function increment($itemHash)
220
    {
221
        $item = $this->getItem($itemHash);
222
        $item->qty++;
0 ignored issues
show
Documentation introduced by
The property qty does not exist on object<LukePOLO\LaraCart\CartItem>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
223
        $this->update();
224
225
        return $item;
226
    }
227
228
    /**
229
     * Decrement the quantity of a cartItem based on the itemHash
230
     *
231
     * @param $itemHash
232
     *
233
     * @return CartItem | null
234
     */
235
    public function decrement($itemHash)
236
    {
237
        $item = $this->getItem($itemHash);
238
        if ($item->qty > 1) {
0 ignored issues
show
Documentation introduced by
The property qty does not exist on object<LukePOLO\LaraCart\CartItem>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
239
            $item->qty--;
0 ignored issues
show
Documentation introduced by
The property qty does not exist on object<LukePOLO\LaraCart\CartItem>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
240
            $this->update();
241
242
            return $item;
243
        }
244
        $this->removeItem($itemHash);
245
        $this->update();
246
247
        return null;
248
    }
249
250
    /*
251
     * Find items in the cart matching a data set
252
     *
253
     * @return array
254
     */
255
    public function find($data)
256
    {
257
        $matches = [];
258
259
        foreach ($this->getItems() as $item) {
260
            if ($item->find($data)) {
261
                $matches[] = $item;
262
            }
263
        }
264
265
        return $matches;
266
    }
267
268
    /**
269
     * Finds a cartItem based on the itemHash
270
     *
271
     * @param $itemHash
272
     *
273
     * @return CartItem | null
274
     */
275
    public function getItem($itemHash)
276
    {
277
        return array_get($this->getItems(), $itemHash);
278
    }
279
280
    /**
281
     * Gets all the items within the cart
282
     *
283
     * @return array
284
     */
285
    public function getItems()
286
    {
287
        $items = [];
288
        if (isset($this->cart->items) === true) {
289
            foreach ($this->cart->items as $item) {
290
                $items[$item->getHash()] = $item;
291
            }
292
        }
293
294
        return $items;
295
    }
296
297
    /**
298
     * Updates an items attributes
299
     *
300
     * @param $itemHash
301
     * @param $key
302
     * @param $value
303
     *
304
     * @return CartItem
305
     *
306
     * @throws Exceptions\InvalidPrice
307
     * @throws Exceptions\InvalidQuantity
308
     */
309
    public function updateItem($itemHash, $key, $value)
310
    {
311
        if (empty($item = $this->getItem($itemHash)) === false) {
312
            $item->$key = $value;
313
        }
314
315
        $item->generateHash();
316
317
        return $item;
318
    }
319
320
    /**
321
     * Removes a CartItem based on the itemHash
322
     *
323
     * @param $itemHash
324
     */
325
    public function removeItem($itemHash)
326
    {
327
        foreach ($this->cart->items as $itemKey => $item) {
328
            if ($item->getHash() == $itemHash) {
329
                unset($this->cart->items[$itemKey]);
330
                break;
331
            }
332
        }
333
334
        $this->events->fire('laracart.removeItem', $itemHash);
335
    }
336
337
    /**
338
     * Empties the carts items
339
     */
340
    public function emptyCart()
341
    {
342
        unset($this->cart->items);
343
344
        $this->update();
345
346
        $this->events->fire('laracart.empty', $this->cart->instance);
347
    }
348
349
    /**
350
     * Completely destroys cart and anything associated with it
351
     */
352
    public function destroyCart()
353
    {
354
        $instance = $this->cart->instance;
355
356
        $this->session->forget(config('laracart.cache_prefix', 'laracart') . '.' . $instance);
357
358
        $this->setInstance('default');
359
360
        $this->events->fire('laracart.destroy', $instance);
361
    }
362
363
    /**
364
     * Gets the coupons for the current cart
365
     *
366
     * @return array
367
     */
368
    public function getCoupons()
369
    {
370
        return $this->cart->coupons;
371
    }
372
373
    /**
374
     * Finds a specific coupon in the cart
375
     *
376
     * @param $code
377
     * @return mixed
378
     */
379
    public function findCoupon($code)
380
    {
381
        return array_get($this->cart->coupons, $code);
382
    }
383
384
    /**
385
     * Applies a coupon to the cart
386
     *
387
     * @param CouponContract $coupon
388
     */
389
    public function addCoupon(CouponContract $coupon)
390
    {
391
        if (!$this->cart->multipleCoupons) {
392
            $this->cart->coupons = [];
393
        }
394
395
        $this->cart->coupons[$coupon->code] = $coupon;
0 ignored issues
show
Bug introduced by
Accessing code on the interface LukePOLO\LaraCart\Contracts\CouponContract suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
396
397
        $this->update();
398
    }
399
400
    /**
401
     * Removes a coupon in the cart
402
     *
403
     * @param $code
404
     */
405
    public function removeCoupon($code)
406
    {
407
        foreach ($this->getItems() as $item) {
408
            if (isset($item->code) && $item->code == $code) {
409
                $item->code = null;
410
                $item->discount = null;
411
                $item->couponInfo = [];
412
            }
413
        }
414
415
        array_forget($this->cart->coupons, $code);
416
417
        $this->update();
418
    }
419
420
    /**
421
     * Gets a speific fee from the fees array
422
     *
423
     * @param $name
424
     *
425
     * @return mixed
426
     */
427
    public function getFee($name)
428
    {
429
        return array_get($this->cart->fees, $name, new CartFee(null, false));
430
    }
431
432
    /**
433
     * Allows to charge for additional fees that may or may not be taxable
434
     * ex - service fee , delivery fee, tips
435
     *
436
     * @param $name
437
     * @param $amount
438
     * @param bool|false $taxable
439
     * @param array $options
440
     */
441
    public function addFee($name, $amount, $taxable = false, array $options = [])
442
    {
443
        array_set($this->cart->fees, $name, new CartFee($amount, $taxable, $options));
444
445
        $this->update();
446
    }
447
448
    /**
449
     * Reemoves a fee from the fee array
450
     *
451
     * @param $name
452
     */
453
    public function removeFee($name)
454
    {
455
        array_forget($this->cart->fees, $name);
456
457
        $this->update();
458
    }
459
460
    /**
461
     * Gets the total tax for the cart
462
     *
463
     * @param bool|true $format
464
     *
465
     * @return string
466
     */
467
    public function taxTotal($format = true)
468
    {
469
        $totalTax = 0;
470
        $discounted = 0;
471
        $totalDiscount = $this->totalDiscount(false);
472
473
        if ($this->count() != 0) {
474
            foreach ($this->getItems() as $item) {
475
                if ($discounted >= $totalDiscount) {
476
                    $totalTax += $item->tax();
477
                } else {
478
                    $itemPrice = $item->subTotal(false);
479
480
                    if (($discounted + $itemPrice) > $totalDiscount) {
481
                        $totalTax += $item->tax($totalDiscount - $discounted);
482
                    }
483
484
                    $discounted += $itemPrice;
485
                }
486
            }
487
        }
488
489
        foreach ($this->getFees() as $fee) {
490
            if ($fee->taxable) {
491
                $totalTax += $fee->amount * $fee->tax;
492
            }
493
        }
494
495
        return $this->formatMoney($totalTax, null, null, $format);
496
    }
497
498
    /**
499
     * Gets the total of the cart with or without tax
500
     *
501
     * @param boolean $format
502
     * @param boolean $withDiscount
503
     *
504
     * @return string
505
     */
506
    public function total($format = true, $withDiscount = true, $withTax = true)
507
    {
508
        $total = $this->subTotal(false) + $this->feeTotals(false);
509
510
        if ($withDiscount) {
511
            $total -= $this->totalDiscount(false);
512
        }
513
514
        if ($withTax) {
515
            $total += $this->taxTotal(false);
516
        }
517
518
        return $this->formatMoney($total, null, null, $format);
519
    }
520
521
    /**
522
     * Gets the subtotal of the cart with or without tax
523
     *
524
     * @param boolean $format
525
     * @param boolean $withDiscount
526
     *
527
     * @return string
528
     */
529
    public function subTotal($format = true, $withDiscount = true)
530
    {
531
        $total = 0;
532
533
        if ($this->count() != 0) {
534
            foreach ($this->getItems() as $item) {
535
                $total += $item->subTotal(false, $withDiscount);
536
            }
537
        }
538
539
        return $this->formatMoney($total, null, null, $format);
540
    }
541
542
    /**
543
     * Get the count based on qty, or number of unique items
544
     *
545
     * @param bool $withItemQty
546
     *
547
     * @return int
548
     */
549
    public function count($withItemQty = true)
550
    {
551
        $count = 0;
552
553
        foreach ($this->getItems() as $item) {
554
            if ($withItemQty) {
555
                $count += $item->qty;
556
            } else {
557
                $count++;
558
            }
559
        }
560
561
        return $count;
562
    }
563
564
    /**
565
     *
566
     * Formats the number into a money format based on the locale and international formats
567
     *
568
     * @param $number
569
     * @param $locale
570
     * @param $internationalFormat
571
     * @param $format
572
     *
573
     * @return string
574
     */
575
    public static function formatMoney($number, $locale = null, $internationalFormat = null, $format = true)
576
    {
577
        $number = number_format($number, 2, '.', '');
578
579
        if ($format) {
580
            setlocale(LC_MONETARY, null);
581
            setlocale(LC_MONETARY, empty($locale) ? config('laracart.locale', 'en_US.UTF-8') : $locale);
582
583
            if (empty($internationalFormat) === true) {
584
                $internationalFormat = config('laracart.international_format', false);
585
            }
586
587
            $number = money_format($internationalFormat ? '%i' : '%n', $number);
588
        }
589
590
        return $number;
591
    }
592
593
    /**
594
     * Gets all the fee totals
595
     *
596
     * @param boolean $format
597
     *
598
     * @return string
599
     */
600
    public function feeTotals($format = true, $withTax = false)
601
    {
602
        $feeTotal = 0;
603
604
        foreach ($this->getFees() as $fee) {
605
            $feeTotal += $fee->amount;
606
607
            if ($withTax && $fee->taxable && $fee->tax > 0) {
608
                $feeTotal += $fee->amount * $fee->tax;
609
            }
610
        }
611
612
        return $this->formatMoney($feeTotal, null, null, $format);
613
    }
614
615
    /**
616
     * Gets all the fees on the cart object
617
     *
618
     * @return mixed
619
     */
620
    public function getFees()
621
    {
622
        return $this->cart->fees;
623
    }
624
625
    /**
626
     * Gets the total amount discounted
627
     *
628
     * @param boolean $format
629
     *
630
     * @return string
631
     */
632
    public function totalDiscount($format = true)
633
    {
634
        $total = 0;
635
636
        foreach ($this->cart->coupons as $coupon) {
637
            if ($coupon->appliedToCart) {
638
                $total += $coupon->discount();
639
            }
640
        }
641
642
        return $this->formatMoney($total, null, null, $format);
643
    }
644
}
645