Passed
Push — 1.0 ( dbac97...74fb09 )
by Morven
04:14
created

LineItem   D

Complexity

Total Complexity 61

Size/Duplication

Total Lines 549
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 549
rs 4.054
c 0
b 0
f 0
wmc 61

23 Methods

Rating   Name   Duplication   Size   Complexity  
A getTaxTotal() 0 7 1
A FindStockItem() 0 3 1
A canView() 0 8 3
B Image() 0 10 8
A CustomisationAndPriceList() 0 18 4
A getSubTotal() 0 7 1
B Match() 0 12 5
A onBeforeDelete() 0 6 2
A canDelete() 0 8 3
A canEdit() 0 8 3
A onAfterWrite() 0 15 4
A onBeforeWrite() 0 6 1
A canCreate() 0 8 3
A CustomisationList() 0 18 4
A getUnitPrice() 0 11 2
A getTaxRate() 0 7 2
A getTotal() 0 7 1
A duplicate() 0 14 3
A getUnitTotal() 0 7 1
A checkStockLevel() 0 10 2
A getCMSFields() 0 55 2
A CustomisationHTML() 0 17 4
A getUnitTax() 0 7 1

How to fix   Complexity   

Complex Class

Complex classes like LineItem often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use LineItem, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace SilverCommerce\OrdersAdmin\Model;
4
5
use SilverStripe\ORM\DataObject;
6
use SilverStripe\ORM\FieldType\DBHTMLText as HTMLText;
7
use SilverStripe\ORM\ArrayList;
8
use SilverStripe\Forms\FieldList;
9
use SilverStripe\Forms\ReadonlyField;
10
use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
11
use SilverStripe\Forms\GridField\GridField;
12
use SilverStripe\Forms\GridField\GridFieldConfig;
13
use SilverStripe\Forms\GridField\GridFieldConfig_Base;
14
use SilverStripe\Forms\GridField\GridFieldButtonRow;
15
use Symbiote\GridFieldExtensions\GridFieldEditableColumns;
16
use Symbiote\GridFieldExtensions\GridFieldAddNewInlineButton;
17
use SilverStripe\Forms\GridField\GridFieldEditButton;
18
use SilverStripe\Forms\GridField\GridFieldDeleteAction;
19
use SilverStripe\Forms\GridField\GridFieldDataColumns;
20
use SilverStripe\Forms\GridField\GridFieldAddNewButton;
21
use SilverStripe\Forms\GridField\GridFieldAddExistingAutocompleter;
22
use SilverStripe\SiteConfig\SiteConfig;
23
use SilverCommerce\TaxAdmin\Model\TaxRate;
24
use SilverStripe\Forms\DropdownField;
25
26
/**
27
 * A LineItem is a single line item on an order, extimate or even in
28
 * the shopping cart.
29
 * 
30
 * An item has a number of fields that describes a product:
31
 * 
32
 * - Key: ID used to detect this item
33
 * - Title: Title of the item
34
 * - Content: Description of this object
35
 * - Quantity: Number or items in this order
36
 * - Weight: Weight of this item (unit of measurment is defined globally)
37
 * - TaxRate: Rate of tax for this item (e.g. 20.00 for 20%)
38
 * - ProductClass: ClassName of product that this item is matched against
39
 * - StockID: Unique identifier of this item (used with ProductClass
40
 *            match to a product)
41
 * - Locked: Is this a locked item? Locked items cannot be changed in the
42
 *           shopping cart
43
 * - Deliverable: Is this a product that can be delivered? This can effect
44
 *                delivery options
45
 *
46
 * @author Mo <[email protected]>
47
 */
