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