Completed
Pull Request — master (#87)
by Luke
04:23 queued 01:53
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\Auth\AuthManager;
6
use Illuminate\Contracts\Events\Dispatcher;
7
use Illuminate\Session\SessionManager;
8
use LukePOLO\LaraCart\Contracts\CouponContract;
9
use LukePOLO\LaraCart\Contracts\LaraCartContract;
10
11
/**
12
 * Class LaraCart
13
 *
14
 * @package LukePOLO\LaraCart
15
 */
16
class LaraCart implements LaraCartContract
17
{
18
    const QTY = 'qty';
19
    const HASH = 'generateCartHash';
20
    const PRICE = 'price';
21
    const SERVICE = 'laracart';
22
    const RANHASH = 'generateRandomCartItemHash';
23
24
    protected $events;
25
    protected $session;
26
    protected $authManager;
27
    protected $prefix;
28
29
    public $cart;
30
31
    /**
32
     * LaraCart constructor.
33
     *
34
     * @param SessionManager $session
35
     * @param Dispatcher $events
36
     * @param AuthManager $authManager
37
     */
38
    public function __construct(SessionManager $session, Dispatcher $events, AuthManager $authManager)
39
    {
40
        $this->session = $session;
41
        $this->events = $events;
42
        $this->authManager = $authManager;
43
        $this->prefix = config('laracart.cache_prefix', 'laracart');
44
45
        $this->setInstance($this->session->get($this->prefix . '.instance', 'default'));
46
    }
47
48
    /**
49
     * Gets all current instances inside the session
50
     *
51
     * @return mixed
52
     */
53
    public function getInstances()
54
    {
55
        return $this->session->get($this->prefix . '.instances', [
56
            'default'
57
        ]);
58
    }
59
60
    /**
61
     * Sets and Gets the instance of the cart in the session we should be using
62
     *
63
     * @param string $instance
64
     *
65
     * @return LaraCart
66
     */
67
    public function setInstance($instance = 'default')
68
    {
69
        $this->get($instance);
70
71
        $this->session->set($this->prefix . '.instance', $instance);
72
73
        $this->events->fire('laracart.new');
74
75
        return $this;
76
    }
77
78
    /**
79
     * Gets the instance in the session
80
     *
81
     * @param string $instance
82
     *
83
     * @return $this cart instance
84
     */
85
    public function get($instance = 'default')
86
    {
87
        if (config('laracart.cross_devices', false)) {
88
            if (!empty($cartSessionID = $this->authManager->user()->cart_session_id)) {
89
                $this->session->setId($cartSessionID);
90
                $this->session->start();
91
            }
92
        }
93
94
        if (empty($this->cart = $this->session->get($this->prefix . '.' . $instance))) {
95
            $this->cart = new Cart($instance);
96
            $this->session->push($this->prefix . '.instances', $instance);
97
        }
98
99
        return $this;
100
    }
101
102
    /**
103
     * Gets an an attribute from the cart
104
     *
105
     * @param $attribute
106
     * @param $defaultValue
107
     *
108
     * @return mixed
109
     */
110
    public function getAttribute($attribute, $defaultValue = null)
111
    {
112
        return array_get($this->cart->attributes, $attribute, $defaultValue);
113
    }
114
115
    /**
116
     * Gets all the carts attributes
117
     *
118
     * @return mixed
119
     */
120
    public function getAttributes()
121
    {
122
        return $this->cart->attributes;
123
    }
124
125
    /**
126
     * Adds an Attribute to the cart
127
     *
128
     * @param $attribute
129
     * @param $value
130
     */
131
    public function setAttribute($attribute, $value)
132
    {
133
        array_set($this->cart->attributes, $attribute, $value);
134
135
        $this->update();
136
    }
137
138
    /**
139
     * Updates cart session
140
     */
141
    public function update()
142
    {
143
        $this->session->set($this->prefix . '.' . $this->cart->instance, $this->cart);
144
145
        if (config('laracart.cross_devices', false)) {
146
            $this->authManager->user()->cart_session_id = $this->session->getId();
147
            $this->authManager->user()->save();
148
        }
149
150
        $this->events->fire('laracart.update', $this->cart);
151
    }
152
153
    /**
154
     * Removes an attribute from the cart
155
     *
156
     * @param $attribute
157
     */
158
    public function removeAttribute($attribute)
159
    {
160
        array_forget($this->cart->attributes, $attribute);
161
162
        $this->update();
163
    }
164
165
    /**
166
     * Creates a CartItem and then adds it to cart
167
     *
168
     * @param string|int $itemID
169
     * @param null $name
170
     * @param int $qty
171
     * @param string $price
172
     * @param array $options
173
     * @param bool|true $taxable
174
     *
175
     * @return CartItem
176
     */
177
    public function addLine($itemID, $name = null, $qty = 1, $price = '0.00', $options = [], $taxable = true)
178
    {
179
        return $this->add($itemID, $name, $qty, $price, $options, $taxable, true);
180
    }
181
182
    /**
183
     * Creates a CartItem and then adds it to cart
184
     *
185
     * @param $itemID
186
     * @param null $name
187
     * @param int $qty
188
     * @param string $price
189
     * @param array $options
190
     * @param bool|false $taxable
191
     * @param bool|false $lineItem
192
     *
193
     * @return CartItem
194
     */
195
    public function add(
196
        $itemID,
197
        $name = null,
198
        $qty = 1,
199
        $price = '0.00',
200
        $options = [],
201
        $taxable = true,
202
        $lineItem = false
203
    ) {
204
        $item = $this->addItem(
205
            new CartItem(
206
                $itemID,
207
                $name,
208
                $qty,
209
                $price,
210
                $options,
211
                $taxable,
212
                $lineItem
213
            )
214
        );
215
216
        $this->update();
217
218
        return $this->getItem($item->getHash());
219
    }
220
221
    /**
222
     * Adds the cartItem into the cart session
223
     *
224
     * @param CartItem $cartItem
225
     *
226
     * @return CartItem
227
     */
228
    public function addItem(CartItem $cartItem)
229
    {
230
        $itemHash = $cartItem->generateHash();
231
232
        if ($this->getItem($itemHash)) {
233
            $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...
234
        } else {
235
            $this->cart->items[] = $cartItem;
236
        }
237
238
        $this->events->fire('laracart.addItem', $cartItem);
239
240
        return $cartItem;
241
    }
242
243
    /**
244
     * Increment the quantity of a cartItem based on the itemHash
245
     *
246
     * @param $itemHash
247
     *
248
     * @return CartItem | null
249
     */
250
    public function increment($itemHash)
251
    {
252
        $item = $this->getItem($itemHash);
253
        $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...
254
        $this->update();
255
256
        return $item;
257
    }
258
259
    /**
260
     * Decrement the quantity of a cartItem based on the itemHash
261
     *
262
     * @param $itemHash
263
     *
264
     * @return CartItem | null
265
     */
266
    public function decrement($itemHash)
267
    {
268
        $item = $this->getItem($itemHash);
269
        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...
270
            $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...
271
            $this->update();
272
273
            return $item;
274
        }
275
        $this->removeItem($itemHash);
276
        $this->update();
277
278
        return null;
279
    }
280
281
    /**
282
     * Find items in the cart matching a data set
283
     *
284
     *
285
     * param $data
286
     * @return array
287
     */
288
    public function find($data)
289
    {
290
        $matches = [];
291
292
        foreach ($this->getItems() as $item) {
293
            if ($item->find($data)) {
294
                $matches[] = $item;
295
            }
296
        }
297
298
        return $matches;
299
    }
300
301
    /**
302
     * Finds a cartItem based on the itemHash
303
     *
304
     * @param $itemHash
305
     *
306
     * @return CartItem | null
307
     */
308
    public function getItem($itemHash)
309
    {
310
        return array_get($this->getItems(), $itemHash);
311
    }
312
313
    /**
314
     * Gets all the items within the cart
315
     *
316
     * @return array
317
     */
318
    public function getItems()
319
    {
320
        $items = [];
321
        if (isset($this->cart->items) === true) {
322
            foreach ($this->cart->items as $item) {
323
                $items[$item->getHash()] = $item;
324
            }
325
        }
326
327
        return $items;
328
    }
329
330
    /**
331
     * Updates an items attributes
332
     *
333
     * @param $itemHash
334
     * @param $key
335
     * @param $value
336
     *
337
     * @return CartItem
338
     *
339
     * @throws Exceptions\InvalidPrice
340
     * @throws Exceptions\InvalidQuantity
341
     */
342
    public function updateItem($itemHash, $key, $value)
343
    {
344
        if (empty($item = $this->getItem($itemHash)) === false) {
345
            $item->$key = $value;
346
        }
347
348
        $item->generateHash();
349
350
        $this->update();
351
352
        return $item;
353
    }
354
355
    /**
356
     * Removes a CartItem based on the itemHash
357
     *
358
     * @param $itemHash
359
     */
360
    public function removeItem($itemHash)
361
    {
362
        foreach ($this->cart->items as $itemKey => $item) {
363
            if ($item->getHash() == $itemHash) {
364
                unset($this->cart->items[$itemKey]);
365
                break;
366
            }
367
        }
368
369
        $this->events->fire('laracart.removeItem', $itemHash);
370
371
        $this->update();
372
    }
373
374
    /**
375
     * Empties the carts items
376
     */
377
    public function emptyCart()
378
    {
379
        unset($this->cart->items);
380
381
        $this->update();
382
383
        $this->events->fire('laracart.empty', $this->cart->instance);
384
    }
385
386
    /**
387
     * Completely destroys cart and anything associated with it
388
     */
389
    public function destroyCart()
390
    {
391
        $instance = $this->cart->instance;
392
393
        $this->session->forget($this->prefix . '.' . $instance);
394
395
        $this->setInstance('default');
396
397
        $this->events->fire('laracart.destroy', $instance);
398
399
        $this->update();
400
    }
401
402
    /**
403
     * Gets the coupons for the current cart
404
     *
405
     * @return array
406
     */
407
    public function getCoupons()
408
    {
409
        return $this->cart->coupons;
410
    }
411
412
    /**
413
     * Finds a specific coupon in the cart
414
     *
415
     * @param $code
416
     * @return mixed
417
     */
418
    public function findCoupon($code)
419
    {
420
        return array_get($this->cart->coupons, $code);
421
    }
422
423
    /**
424
     * Applies a coupon to the cart
425
     *
426
     * @param CouponContract $coupon
427
     */
428
    public function addCoupon(CouponContract $coupon)
429
    {
430
        if (!$this->cart->multipleCoupons) {
431
            $this->cart->coupons = [];
432
        }
433
434
        $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...
435
436
        $this->update();
437
    }
438
439
    /**
440
     * Removes a coupon in the cart
441
     *
442
     * @param $code
443
     */
444
    public function removeCoupon($code)
445
    {
446
        foreach ($this->getItems() as $item) {
447
            if (isset($item->code) && $item->code == $code) {
448
                $item->code = null;
449
                $item->discount = null;
450
                $item->couponInfo = [];
451
            }
452
        }
453
454
        array_forget($this->cart->coupons, $code);
455
456
        $this->update();
457
    }
458
459
    /**
460
     * Gets a speific fee from the fees array
461
     *
462
     * @param $name
463
     *
464
     * @return mixed
465
     */
466
    public function getFee($name)
467
    {
468
        return array_get($this->cart->fees, $name, new CartFee(null, false));
469
    }
470
471
    /**
472
     * Allows to charge for additional fees that may or may not be taxable
473
     * ex - service fee , delivery fee, tips
474
     *
475
     * @param $name
476
     * @param $amount
477
     * @param bool|false $taxable
478
     * @param array $options
479
     */
480
    public function addFee($name, $amount, $taxable = false, array $options = [])
481
    {
482
        array_set($this->cart->fees, $name, new CartFee($amount, $taxable, $options));
483
484
        $this->update();
485
    }
486
487
    /**
488
     * Reemoves a fee from the fee array
489
     *
490
     * @param $name
491
     */
492
    public function removeFee($name)
493
    {
494
        array_forget($this->cart->fees, $name);
495
496
        $this->update();
497
    }
498
499
    /**
500
     * Gets the total tax for the cart
501
     *
502
     * @param bool|true $format
503
     *
504
     * @return string
505
     */
506
    public function taxTotal($format = true)
507
    {
508
        $totalTax = 0;
509
        $discounted = 0;
510
        $totalDiscount = $this->totalDiscount(false);
511
512
        if ($this->count() != 0) {
513
            foreach ($this->getItems() as $item) {
514
                if ($discounted >= $totalDiscount) {
515
                    $totalTax += $item->tax();
516
                } else {
517
                    $itemPrice = $item->subTotal(false);
518
519
                    if (($discounted + $itemPrice) > $totalDiscount) {
520
                        $totalTax += $item->tax($totalDiscount - $discounted);
521
                    }
522
523
                    $discounted += $itemPrice;
524
                }
525
            }
526
        }
527
528
        foreach ($this->getFees() as $fee) {
529
            if ($fee->taxable) {
530
                $totalTax += $fee->amount * $fee->tax;
531
            }
532
        }
533
534
        return $this->formatMoney($totalTax, null, null, $format);
535
    }
536
537
    /**
538
     * Gets the total of the cart with or without tax
539
     *
540
     * @param boolean $format
541
     * @param boolean $withDiscount
542
     *
543
     * @return string
544
     */
545
    public function total($format = true, $withDiscount = true, $withTax = true)
546
    {
547
        $total = $this->subTotal(false) + $this->feeTotals(false);
548
549
        if ($withDiscount) {
550
            $total -= $this->totalDiscount(false);
551
        }
552
553
        if ($withTax) {
554
            $total += $this->taxTotal(false);
555
        }
556
557
        return $this->formatMoney($total, null, null, $format);
558
    }
559
560
    /**
561
     * Gets the subtotal of the cart with or without tax
562
     *
563
     * @param boolean $format
564
     * @param boolean $withDiscount
565
     *
566
     * @return string
567
     */
568
    public function subTotal($format = true, $withDiscount = true)
569
    {
570
        $total = 0;
571
572
        if ($this->count() != 0) {
573
            foreach ($this->getItems() as $item) {
574
                $total += $item->subTotal(false, $withDiscount);
575
            }
576
        }
577
578
        return $this->formatMoney($total, null, null, $format);
579
    }
580
581
    /**
582
     * Get the count based on qty, or number of unique items
583
     *
584
     * @param bool $withItemQty
585
     *
586
     * @return int
587
     */
588
    public function count($withItemQty = true)
589
    {
590
        $count = 0;
591
592
        foreach ($this->getItems() as $item) {
593
            if ($withItemQty) {
594
                $count += $item->qty;
595
            } else {
596
                $count++;
597
            }
598
        }
599
600
        return $count;
601
    }
602
603
    /**
604
     *
605
     * Formats the number into a money format based on the locale and international formats
606
     *
607
     * @param $number
608
     * @param $locale
609
     * @param $internationalFormat
610
     * @param $format
611
     *
612
     * @return string
613
     */
614
    public static function formatMoney($number, $locale = null, $internationalFormat = null, $format = true)
615
    {
616
        $number = number_format($number, 2, '.', '');
617
618
        if ($format) {
619
            setlocale(LC_MONETARY, null);
620
            setlocale(LC_MONETARY, empty($locale) ? config('laracart.locale', 'en_US.UTF-8') : $locale);
621
622
            if (empty($internationalFormat) === true) {
623
                $internationalFormat = config('laracart.international_format', false);
624
            }
625
626
            $number = money_format($internationalFormat ? '%i' : '%n', $number);
627
        }
628
629
        return $number;
630
    }
631
632
    /**
633
     * Gets all the fee totals
634
     *
635
     * @param boolean $format
636
     *
637
     * @return string
638
     */
639
    public function feeTotals($format = true, $withTax = false)
640
    {
641
        $feeTotal = 0;
642
643
        foreach ($this->getFees() as $fee) {
644
            $feeTotal += $fee->amount;
645
646
            if ($withTax && $fee->taxable && $fee->tax > 0) {
647
                $feeTotal += $fee->amount * $fee->tax;
648
            }
649
        }
650
651
        return $this->formatMoney($feeTotal, null, null, $format);
652
    }
653
654
    /**
655
     * Gets all the fees on the cart object
656
     *
657
     * @return mixed
658
     */
659
    public function getFees()
660
    {
661
        return $this->cart->fees;
662
    }
663
664
    /**
665
     * Gets the total amount discounted
666
     *
667
     * @param boolean $format
668
     *
669
     * @return string
670
     */
671
    public function totalDiscount($format = true)
672
    {
673
        $total = 0;
674
675
        foreach ($this->cart->coupons as $coupon) {
676
            if ($coupon->appliedToCart) {
677
                $total += $coupon->discount();
678
            }
679
        }
680
681
        return $this->formatMoney($total, null, null, $format);
682
    }
683
}
684