48
class LineItem extends DataObject
49
{
50
    private static $table_name = 'LineItem';
51
52
    /**
53
     * The name of the param used on a related product to
54
     * track Stock Levels.
55
     * 
56
     * Defaults to StockLevel
57
     *
58
     * @var string
59
     * @config
60
     */
61
    private static $stock_param = "StockLevel";
62
63
    /**
64
     * Standard database columns
65
     * 
66
     * @var array
67
     * @config
68
     */
69
    private static $db = [
70
        "Key"           => "Varchar(255)",
71
        "Title"         => "Varchar",
72
        "Content"       => "HTMLText",
73
        "Quantity"      => "Int",
74
        "Price"         => "Currency",
75
        "Weight"        => "Decimal",
76
        "StockID"       => "Varchar(100)",
77
        "ProductClass"  => "Varchar",
78
        "Locked"        => "Boolean",
79
        "Stocked"       => "Boolean",
80
        "Deliverable"   => "Boolean",
81
        "Customisation" => "Text",
82
    ];
83
84
    /**
85
     * Foreign key associations in DB
86
     * 
87
     * @var array
88
     * @config
89
     */
90
    private static $has_one = [
91
        "Parent"      => Estimate::class,
92
        "Tax"         => TaxRate::class,
93
    ];
94
    
95
    /**
96
     * One to many associations
97
     *
98
     * @var array
99
     * @config
100
     */
101
    private static $has_many = [
102
        "Customisations" => LineItemCustomisation::class
103
    ];
104
105
    /**
106
     * Specify default values of a field
107
     *
108
     * @var array
109
     * @config
110
     */
111
    private static $defaults = [
112
        "Quantity"      => 1,
113
        "ProductClass"  => "Product",
114
        "Locked"        => false,
115
        "Stocked"       => false,
116
        "Deliverable"   => true
117
    ];
118
119
    /**
120
     * Fields to display in list tables
121
     * 
122
     * @var array
123
     * @config
124
     */
125
    private static $summary_fields = [
126
        "Quantity"  => "Quantity",
127
        "Title"     => "Title",
128
        "StockID"   => "Stock ID",
129
        "Price"     => "Item Price",
130
        "TaxID"    => "Tax",
131
        "CustomisationAndPriceList" => "Customisations"
132
    ];
133
    
134
    /**
135
     * Function to DB Object conversions
136
     * 
137
     * @var array
138
     * @config
139
     */
140
    private static $casting = [
141
        "UnitPrice" => "Currency",
142
        "UnitTax"   => "Currency",
143
        "UnitTotal" => "Currency",
144
        "SubTotal"  => "Currency",
145
        "TaxRate"   => "Decimal",
146
        "TaxTotal"  => "Currency",
147
        "Total"     => "Currency"
148
    ];
149
150
    /**
151
     * Modify default field scaffolding in admin
152
     *
153
     * @return FieldList
154
     */
155
    public function getCMSFields()
156
    {
157
        
158
        $this->beforeUpdateCMSFields(function ($fields) {
159
            $config = SiteConfig::current_site_config();
160
161
            $fields->removeByName("Customisation");
162
163
            $fields->addFieldToTab(
164
                "Root.Main",
165
                ReadonlyField::create("Key"),
0 ignored issues
show
Bug introduced by
'Key' of type string is incompatible with the type array expected by parameter $args of SilverStripe\View\ViewableData::create(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

165
                ReadonlyField::create(/** @scrutinizer ignore-type */ "Key"),
Loading history...
166
                "Title"
167
            );
168
169
            $fields->addFieldToTab(
170
                "Root.Main",
171
                DropdownField::create(
172
                    "TaxID",
173
                    $this->fieldLabel("TaxID"),
174
                    $config->TaxRates()->map()
175
                ),
176
                "Weight"
177
            );
178
179
            $fields->addFieldsToTab(
180
                "Root.Description",
181
                array(
182
                    HTMLEditorField::create("Content")
183
                        ->addExtraClass("stacked")
184
                )
185
            );
186
187
            // Change unlink button to remove on customisation
188
            $custom_field = $fields->dataFieldByName("Customisations");
189
190
            if ($custom_field) {
191
                $config = $custom_field->getConfig();
192
                $config
193
                    ->removeComponentsByType(GridFieldDeleteAction::class)
194
                    ->removeComponentsByType(GridFieldDataColumns::class)
195
                    ->removeComponentsByType(GridFieldEditButton::class)
196
                    ->removeComponentsByType(GridFieldAddNewButton::class)
197
                    ->removeComponentsByType(GridFieldAddExistingAutocompleter::class)
198
                    ->addComponents(
199
                        new GridFieldEditableColumns(),
200
                        new GridFieldAddNewInlineButton(),
201
                        new GridFieldEditButton(),
202
                        new GridFieldDeleteAction()
203
                    );
204
                
205
                    $custom_field->setConfig($config);
206
            }
207
        });
208
209
        return parent::getCMSFields();
210
    }
211
212
    /**
213
     * Get the rate of tax for this item
214
     * 
215
     * @return float
216
     */
217
    public function getTaxRate()
218
    {
219
        $rate = ($this->Tax()->exists()) ? $this->Tax()->Rate : 0;
0 ignored issues
show
Bug introduced by
The method Tax() does not exist on SilverCommerce\OrdersAdmin\Model\LineItem. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

219
        $rate = ($this->/** @scrutinizer ignore-call */ Tax()->exists()) ? $this->Tax()->Rate : 0;
Loading history...
220
221
        $this->extend("updateTaxRate", $rate);
222
223
        return $rate;
224
    }
225
    
226
    /**
227
     * Get the price for a single line item (unit), minus any
228
     * tax
229
     * 
230
     * @return float
231
     */
232
    public function getUnitPrice()
233
    {
234
        $total = $this->Price;
0 ignored issues
show
Bug Best Practice introduced by
The property Price does not exist on SilverCommerce\OrdersAdmin\Model\LineItem. Since you implemented __get, consider adding a @property annotation.
Loading history...
235
236
        foreach ($this->Customisations() as $customisation) {
0 ignored issues
show
Bug introduced by
The method Customisations() does not exist on SilverCommerce\OrdersAdmin\Model\LineItem. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

236
        foreach ($this->/** @scrutinizer ignore-call */ Customisations() as $customisation) {
Loading history...
237
            $total += $customisation->Price;
238
        }
239
240
        $this->extend("updateUnitPrice", $total);
241
242
        return $total;
243
    }
244
245
    /**
246
     * Get the amount of tax for a single unit of this item
247
     * 
248
     * @return float
249
     */
250
    public function getUnitTax()
251
    {
252
        $total = ($this->UnitPrice / 100) * $this->TaxRate;
0 ignored issues
show
Bug Best Practice introduced by
The property TaxRate does not exist on SilverCommerce\OrdersAdmin\Model\LineItem. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property UnitPrice does not exist on SilverCommerce\OrdersAdmin\Model\LineItem. Since you implemented __get, consider adding a @property annotation.
Loading history...
253
254
        $this->extend("updateUnitTax", $total);
255
256
        return $total;
257
    }
258
259
    /**
260
     * Get the total price and tax for a single unit
261
     * 
262
     * @return float
263
     */
264
    public function getUnitTotal()
265
    {
266
        $total = $this->UnitPrice + $this->UnitTax;
0 ignored issues
show
Bug Best Practice introduced by
The property UnitTax does not exist on SilverCommerce\OrdersAdmin\Model\LineItem. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property UnitPrice does not exist on SilverCommerce\OrdersAdmin\Model\LineItem. Since you implemented __get, consider adding a @property annotation.
Loading history...
267
268
        $this->extend("updateUnitTotal", $total);
269
270
        return $total;
271
    }
272
273
    /**
274
     * Get the value of this item, minus any tax
275
     * 
276
     * @return float
277
     */
278
    public function getSubTotal()
279
    {
280
        $total = $this->UnitPrice * $this->Quantity;
0 ignored issues
show
Bug Best Practice introduced by
The property Quantity does not exist on SilverCommerce\OrdersAdmin\Model\LineItem. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property UnitPrice does not exist on SilverCommerce\OrdersAdmin\Model\LineItem. Since you implemented __get, consider adding a @property annotation.
Loading history...
281
282
        $this->extend("updateSubTotal", $total);
283
284
        return $total;
285
    }
286
287
    /**
288
     * Get the total amount of tax for a single unit of this item
289
     * 
290
     * @return float
291
     */
292
    public function getTaxTotal()
293
    {
294
        $total = $this->UnitTax * $this->Quantity;
0 ignored issues
show
Bug Best Practice introduced by
The property Quantity does not exist on SilverCommerce\OrdersAdmin\Model\LineItem. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property UnitTax does not exist on SilverCommerce\OrdersAdmin\Model\LineItem. Since you implemented __get, consider adding a @property annotation.
Loading history...
295
296
        $this->extend("updateTaxTotal", $total);
297
298
        return $total;
299
    }
300
301
    /**
302
     * Get the value of this item, minus any tax
303
     * 
304
     * @return float
305
     */
306
    public function getTotal()
307
    {
308
        $total = $this->SubTotal + $this->TaxTotal;
0 ignored issues
show
Bug Best Practice introduced by
The property TaxTotal does not exist on SilverCommerce\OrdersAdmin\Model\LineItem. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property SubTotal does not exist on SilverCommerce\OrdersAdmin\Model\LineItem. Since you implemented __get, consider adding a @property annotation.
Loading history...
309
310
        $this->extend("updateTotal", $total);
311
312
        return $total;
313
    }
314
315
    /**
316
     * Get an image object associated with this line item.
317
     * By default this is retrieved from the base product.
318
     * 
319
     * @return Image | null
0 ignored issues
show
Bug introduced by
The type SilverCommerce\OrdersAdmin\Model\Image was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
320
     */
321
    public function Image()
322
    {
323
        $product = $this->FindStockItem();
324
325
        if ($product && method_exists($product, "SortedImages")) {
326
            return  $product->SortedImages()->first();
327
        } elseif ($product && method_exists($product, "Images")) {
328
            return $product->Images()->first();
329
        } elseif ($product && method_exists($product, "Image") && $product->Image()->exists()) {
330
            return $product->Image();
331
        }
332
    }
333
    
334
    /**
335
     * Provide a string of customisations seperated by a comma but not
336
     * including a price
337
     *
338
     * @return string
339
     */
340
    public function CustomisationList()
341
    {
342
        $return = "";
343
        $items = $this->Customisations();
344
        
345
        if ($items && $items->exists()) {
346
            $map = [];
347
348
            foreach ($items as $item) {
349
                $map[] = $item->Title . ': ' . $item->Value;
350
            }
351
352
            $return = implode(", ", $map);
353
        }
354
355
        $this->extend("updateCustomisationList", $return);
356
        
357
        return $return;
358
    }
359
360
    /**
361
     * Provide a string of customisations seperated by a comma and
362
     * including a price
363
     *
364
     * @return string
365
     */
366
    public function CustomisationAndPriceList()
367
    {
368
        $return = "";
369
        $items = $this->Customisations();
370
        
371
        if ($items && $items->exists()) {
372
            $map = [];
373
374
            foreach ($items as $item) {
375
                $map[] = $item->Title . ': ' . $item->Value . ' (' . $item->dbObject("Price")->Nice() . ')';
376
            }
377
378
            $return = implode(", ", $map);
379
        }
380
381
        $this->extend("updateCustomisationAndPriceList", $return);
382
        
383
        return $return;
384
    }
385
    
386
    /**
387
     * Unserialise the list of customisations and rendering into a basic
388
     * HTML string
389
     *
390
     * @return HTMLText
391
     */
392
    public function CustomisationHTML()
393
    {
394
        $return = HTMLText::create();
395
        $items = $this->Customisations();
396
        $html = "";
397
        
398
        if ($items && $items->exists()) {
399
            foreach ($items as $item) {
400
                $html .= $item->Title . ': ' . $item->Value . ";<br/>";
401
            }
402
        }
403
404
        $return->setValue($html);
405
406
        $this->extend("updateCustomisationHTML", $return);
407
408
        return $return;
409
    }
410
        
411
    /**
412
     * Match this item to another object in the Database, by the
413
     * provided details.
414
     * 
415
     * @param $relation_name = The class name of the related dataobject
416
     * @param $relation_col = The column name of the related object
417
     * @param $match_col = The column we use to match the two objects
418
     * @return DataObject
419
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment = at position 0 could not be parsed: Unknown type name '=' at position 0 in =.
Loading history...
420
    public function Match($relation_name = null, $relation_col = "StockID", $match_col = "StockID")
421
    {
422
        // Try to determine relation name
423
        if (!$relation_name && !$this->ProductClass) {
0 ignored issues
show
Bug Best Practice introduced by
The property ProductClass does not exist on SilverCommerce\OrdersAdmin\Model\LineItem. Since you implemented __get, consider adding a @property annotation.
Loading history...
424
            $relation_name = "Product";
425
        } elseif(!$relation_name && $this->ProductClass) {
426
            $relation_name = $this->ProductClass;
427
        }
428
        
429
        return $relation_name::get()
430
            ->filter($relation_col, $this->$match_col)
431
            ->first();
432
    }
433
434
    /**
435
     * Find our original stock item (useful for adding links back to the
436
     * original product).
437
     * 
438
     * This function is a synonym for @Link Match (as a result of) merging
439
     * LineItem
440
     * 
441
     * @return DataObject
442
     */
443
    public function FindStockItem()
444
    {
445
        return $this->Match();
446
    }
447
448
    /**
449
     * Check stock levels for this item, will return the actual number
450
     * of remaining stock after removing the current quantity
451
     * 
452
     * @param $qty The quantity we want to check against
0 ignored issues
show
Bug introduced by
The type SilverCommerce\OrdersAdmin\Model\The was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
453
     * @return Int
454
     */
455
    public function checkStockLevel($qty)
456
    {
457
        $stock_param = $this->config()->get("stock_param");
458
        $item = $this->Match();
459
        $stock = ($item->$stock_param) ? $item->$stock_param : 0;
460
        $return = $stock - $qty;
461
462
        $this->extend("updateCheckStockLevel", $return);
463
        
464
        return $return;
465
    }
466
467
    /**
468
     * Only order creators or users with VIEW admin rights can view
469
     *
470
     * @return Boolean
471
     */
472
    public function canView($member = null, $context = [])
0 ignored issues
show
Unused Code introduced by
The parameter $context is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

472
    public function canView($member = null, /** @scrutinizer ignore-unused */ $context = [])

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

Loading history...
473
    {
474
        $extended = $this->extend('canView', $member);
475
        if ($extended && $extended !== null) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $extended of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
476
            return $extended;
477
        }
478
479
        return $this->Parent()->canView($member);
0 ignored issues
show
Bug introduced by
The method Parent() does not exist on SilverCommerce\OrdersAdmin\Model\LineItem. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

479
        return $this->/** @scrutinizer ignore-call */ Parent()->canView($member);
Loading history...
480
    }
481
482
    /**
483
     * Anyone can create an order item
484
     *
485
     * @return Boolean
486
     */
487
    public function canCreate($member = null, $context = [])
488
    {
489
        $extended = $this->extend('canCreate', $member);
490
        if ($extended && $extended !== null) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $extended of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
491
            return $extended;
492
        }
493
494
        return true;
495
    }
496
497
    /**
498
     * No one can edit items once they are created
499
     *
500
     * @return Boolean
501
     */
502
    public function canEdit($member = null, $context = [])
0 ignored issues
show
Unused Code introduced by
The parameter $context is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

502
    public function canEdit($member = null, /** @scrutinizer ignore-unused */ $context = [])

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

Loading history...
503
    {
504
        $extended = $this->extend('canEdit', $member);
505
        if ($extended && $extended !== null) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $extended of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
506
            return $extended;
507
        }
508
509
        return $this->Parent()->canEdit($member);
510
    }
