OrderItem   A
last analyzed

Complexity

Total Complexity 33

Size/Duplication

Total Lines 226
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 74
c 1
b 0
f 0
dl 0
loc 226
rs 9.76
wmc 33

16 Methods

Rating   Name   Duplication   Size   Complexity  
A setQuantity() 0 4 2
A Buyable() 0 3 1
A onPayment() 0 3 1
A onPlacement() 0 3 1
A removeallLink() 0 4 2
A addLink() 0 4 2
A removeLink() 0 4 2
A QuantityField() 0 3 1
A Image() 0 4 2
A setquantityLink() 0 4 2
A onBeforeWrite() 0 5 4
A UnitPrice() 0 9 3
A calculatetotal() 0 6 1
A Total() 0 6 2
A setUnitPrice() 0 6 2
A uniquedata() 0 16 5
1
<?php
2
3
namespace SilverShop\Model;
4
5
use SilverShop\Cart\ShoppingCartController;
6
use SilverShop\Forms\ShopQuantityField;
7
use SilverStripe\Forms\TextField;
8
use SilverStripe\ORM\FieldType\DBCurrency;
9
10
/**
11
 * An order item is a product which has been added to an order,
12
 * ready for purchase. An order item is typically a product itself,
13
 * but also can include references to other information such as
14
 * product attributes like colour, size, or type.
15
 *
16
 * @property int $Quantity
17
 * @property DBCurrency $UnitPrice
18
 */
