ManagesCartItems::destroy()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Treestoneit\ShoppingCart\Concerns;
4
5
use Illuminate\Support\Facades\Session;
6
use Treestoneit\ShoppingCart\Buyable;
7
use Treestoneit\ShoppingCart\Models\Cart;
8
use Treestoneit\ShoppingCart\Models\CartItem;
9
10
trait ManagesCartItems
11
{
12
    use HasItems;
13
14
    /**
15
     * Get the cart model instance.
16
     *
17
     * @return \Treestoneit\ShoppingCart\Models\Cart
18
     */
19
    public function getModel(): Cart
20
    {
21
        return $this->cart;
22
    }
23
24
    /**
25
     * Add an item to the cart.
26
     *
27
     * @param  \Treestoneit\ShoppingCart\Buyable  $buyable
28
     * @param  int  $quantity
29
     * @param  array|null  $options
30
     * @return \Treestoneit\ShoppingCart\CartManager
31
     */
32
    public function add(Buyable $buyable, int $quantity = 1, array $options = []): self
33
    {
34
        $newItem = new CartItem();
35
        $newItem->setRelation('buyable', $buyable);
36
        $newItem->buyable()->associate($buyable);
0 ignored issues
show
Compatibility introduced by
$buyable of type object<Treestoneit\ShoppingCart\Buyable> is not a sub-type of object<Illuminate\Database\Eloquent\Model>. It seems like you assume a concrete implementation of the interface Treestoneit\ShoppingCart\Buyable to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
37
        $newItem->fill([
38
            'quantity' => $quantity,
39
            'options' => $options,
40
        ]);
41
42
        $item = $this->items()->first(function (CartItem $cartItem) use ($newItem) {
43
            return $cartItem->getIdentifierAttribute() === $newItem->getIdentifierAttribute();
44
        });
45
46
        // If the item already exists in the cart, we'll
47
        // just update the quantity by the given value.
48
        if ($item) {
49
            $item->increment('quantity', $quantity);
50
51
            return $this;
52
        }
53
54
        if (! $this->cart->exists) {
55
            $this->cart->save();
56
        }
57
58
        // We persist the new item to the database and add it to the items
59
        // collection. Eloquent doesn't do this by default, so we'll do it ourselves.
60
        $this->cart->items->add(
61
            $this->cart->items()->save($newItem)
62
        );
63
64
        $this->cart->push();
65
66
        $this->refreshCart();
67
68
        return $this;
69
    }
70
71
    /**
72
     * Change the quantity of an item in the cart.
73
     *
74
     * @param  int  $item
75
     * @param  int  $quantity
76
     * @return \Treestoneit\ShoppingCart\CartManager
77
     * @throws \Exception
78
     */
79
    public function update(int $item, int $quantity): self
80
    {
81
        return $this->updateQuantity($item, $quantity);
82
    }
83
84
    /**
85
     * Change the quantity of an item in the cart.
86
     *
87
     * @param  int  $item
88
     * @param  int  $quantity
89
     * @return \Treestoneit\ShoppingCart\CartManager
90
     * @throws \Exception
91
     */
92
    public function updateQuantity(int $item, int $quantity): self
93
    {
94
        if ($quantity <= 0) {
95
            return $this->remove($item);
96
        }
97
98
        if (! $this->items()->contains($item)) {
99
            return $this;
100
        }
101
102
        $this->items()->find($item)->update(['quantity' => $quantity]);
103
104
        return $this;
105
    }
106
107
    /**
108
     * Update the options of an item in the cart.
109
     *
110
     * @param  int  $item
111
     * @param  array  $options
112
     * @return \Treestoneit\ShoppingCart\CartManager
113
     */
114
    public function updateOptions(int $item, array $options): self
115
    {
116
        $this->items()->find($item)->update(['options' => $options]);
117
118
        return $this;
119
    }
120
121
    /**
122
     * Update an option of an item in the cart.
123
     *
124
     * @param  int  $item
125
     * @param  string  $option
126
     * @param $value
127
     * @return \Treestoneit\ShoppingCart\CartManager
128
     */
129
    public function updateOption(int $item, string $option, $value): self
130
    {
131
        return $this->updateOptions($item, [$option => $value]);
132
    }
133
134
    /**
135
     * Remove an item from the cart.
136
     *
137
     * @param  int  $item
138
     * @return static
139
     * @throws \Exception
140
     */
141
    public function remove(int $item): self
142
    {
143
        $key = $this->items()->search(function (CartItem $i) use ($item) {
144
            return $i->getKey() == $item;
145
        });
146
147
        if ($key === false) {
148
            return $this;
149
        }
150
151
        $this->items()->pull($key)->delete();
152
153
        if ($this->items()->isEmpty()) {
154
            return $this->destroy();
155
        }
156
157
        return $this;
158
    }
159
160
    /**
161
     * Destroy the cart instance.
162
     *
163
     * @return static
164
     */
165
    public function destroy()
166
    {
167
        $this->cart->delete();
168
169
        $this->refreshCart(new Cart());
170
171
        return $this;
172
    }
173
174
    /**
175
     * Toggle the session key, and recalculate totals.
176
     *
177
     * @param  \Treestoneit\ShoppingCart\Models\Cart|null  $cart
178
     * @return static
179
     */
180
    public function refreshCart(Cart $cart = null): self
181
    {
182
        if ($cart) {
183
            $this->cart = $cart;
184
        }
185
186
        $cart = $cart ?? $this->cart;
187
188
        if ($cart->exists) {
189
            $cart->loadMissing('items.buyable');
190
191
            Session::put('cart', $cart->getKey());
192
        } else {
193
            Session::forget('cart');
194
        }
195
196
        $this->clearCached();
0 ignored issues
show
Bug introduced by
It seems like clearCached() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
197
198
        return $this;
199
    }
200
201
    /**
202
     * Persist the cart contents to the database.
203
     *
204
     * @return static
205
     */
206
    protected function persist(): self
207
    {
208
        Session::put('cart', $this->cart->getKey());
209
210
        return $this;
211
    }
212
}
213