511
512
    /**
513
     * No one can delete items once they are created
514
     *
515
     * @return Boolean
516
     */
517
    public function canDelete($member = null, $context = [])
0 ignored issues
show
Unused Code introduced by
The parameter $context is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

517
    public function canDelete($member = null, /** @scrutinizer ignore-unused */ $context = [])

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

Loading history...
518
    {
519
        $extended = $this->extend('canDelete', $member);
520
        if ($extended && $extended !== null) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $extended of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
521
            return $extended;
522
        }
523
524
        return $this->Parent()->canEdit($member);
525
    }
526
527
    /**
528
     * Overwrite default duplicate function
529
     *
530
     * @param boolean $doWrite (write the cloned object to DB)
531
     * @return DataObject $clone The duplicated object
532
     */
533
    public function duplicate($doWrite = true, $manyMany = "many_many")
534
    {
535
        $clone = parent::duplicate($doWrite);
536
537
        // Ensure we clone any customisations
538
        if ($doWrite) {
539
            foreach ($this->Customisations() as $customisation) {
540
                $new_item = $customisation->duplicate(false);
541
                $new_item->ParentID = $clone->ID;
542
                $new_item->write();
543
            }
544
        }
545
546
        return $clone;
547
    }
548
549
    /**
550
     * Pre-write tasks
551
     *
552
     * @return void
553
     */