19
class OrderItem extends OrderAttribute
20
{
21
    private static $db = [
22
        'Quantity' => 'Int',
23
        'UnitPrice' => 'Currency',
24
    ];
25
26
    private static $casting = [
27
        'UnitPrice' => 'Currency',
28
        'Total' => 'Currency',
29
    ];
30
31
    private static $searchable_fields = [
32
        'OrderID' => [
33
            'title' => 'Order ID',
34
            'field' => TextField::class,
35
        ],
36
        'Title' => 'PartialMatchFilter',
37
        'TableTitle' => 'PartialMatchFilter',
38
        'CartTitle' => 'PartialMatchFilter',
39
        'UnitPrice',
40
        'Quantity',
41
        'Total',
42
    ];
43
44
    private static $summary_fields = [
45
        'Order.ID' => 'Order ID',
46
        'TableTitle' => 'Title',
47
        'UnitPrice' => 'Unit Price',
48
        'Quantity' => 'Quantity',
49
        'Total' => 'Total Price',
50
    ];
51
52
    private static $required_fields = [];
53
54
    /**
55
     * The ORM relationship to the buyable item
56
     *
57
     * @config
58
     * @var    string
59
     */
60
    private static $buyable_relationship = 'Product';
61
62
    private static $singular_name = 'Item';
63
64
    private static $plural_name = 'Items';
65
66
    private static $default_sort = '"Created" DESC';
67
68
    private static $table_name = 'SilverShop_OrderItem';
69
70
    /**
71
     * Get the buyable object related to this item.
72
     */
73
    public function Buyable()
74
    {
75
        return $this->{self::config()->buyable_relationship}();
76
    }
77
78
    /**
79
     * Get unit price for this item.
80
     * Fetches from db, or Buyable, based on order status.
81
     */
82
    public function UnitPrice()
83
    {
84
        if ($this->Order()->IsCart()) {
85
            $buyable = $this->Buyable();
86
            $unitprice = ($buyable) ? $buyable->sellingPrice() : $this->UnitPrice;
87
            $this->extend('updateUnitPrice', $unitprice);
88
            return $this->UnitPrice = $unitprice;
89
        }
90
        return $this->UnitPrice;
91
    }
92
93
    /**
94
     * Prevent unit price ever being below 0
95
     */
96
    public function setUnitPrice($val)
97
    {
98
        if ($val < 0) {
99
            $val = 0;
100
        }
101
        $this->setField('UnitPrice', $val);
102
    }
103
104
    /**
105
     * Prevent quantity being below 1.
106
     * 0 quantity means it should instead be deleted.
107
     *
108
     * @param int $val new quantity to set
109
     */
110
    public function setQuantity($val)
111
    {
112
        $val = $val < 1 ? 1 : $val;
113
        $this->setField('Quantity', $val);
114
    }
115
116
    /**
117
     * Get calculated total, or stored total
118
     * depending on whether the order is in cart
119
     */
120
    public function Total()
121
    {
122
        if ($this->Order()->IsCart()) { //always calculate total if order is in cart
123
            return $this->calculatetotal();
124
        }
125
        return $this->CalculatedTotal; //otherwise get value from database
126
    }
127
128
    /**
129
     * Calculates the total for this item.
130
     * Generally called by onBeforeWrite
131
     */
132
    protected function calculatetotal()
133
    {
134
        $total = (float)$this->UnitPrice() * (int)$this->Quantity;
135
        $this->extend('updateTotal', $total);
136
        $this->CalculatedTotal = $total;
137
        return $total;
138
    }
139
140
    /**
141
     * Intersects this item's required_fields with the data record.
142
     * This is used for uniquely adding items to the cart.
143
     */
144
    public function uniquedata()
145
    {
146
        $required = self::config()->required_fields; //TODO: also combine with all ancestors of this->class
147
        $unique = [];
148
        $hasOnes = $this->hasOne();
149
        //reduce record to only required fields
150
        if ($required) {
151
            foreach ($required as $field) {
152
                if ($hasOnes === $field || isset($hasOnes[$field])) {
153
                    $field = $field . 'ID'; //add ID to hasones
154
                }
155
                $unique[$field] = $this->$field;
156
            }
157
        }
158
        $this->extend('updateuniquedata', $unique);
159
        return $unique;
160
    }
161
162
    /**
163
     * Recalculate total before saving to database.
164
     */
165
    public function onBeforeWrite()
166
    {
167
        parent::onBeforeWrite();
168
        if ($this->OrderID && $this->Order() && $this->Order()->isCart()) {
169
            $this->calculatetotal();
170
        }
171
    }
172
173
    /*
174
     * Event handler called when an order is fully paid for.
175
     */
176
    public function onPayment()
177
    {
178
        $this->extend('onPayment');
179
    }
180
181
    /**
182
     * Event handlier called for last time saving/processing,
183
     * before item permanently stored in database.
184
     * This should only be called when order is transformed from
185
     * Cart to Order, aka being 'placed'.
186
     */
187
    public function onPlacement()
188
    {
189
        $this->extend('onPlacement');
190
    }
191
192
    /**
193
     * Get the buyable image.
194
     * Also serves as a standardised placeholder for overriding in subclasses.
195
     */
196
    public function Image()
197
    {
198
        if ($this->Buyable()) {
199
            return $this->Buyable()->Image();
200
        }
201
    }
202
203
    /**
204
     * @return ShopQuantityField
205
     */
206
    public function QuantityField()
207
    {
208
        return ShopQuantityField::create($this);
209
    }
210
211
    /**
212
     * @return string
213
     */
214
    public function addLink()
215
    {
216
        $buyable = $this->Buyable();
217
        return $buyable ? ShoppingCartController::add_item_link($buyable, $this->uniquedata()) : '';
0 ignored issues
show
Bug Best Practice introduced by
The expression return $buyable ? Silver...his->uniquedata()) : '' could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
218
    }
219
220
    /**
221
     * @return string
222
     */
223
    public function removeLink()
224
    {
225
        $buyable = $this->Buyable();
226
        return $buyable ? ShoppingCartController::remove_item_link($buyable, $this->uniquedata()) : '';
0 ignored issues
show
Bug Best Practice introduced by
The expression return $buyable ? Silver...his->uniquedata()) : '' could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
227
    }
228
229
    /**
230
     * @return string
231
     */
232
    public function removeallLink()
233
    {
234
        $buyable = $this->Buyable();
235
        return $buyable ? ShoppingCartController::remove_all_item_link($buyable, $this->uniquedata()) : '';
0 ignored issues
show
Bug Best Practice introduced by
The expression return $buyable ? Silver...his->uniquedata()) : '' could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
236
    }
237
238
    /**
239
     * @return string
240
     */
241
    public function setquantityLink()
242
    {
243
        $buyable = $this->Buyable();
244
        return $buyable ? ShoppingCartController::set_quantity_item_link($buyable, $this->uniquedata()) : '';
0 ignored issues
show
Bug Best Practice introduced by
The expression return $buyable ? Silver...his->uniquedata()) : '' could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
245
    }
246
}
247