Completed
Pull Request — master (#183)
by
unknown
01:11
created

Cart::associate()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 9.6666
c 0
b 0
f 0
cc 3
nc 2
nop 1
1
<?php namespace Darryldecode\Cart;
2
3
use Darryldecode\Cart\Exceptions\InvalidConditionException;
4
use Darryldecode\Cart\Exceptions\InvalidItemException;
5
use Darryldecode\Cart\Helpers\Helpers;
6
use Darryldecode\Cart\Validators\CartItemValidator;
7
use Darryldecode\Cart\Exceptions\UnknownModelException;
8
9
/**
10
 * Class Cart
11
 * @package Darryldecode\Cart
12
 */
13
class Cart
14
{
15
16
    /**
17
     * the item storage
18
     *
19
     * @var
20
     */
21
    protected $session;
22
23
    /**
24
     * the event dispatcher
25
     *
26
     * @var
27
     */
28
    protected $events;
29
30
    /**
31
     * the cart session key
32
     *
33
     * @var
34
     */
35
    protected $instanceName;
36
37
    /**
38
     * the session key use for the cart
39
     *
40
     * @var
41
     */
42
    protected $sessionKey;
43
44
    /**
45
     * the session key use to persist cart items
46
     *
47
     * @var
48
     */
49
    protected $sessionKeyCartItems;
50
51
    /**
52
     * the session key use to persist cart conditions
53
     *
54
     * @var
55
     */
56
    protected $sessionKeyCartConditions;
57
58
    /**
59
     * Configuration to pass to ItemCollection
60
     *
61
     * @var
62
     */
63
    protected $config;
64
65
    /**
66
     * This holds the currently added item id in cart for association
67
     * 
68
     * @var
69
     */
70
    protected $currentItemId;
71
72
    /**
73
     * our object constructor
74
     *
75
     * @param $session
76
     * @param $events
77
     * @param $instanceName
78
     * @param $session_key
79
     * @param $config
80
     */
81
    public function __construct($session, $events, $instanceName, $session_key, $config)
82
    {
83
        $this->events = $events;
84
        $this->session = $session;
85
        $this->instanceName = $instanceName;
86
        $this->sessionKey = $session_key;
87
        $this->sessionKeyCartItems = $this->sessionKey . '_cart_items';
88
        $this->sessionKeyCartConditions = $this->sessionKey . '_cart_conditions';
89
        $this->config = $config;
90
        $this->currentItem = null;
0 ignored issues
show
Bug introduced by
The property currentItem does not seem to exist. Did you mean currentItemId?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
91
        $this->fireEvent('created');
92
    }
93
94
    /**
95
     * sets the session key
96
     *
97
     * @param string $sessionKey the session key or identifier
98
     * @return $this|bool
99
     * @throws \Exception
100
     */
101
    public function session($sessionKey)
102
    {
103
        if (!$sessionKey) throw new \Exception("Session key is required.");
104
105
        $this->sessionKey = $sessionKey;
106
        $this->sessionKeyCartItems = $this->sessionKey . '_cart_items';
107
        $this->sessionKeyCartConditions = $this->sessionKey . '_cart_conditions';
108
109
        return $this;
110
    }
111
112
    /**
113
     * get instance name of the cart
114
     *
115
     * @return string
116
     */
117
    public function getInstanceName()
118
    {
119
        return $this->instanceName;
120
    }
121
122
    /**
123
     * get an item on a cart by item ID
124
     *
125
     * @param $itemId
126
     * @return mixed
127
     */
128
    public function get($itemId)
129
    {
130
        return $this->getContent()->get($itemId);
131
    }
132
133
    /**
134
     * check if an item exists by item ID
135
     *
136
     * @param $itemId
137
     * @return bool
138
     */
139
    public function has($itemId)
140
    {
141
        return $this->getContent()->has($itemId);
142
    }
143
144
    /**
145
     * add item to the cart, it can be an array or multi dimensional array
146
     *
147
     * @param string|array $id
148
     * @param string $name
149
     * @param float $price
150
     * @param int $quantity
151
     * @param array $attributes
152
     * @param CartCondition|array $conditions
153
     * @return $this
154
     * @throws InvalidItemException
155
     */
156
    public function add($id, $name = null, $price = null, $quantity = null, $attributes = array(), $conditions = array())
157
    {
158
        // if the first argument is an array,
159
        // we will need to call add again
160
        if (is_array($id)) {
161
            // the first argument is an array, now we will need to check if it is a multi dimensional
162
            // array, if so, we will iterate through each item and call add again
163
            if (Helpers::isMultiArray($id)) {
164
                foreach ($id as $item) {
165
                    $this->add(
166
                        $item['id'],
167
                        $item['name'],
168
                        $item['price'],
169
                        $item['quantity'],
170
                        Helpers::issetAndHasValueOrAssignDefault($item['attributes'], array()),
171
                        Helpers::issetAndHasValueOrAssignDefault($item['conditions'], array())
172
                    );
173
                }
174
            } else {
175
                $this->add(
176
                    $id['id'],
177
                    $id['name'],
178
                    $id['price'],
179
                    $id['quantity'],
180
                    Helpers::issetAndHasValueOrAssignDefault($id['attributes'], array()),
181
                    Helpers::issetAndHasValueOrAssignDefault($id['conditions'], array())
182
                );
183
            }
184
185
            return $this;
186
        }
187
188
        // validate data
189
        $item = $this->validate(array(
190
            'id' => $id,
191
            'name' => $name,
192
            'price' => Helpers::normalizePrice($price),
193
            'quantity' => $quantity,
194
            'attributes' => new ItemAttributeCollection($attributes),
195
            'conditions' => $conditions,
196
        ));
197
198
        // get the cart
199
        $cart = $this->getContent();
200
201
        // if the item is already in the cart we will just update it
202
        if ($cart->has($id)) {
203
204
            $this->update($id, $item);
205
        } else {
206
207
            $this->addRow($id, $item);
208
        }
209
210
        $this->currentItemId = $id;
211
212
        return $this;
213
    }
214
215
    /**
216
     * update a cart
217
     *
218
     * @param $id
219
     * @param $data
220
     *
221
     * the $data will be an associative array, you don't need to pass all the data, only the key value
222
     * of the item you want to update on it
223
     * @return bool
224
     */
225
    public function update($id, $data)
226
    {
227
        if ($this->fireEvent('updating', $data) === false) {
228
            return false;
229
        }
230
231
        $cart = $this->getContent();
232
233
        $item = $cart->pull($id);
234
235
        foreach ($data as $key => $value) {
236
            // if the key is currently "quantity" we will need to check if an arithmetic
237
            // symbol is present so we can decide if the update of quantity is being added
238
            // or being reduced.
239
            if ($key == 'quantity') {
240
                // we will check if quantity value provided is array,
241
                // if it is, we will need to check if a key "relative" is set
242
                // and we will evaluate its value if true or false,
243
                // this tells us how to treat the quantity value if it should be updated
244
                // relatively to its current quantity value or just totally replace the value
245
                if (is_array($value)) {
246
                    if (isset($value['relative'])) {
247
                        if ((bool)$value['relative']) {
248
                            $item = $this->updateQuantityRelative($item, $key, $value['value']);
249
                        } else {
250
                            $item = $this->updateQuantityNotRelative($item, $key, $value['value']);
251
                        }
252
                    }
253
                } else {
254
                    $item = $this->updateQuantityRelative($item, $key, $value);
255
                }
256
            } elseif ($key == 'attributes') {
257
                $item[$key] = new ItemAttributeCollection($value);
258
            } else {
259
                $item[$key] = $value;
260
            }
261
        }
262
263
        $cart->put($id, $item);
264
265
        $this->save($cart);
266
267
        $this->fireEvent('updated', $item);
268
        return true;
269
    }
270
271
    /**
272
     * add condition on an existing item on the cart
273
     *
274
     * @param int|string $productId
275
     * @param CartCondition $itemCondition
276
     * @return $this
277
     */
278
    public function addItemCondition($productId, $itemCondition)
279
    {
280
        if ($product = $this->get($productId)) {
281
            $conditionInstance = "\\Darryldecode\\Cart\\CartCondition";
282
283
            if ($itemCondition instanceof $conditionInstance) {
284
                // we need to copy first to a temporary variable to hold the conditions
285
                // to avoid hitting this error "Indirect modification of overloaded element of Darryldecode\Cart\ItemCollection has no effect"
286
                // this is due to laravel Collection instance that implements Array Access
287
                // // see link for more info: http://stackoverflow.com/questions/20053269/indirect-modification-of-overloaded-element-of-splfixedarray-has-no-effect
288
                $itemConditionTempHolder = $product['conditions'];
289
290
                if (is_array($itemConditionTempHolder)) {
291
                    array_push($itemConditionTempHolder, $itemCondition);
292
                } else {
293
                    $itemConditionTempHolder = $itemCondition;
294
                }
295
296
                $this->update($productId, array(
297
                    'conditions' => $itemConditionTempHolder // the newly updated conditions
298
                ));
299
            }
300
        }
301
302
        return $this;
303
    }
304
305
    /**
306
     * removes an item on cart by item ID
307
     *
308
     * @param $id
309
     * @return bool
310
     */
311
    public function remove($id)
312
    {
313
        $cart = $this->getContent();
314
315
        if ($this->fireEvent('removing', $id) === false) {
316
            return false;
317
        }
318
319
        $cart->forget($id);
320
321
        $this->save($cart);
322
323
        $this->fireEvent('removed', $id);
324
        return true;
325
    }
326
327
    /**
328
     * clear cart
329
     * @return bool
330
     */
331
    public function clear()
332
    {
333
        if ($this->fireEvent('clearing') === false) {
334
            return false;
335
        }
336
337
        $this->session->put(
338
            $this->sessionKeyCartItems,
339
            array()
340
        );
341
342
        $this->fireEvent('cleared');
343
        return true;
344
    }
345
346
    /**
347
     * add a condition on the cart
348
     *
349
     * @param CartCondition|array $condition
350
     * @return $this
351
     * @throws InvalidConditionException
352
     */
353
    public function condition($condition)
354
    {
355
        if (is_array($condition)) {
356
            foreach ($condition as $c) {
357
                $this->condition($c);
358
            }
359
360
            return $this;
361
        }
362
363
        if (!$condition instanceof CartCondition) throw new InvalidConditionException('Argument 1 must be an instance of \'Darryldecode\Cart\CartCondition\'');
364
365
        $conditions = $this->getConditions();
366
367
        // Check if order has been applied
368
        if ($condition->getOrder() == 0) {
369
            $last = $conditions->last();
370
            $condition->setOrder(!is_null($last) ? $last->getOrder() + 1 : 1);
371
        }
372
373
        $conditions->put($condition->getName(), $condition);
374
375
        $conditions = $conditions->sortBy(function ($condition, $key) {
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
376
            return $condition->getOrder();
377
        });
378
379
        $this->saveConditions($conditions);
380
381
        return $this;
382
    }
383
384
    /**
385
     * get conditions applied on the cart
386
     *
387
     * @return CartConditionCollection
388
     */
389
    public function getConditions()
390
    {
391
        return new CartConditionCollection($this->session->get($this->sessionKeyCartConditions));
392
    }
393
394
    /**
395
     * get condition applied on the cart by its name
396
     *
397
     * @param $conditionName
398
     * @return CartCondition
399
     */
400
    public function getCondition($conditionName)
401
    {
402
        return $this->getConditions()->get($conditionName);
403
    }
404
405
    /**
406
     * Get all the condition filtered by Type
407
     * Please Note that this will only return condition added on cart bases, not those conditions added
408
     * specifically on an per item bases
409
     *
410
     * @param $type
411
     * @return CartConditionCollection
412
     */
413
    public function getConditionsByType($type)
414
    {
415
        return $this->getConditions()->filter(function (CartCondition $condition) use ($type) {
416
            return $condition->getType() == $type;
417
        });
418
    }
419
420
421
    /**
422
     * Remove all the condition with the $type specified
423
     * Please Note that this will only remove condition added on cart bases, not those conditions added
424
     * specifically on an per item bases
425
     *
426
     * @param $type
427
     * @return $this
428
     */
429
    public function removeConditionsByType($type)
430
    {
431
        $this->getConditionsByType($type)->each(function ($condition) {
432
            $this->removeCartCondition($condition->getName());
433
        });
434
    }
435
436
437
    /**
438
     * removes a condition on a cart by condition name,
439
     * this can only remove conditions that are added on cart bases not conditions that are added on an item/product.
440
     * If you wish to remove a condition that has been added for a specific item/product, you may
441
     * use the removeItemCondition(itemId, conditionName) method instead.
442
     *
443
     * @param $conditionName
444
     * @return void
445
     */
446
    public function removeCartCondition($conditionName)
447
    {
448
        $conditions = $this->getConditions();
449
450
        $conditions->pull($conditionName);
451
452
        $this->saveConditions($conditions);
453
    }
454
455
    /**
456
     * remove a condition that has been applied on an item that is already on the cart
457
     *
458
     * @param $itemId
459
     * @param $conditionName
460
     * @return bool
461
     */
462
    public function removeItemCondition($itemId, $conditionName)
463
    {
464
        if (!$item = $this->getContent()->get($itemId)) {
465
            return false;
466
        }
467
468
        if ($this->itemHasConditions($item)) {
469
            // NOTE:
470
            // we do it this way, we get first conditions and store
471
            // it in a temp variable $originalConditions, then we will modify the array there
472
            // and after modification we will store it again on $item['conditions']
473
            // This is because of ArrayAccess implementation
474
            // see link for more info: http://stackoverflow.com/questions/20053269/indirect-modification-of-overloaded-element-of-splfixedarray-has-no-effect
475
476
            $tempConditionsHolder = $item['conditions'];
477
478
            // if the item's conditions is in array format
479
            // we will iterate through all of it and check if the name matches
480
            // to the given name the user wants to remove, if so, remove it
481
            if (is_array($tempConditionsHolder)) {
482
                foreach ($tempConditionsHolder as $k => $condition) {
483
                    if ($condition->getName() == $conditionName) {
484
                        unset($tempConditionsHolder[$k]);
485
                    }
486
                }
487
488
                $item['conditions'] = $tempConditionsHolder;
489
            }
490
491
            // if the item condition is not an array, we will check if it is
492
            // an instance of a Condition, if so, we will check if the name matches
493
            // on the given condition name the user wants to remove, if so,
494
            // lets just make $item['conditions'] an empty array as there's just 1 condition on it anyway
495
            else {
496
                $conditionInstance = "Darryldecode\\Cart\\CartCondition";
497
498
                if ($item['conditions'] instanceof $conditionInstance) {
499
                    if ($tempConditionsHolder->getName() == $conditionName) {
500
                        $item['conditions'] = array();
501
                    }
502
                }
503
            }
504
        }
505
506
        $this->update($itemId, array(
507
            'conditions' => $item['conditions']
508
        ));
509
510
        return true;
511
    }
512
513
    /**
514
     * remove all conditions that has been applied on an item that is already on the cart
515
     *
516
     * @param $itemId
517
     * @return bool
518
     */
519
    public function clearItemConditions($itemId)
520
    {
521
        if (!$item = $this->getContent()->get($itemId)) {
522
            return false;
523
        }
524
525
        $this->update($itemId, array(
526
            'conditions' => array()
527
        ));
528
529
        return true;
530
    }
531
532
    /**
533
     * clears all conditions on a cart,
534
     * this does not remove conditions that has been added specifically to an item/product.
535
     * If you wish to remove a specific condition to a product, you may use the method: removeItemCondition($itemId, $conditionName)
536
     *
537
     * @return void
538
     */
539
    public function clearCartConditions()
540
    {
541
        $this->session->put(
542
            $this->sessionKeyCartConditions,
543
            array()
544
        );
545
    }
546
547
    /**
548
     * get cart sub total without conditions
549
     * @param bool $formatted
550
     * @return float
551
     */
552
    public function getSubTotalWithoutConditions($formatted = true)
553
    {
554
        $cart = $this->getContent();
555
556
        $sum = $cart->sum(function ($item) {
557
            return $item->getPriceSum();
558
        });
559
560
        return Helpers::formatValue(floatval($sum), $formatted, $this->config);
561
    }
562
563
    /**
564
     * get cart sub total
565
     * @param bool $formatted
566
     * @return float
567
     */
568
    public function getSubTotal($formatted = true)
569
    {
570
        $cart = $this->getContent();
571
572
        $sum = $cart->sum(function (ItemCollection $item) {
573
            return $item->getPriceSumWithConditions(false);
574
        });
575
576
        // get the conditions that are meant to be applied
577
        // on the subtotal and apply it here before returning the subtotal
578
        $conditions = $this
579
            ->getConditions()
580
            ->filter(function (CartCondition $cond) {
581
                return $cond->getTarget() === 'subtotal';
582
            });
583
584
        // if there is no conditions, lets just return the sum
585
        if (!$conditions->count()) return Helpers::formatValue(floatval($sum), $formatted, $this->config);
586
587
        // there are conditions, lets apply it
588
        $newTotal = 0.00;
589
        $process = 0;
590
591 View Code Duplication
        $conditions->each(function (CartCondition $cond) use ($sum, &$newTotal, &$process) {
592
593
            // if this is the first iteration, the toBeCalculated
594
            // should be the sum as initial point of value.
595
            $toBeCalculated = ($process > 0) ? $newTotal : $sum;
596
597
            $newTotal = $cond->applyCondition($toBeCalculated);
598
599
            $process++;
600
        });
601
602
        return Helpers::formatValue(floatval($newTotal), $formatted, $this->config);
603
    }
604
605
    /**
606
     * the new total in which conditions are already applied
607
     *
608
     * @return float
609
     */
610
    public function getTotal()
611
    {
612
        $subTotal = $this->getSubTotal(false);
613
614
        $newTotal = 0.00;
615
616
        $process = 0;
617
618
        $conditions = $this
619
            ->getConditions()
620
            ->filter(function (CartCondition $cond) {
621
                return $cond->getTarget() === 'total';
622
            });
623
624
        // if no conditions were added, just return the sub total
625
        if (!$conditions->count()) {
626
            return Helpers::formatValue($subTotal, $this->config['format_numbers'], $this->config);
627
        }
628
629
        $conditions
630 View Code Duplication
            ->each(function (CartCondition $cond) use ($subTotal, &$newTotal, &$process) {
631
                $toBeCalculated = ($process > 0) ? $newTotal : $subTotal;
632
633
                $newTotal = $cond->applyCondition($toBeCalculated);
634
635
                $process++;
636
            });
637
638
        return Helpers::formatValue($newTotal, $this->config['format_numbers'], $this->config);
639
    }
640
641
    /**
642
     * get total quantity of items in the cart
643
     *
644
     * @return int
645
     */
646
    public function getTotalQuantity()
647
    {
648
        $items = $this->getContent();
649
650
        if ($items->isEmpty()) return 0;
651
652
        $count = $items->sum(function ($item) {
653
            return $item['quantity'];
654
        });
655
656
        return $count;
657
    }
658
659
    /**
660
     * get the cart
661
     *
662
     * @return CartCollection
663
     */
664
    public function getContent()
665
    {
666
        return (new CartCollection($this->session->get($this->sessionKeyCartItems)));
667
    }
668
669
    /**
670
     * check if cart is empty
671
     *
672
     * @return bool
673
     */
674
    public function isEmpty()
675
    {
676
        $cart = new CartCollection($this->session->get($this->sessionKeyCartItems));
677
678
        return $cart->isEmpty();
679
    }
680
681
    /**
682
     * validate Item data
683
     *
684
     * @param $item
685
     * @return array $item;
686
     * @throws InvalidItemException
687
     */
688 View Code Duplication
    protected function validate($item)
689
    {
690
        $rules = array(
691
            'id' => 'required',
692
            'price' => 'required|numeric',
693
            'quantity' => 'required|numeric|min:1',
694
            'name' => 'required',
695
        );
696
697
        $validator = CartItemValidator::make($item, $rules);
698
699
        if ($validator->fails()) {
700
            throw new InvalidItemException($validator->messages()->first());
701
        }
702
703
        return $item;
704
    }
705
706
    /**
707
     * add row to cart collection
708
     *
709
     * @param $id
710
     * @param $item
711
     * @return bool
712
     */
713
    protected function addRow($id, $item)
714
    {
715
        if ($this->fireEvent('adding', $item) === false) {
716
            return false;
717
        }
718
719
        $cart = $this->getContent();
720
721
        $cart->put($id, new ItemCollection($item, $this->config));
722
723
        $this->save($cart);
724
725
        $this->fireEvent('added', $item);
726
727
        return true;
728
    }
729
730
    /**
731
     * save the cart
732
     *
733
     * @param $cart CartCollection
734
     */
735
    protected function save($cart)
736
    {
737
        $this->session->put($this->sessionKeyCartItems, $cart);
738
    }
739
740
    /**
741
     * save the cart conditions
742
     *
743
     * @param $conditions
744
     */
745
    protected function saveConditions($conditions)
746
    {
747
        $this->session->put($this->sessionKeyCartConditions, $conditions);
748
    }
749
750
    /**
751
     * check if an item has condition
752
     *
753
     * @param $item
754
     * @return bool
755
     */
756
    protected function itemHasConditions($item)
757
    {
758
        if (!isset($item['conditions'])) return false;
759
760
        if (is_array($item['conditions'])) {
761
            return count($item['conditions']) > 0;
762
        }
763
764
        $conditionInstance = "Darryldecode\\Cart\\CartCondition";
765
766
        if ($item['conditions'] instanceof $conditionInstance) return true;
767
768
        return false;
769
    }
770
771
    /**
772
     * update a cart item quantity relative to its current quantity
773
     *
774
     * @param $item
775
     * @param $key
776
     * @param $value
777
     * @return mixed
778
     */
779
    protected function updateQuantityRelative($item, $key, $value)
780
    {
781
        if (preg_match('/\-/', $value) == 1) {
782
            $value = (int)str_replace('-', '', $value);
783
784
            // we will not allowed to reduced quantity to 0, so if the given value
785
            // would result to item quantity of 0, we will not do it.
786
            if (($item[$key] - $value) > 0) {
787
                $item[$key] -= $value;
788
            }
789
        } elseif (preg_match('/\+/', $value) == 1) {
790
            $item[$key] += (int)str_replace('+', '', $value);
791
        } else {
792
            $item[$key] += (int)$value;
793
        }
794
795
        return $item;
796
    }
797
798
    /**
799
     * update cart item quantity not relative to its current quantity value
800
     *
801
     * @param $item
802
     * @param $key
803
     * @param $value
804
     * @return mixed
805
     */
806
    protected function updateQuantityNotRelative($item, $key, $value)
807
    {
808
        $item[$key] = (int)$value;
809
810
        return $item;
811
    }
812
813
    /**
814
     * Setter for decimals. Change value on demand.
815
     * @param $decimals
816
     */
817
    public function setDecimals($decimals)
818
    {
819
        $this->decimals = $decimals;
0 ignored issues
show
Bug introduced by
The property decimals does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
820
    }
821
822
    /**
823
     * Setter for decimals point. Change value on demand.
824
     * @param $dec_point
825
     */
826
    public function setDecPoint($dec_point)
827
    {
828
        $this->dec_point = $dec_point;
0 ignored issues
show
Bug introduced by
The property dec_point does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
829
    }
830
831
    public function setThousandsSep($thousands_sep)
832
    {
833
        $this->thousands_sep = $thousands_sep;
0 ignored issues
show
Bug introduced by
The property thousands_sep does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
834
    }
835
836
    /**
837
     * @param $name
838
     * @param $value
839
     * @return mixed
840
     */
841
    protected function fireEvent($name, $value = [])
842
    {
843
        return $this->events->dispatch($this->getInstanceName() . '.' . $name, array_values([$value, $this]));
844
    }
845
846
    /**
847
     * Associate the cart item with the given id with the given model.
848
     *
849
     * @param string $id
0 ignored issues
show
Bug introduced by
There is no parameter named $id. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
850
     * @param mixed  $model
851
     *
852
     * @return void
853
     */
854
    public function associate($model)
855
    {
856
        if (is_string($model) && !class_exists($model)) {
857
            throw new UnknownModelException("The supplied model {$model} does not exist.");
858
        }
859
860
        $cart = $this->getContent();
861
862
        $item = $cart->pull($this->currentItemId);
863
864
        $item['associatedModel'] = $model;
865
866
        $cart->put($this->currentItemId, new ItemCollection($item, $this->config));
867
868
        $this->save($cart);
869
870
        return $this;
871
    }
872
}
873