554
    public function onBeforeWrite()
555
    {
556
        parent::onBeforeWrite();
557
558
        // Generate a unique item key based on 
559
        $this->Key = $this->StockID . ':' . base64_encode(json_encode($this->Customisations()->toArray()));
0 ignored issues
show
Bug Best Practice introduced by
The property Key does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
Bug Best Practice introduced by
The property StockID does not exist on SilverCommerce\OrdersAdmin\Model\LineItem. Since you implemented __get, consider adding a @property annotation.
Loading history...
560
    }
561
562
    /**
563
     * Perform post-DB write functions
564
     *
565
     * @return void
566
     */
567
    public function onAfterWrite()
568
    {
569
        parent::onAfterWrite();
570
571
        if ($this->Customisation) {
572
            $data = unserialize($this->Customisation);
573
574
            if ($data instanceof ArrayList) {
575
                foreach ($data as $data_item) {
576
                    $data_item->ParentID = $this->ID;
577
                    $data_item->write();
578
                }
579
580
                $this->Customisation = null;
0 ignored issues
show
Bug Best Practice introduced by
The property Customisation does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
581
                $this->write();
582
            }
583
        }
584
    }
585
586
    /**
587
     * Clean up DB on deletion
588
     *
589
     * @return void
590
     */
591
    public function onBeforeDelete()
592
    {
593
        parent::onBeforeDelete();
594
595
        foreach ($this->Customisations() as $customisation) {
596
            $customisation->delete();
597
        }
598
    }
599
}
600