Passed
Pull Request — master (#99)
by Nic
02:46
created

Variation::getCMSFields()   B

Complexity

Conditions 3
Paths 1

Size

Total Lines 170
Code Lines 122

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 3
eloc 122
c 3
b 0
f 0
nc 1
nop 0
dl 0
loc 170
rs 8

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Dynamic\Foxy\Model;
4
5
use Bummzack\SortableFile\Forms\SortableUploadField;
6
use SilverStripe\Assets\File;
7
use SilverStripe\Forms\CheckboxField;
8
use SilverStripe\Forms\CurrencyField;
9
use SilverStripe\Forms\DropdownField;
10
use SilverStripe\Forms\FieldGroup;
11
use SilverStripe\Forms\FieldList;
12
use SilverStripe\Forms\NumericField;
13
use SilverStripe\Forms\ReadonlyField;
14
use SilverStripe\Forms\TextField;
15
use SilverStripe\ORM\DataObject;
16
use SilverStripe\ORM\ManyManyList;
17
use SilverStripe\ORM\ValidationResult;
18
19
/**
20
 * Class Variation
21
 * @package Dynamic\Foxy\Model
22
 *
23
 * @property string $Title
24
 * @property bool $UseProductContent
25
 * @property string Content
26
 * @property float $WeightModifier
27
 * @property string $CodeModifier
28
 * @property float $PriceModifier
29
 * @property string $WeightModifierAction
30
 * @property string $CodeModifierAction
31
 * @property string $PriceModifierAction
32
 * @property bool $Available
33
 * @property int $Type
34
 * @property string $OptionModifierKey
35
 * @property int $SortOrder
36
 * @property float $FinalPrice
37
 * @property float $FinalWeight
38
 * @property string $FinalCode
39
 * @property int $VariationTypeID
40
 *
41
 * @method VariationType VariationType()
42
 *
43
 * @method ManyManyList Images()
44
 */
45
class Variation extends DataObject
46
{
47
    /**
48
     * @var string
49
     */
50
    private static $table_name = 'Variation';
51
52
    /**
53
     * @var string
54
     */
55
    private static $singular_name = 'Variation';
56
57
    /**
58
     * @var string
59
     */
60
    private static $plural_name = 'Variations';
61
62
    /**
63
     * @var string[]
64
     */
65
    private static $db = [
66
        'Title' => 'Varchar(255)',
67
        'UseProductContent' => 'Boolean',
68
        'Content' => 'HTMLText',
69
        'WeightModifier' => 'Decimal(9,3)',
70
        'CodeModifier' => 'Text',
71
        'PriceModifier' => 'Currency',
72
        'WeightModifierAction' => "Enum('Add,Subtract,Set', null)",
73
        'CodeModifierAction' => "Enum('Add,Subtract,Set', null)",
74
        'PriceModifierAction' => "Enum('Add,Subtract,Set', null)",
75
        'Available' => 'Boolean',
76
        'Type' => 'Int',
77
        'OptionModifierKey' => 'Varchar(255)',
78
        'SortOrder' => 'Int',
79
        'FinalPrice' => 'Currency',
80
        'FinalWeight' => 'Decimal(9,3)',
81
        'FinalCode' => 'Text',
82
    ];
83
84
    /**
85
     * @var string[]
86
     */
87
    private static $indexes = [
88
        'FinalPrice' => true,
89
        'FinalWeight' => true,
90
        'FinalCode' => true,
91
    ];
92
93
    /**
94
     * @var string[]
95
     */
96
    private static $has_one = [
97
        'VariationType' => VariationType::class,
98
    ];
99
100
    /**
101
     * @var array
102
     */
103
    private static $many_many = [
104
        'Images' => File::class,
105
    ];
106
107
    /**
108
     * @var \string[][]
109
     */
110
    private static $many_many_extraFields = [
111
        'Images' => [
112
            'SortOrder' => 'Int',
113
        ],
114
    ];
115
116
    /**
117
     * @var string[]
118
     */
119
    private static $owns = [
120
        'Images',
121
    ];
122
123
    /**
124
     * The relation name was established before requests for videos.
125
     * The relation has subsequently been updated from Image::class to File::class
126
     * to allow for additional file types such as mp4
127
     *
128
     * @var array
129
     */
130
    private static $allowed_images_extensions = [
131
        'gif',
132
        'jpeg',
133
        'jpg',
134
        'png',
135
        'bmp',
136
        'ico',
137
        'mp4',
138
    ];
139
140
    /**
141
     * @return FieldList
142
     */
143
    public function getCMSFields()
144
    {
145
        $this->beforeUpdateCMSFields(function (FieldList $fields) {
146
            $fields->removeByName([
147
                'Images',
148
                'WeightModifier',
149
                'CodeModifier',
150
                'PriceModifier',
151
                'WeightModifierAction',
152
                'CodeModifierAction',
153
                'PriceModifierAction',
154
                'Available',
155
                'Type',
156
                'OptionModifierKey',
157
                'SortOrder',
158
                'ProductID',
159
                'FinalPrice',
160
                'FinalWeight',
161
                'FinalCode',
162
            ]);
163
164
            $fields->insertBefore(
165
                'Content',
166
                CheckboxField::create('Available')
167
                    ->setTitle('Available for purchase')
168
            );
169
170
            $fields->insertBefore(
171
                'Content',
172
                $fields->dataFieldByName('VariationTypeID')
173
            );
174
175
            $fields->insertBefore(
176
                'Content',
177
                $fields->dataFieldByName('UseProductContent')
178
            );
179
180
            $content = $fields->dataFieldByName('Content');
181
182
            $content->hideUnless('UseProductContent')->isNotChecked()->end();
183
184
            if ($this->exists()) {
185
                $fields->addFieldToTab(
186
                    'Root.ProductModifications',
187
                    ReadonlyField::create('OptionModifierKey')
188
                        ->setTitle(_t('Variation.ModifierKey', 'Modifier Key'))
189
                );
190
            }
191
192
            if ($this->Product()->hasDatabaseField('Weight')) {
0 ignored issues
show
Bug introduced by
The method Product() does not exist on Dynamic\Foxy\Model\Variation. 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

192
            if ($this->/** @scrutinizer ignore-call */ Product()->hasDatabaseField('Weight')) {
Loading history...
193
                $fields->addFieldtoTab(
194
                    'Root.ProductModifications',
195
                    FieldGroup::create(
196
                        DropdownField::create(
197
                            'WeightModifierAction',
198
                            _t('Variation.WeightModifierAction', 'Weight Modification Type'),
199
                            [
200
                                'Add' => _t(
201
                                    'Variation.WeightAdd',
202
                                    'Add to Base Weight',
203
                                    'Add to weight'
204
                                ),
205
                                'Subtract' => _t(
206
                                    'Variation.WeightSubtract',
207
                                    'Subtract from Base Weight',
208
                                    'Subtract from weight'
209
                                ),
210
                                'Set' => _t('Variation.WeightSet', 'Set as a new Weight'),
211
                            ]
212
                        )
213
                            ->setEmptyString('')
214
                            ->setDescription(_t(
215
                                'Variation.WeightDescription',
216
                                'Does weight modify or replace base weight?'
217
                            )),
218
                        NumericField::create("WeightModifier")
219
                            ->setTitle(_t('Variation.WeightModifier', 'Weight'))
220
                            ->setScale(3)
221
                            ->setDescription(_t(
222
                                'Variation.WeightDescription',
223
                                'Only supports up to 3 decimal places'
224
                            ))->displayIf('WeightModifierAction')->isNotEmpty()->end(),
225
                        NumericField::create('FinalWeight')
226
                            ->setTitle('Final Modified Weight')
227
                            ->setDescription("Product's weight is {$this->Product()->Weight}")
228
                            ->performDisabledTransformation()
229
                    )->setTitle('Weight Modification')
230
                );
231
            }
232
233
            $fields->addFieldsToTab(
234
                'Root.ProductModifications',
235
                [
236
                    // Price Modifier Fields
237
                    //HeaderField::create('PriceHD', _t('Variation.PriceHD', 'Modify Price'), 4),
238
                    FieldGroup::create(
239
                        DropdownField::create(
240
                            'PriceModifierAction',
241
                            _t('Variation.PriceModifierAction', 'Price Modification Type'),
242
                            [
243
                                'Add' => _t(
244
                                    'Variation.PriceAdd',
245
                                    'Add to Base Price',
246
                                    'Add to price'
247
                                ),
248
                                'Subtract' => _t(
249
                                    'Variation.PriceSubtract',
250
                                    'Subtract from Base Price',
251
                                    'Subtract from price'
252
                                ),
253
                                'Set' => _t('Variation.PriceSet', 'Set as a new Price'),
254
                            ]
255
                        )
256
                            ->setEmptyString('')
257
                            ->setDescription(_t('Variation.PriceDescription', 'Does price modify or replace base price?')),
258
                        CurrencyField::create('PriceModifier')
259
                            ->setTitle(_t('Variation.PriceModifier', 'Price'))
260
                            ->displayIf('PriceModifierAction')->isNotEmpty()->end(),
261
                        CurrencyField::create('FinalPrice')
262
                            ->setTitle('Final Modified Price')
263
                            ->setDescription("Product's price is {$this->Product()->Price}")
264
                            ->performDisabledTransformation()
265
                    )->setTitle('Price Modifications'),
266
267
                    // Code Modifier Fields
268
                    //HeaderField::create('CodeHD', _t('Variation.CodeHD', 'Modify Code'), 4),
269
                    FieldGroup::create(
270
                        DropdownField::create(
271
                            'CodeModifierAction',
272
                            _t('Variation.CodeModifierAction', 'Code Modification Type'),
273
                            [
274
                                'Add' => _t(
275
                                    'Variation.CodeAdd',
276
                                    'Add to Base Code',
277
                                    'Add to code'
278
                                ),
279
                                'Subtract' => _t(
280
                                    'Variation.CodeSubtract',
281
                                    'Subtract from Base Code',
282
                                    'Subtract from code'
283
                                ),
284
                                'Set' => _t('Variation.CodeSet', 'Set as a new Code'),
285
                            ]
286
                        )
287
                            ->setEmptyString('')
288
                            ->setDescription(_t('Variation.CodeDescription', 'Does code modify or replace base code?')),
289
                        TextField::create('CodeModifier')
290
                            ->setTitle(_t('Variation.CodeModifier', 'Code'))
291
                            ->displayIf('CodeModifierAction')->isNotEmpty()->end(),
292
                        TextField::create('FinalCode')
293
                            ->setTitle('Final Modified Code')
294
                            ->setDescription("Product's code is {$this->Product()->Code}")
295
                            ->performDisabledTransformation()
296
                    )->setTitle('Code Modification'),
297
                ]
298
            );
299
300
            // Images tab
301
            $images = SortableUploadField::create('Images')
302
                ->setSortColumn('SortOrder')
303
                ->setIsMultiUpload(true)
304
                ->setAllowedExtensions($this->config()->get('allowed_images_extensions'))
305
                ->setFolderName('Uploads/Products/Images');
306
307
            $fields->addFieldsToTab('Root.Images', [
308
                $images,
309
            ]);
310
        });
311
312
        return parent::getCMSFields();
313
    }
314
315
    /**
316
     *
317
     */
318
    public function onBeforeWrite()
319
    {
320
        parent::onBeforeWrite();
321
322
        $modifierKeyField = 'OptionModifierKey';
323
        $this->{$modifierKeyField} = $this->getGeneratedValue();
324
325
        $codeModifierField = 'CodeModifier';
326
        switch ($this->CodeModifierAction) {
327
            case 'Subtract':
328
            case 'Add':
329
                if ($this->config()->get('trimAllWhitespace') == false) {
330
                    // trim the right of the code - some companies use spaces to denote options
331
                    $trimmed = rtrim($this->{$codeModifierField});
332
                    // replace duplicate spaces
333
                    $this->{$codeModifierField} = preg_replace('/\s+/', ' ', $trimmed);
334
                    break;
335
                }
336
            /* falls through */
337
            case 'Set':
338
                $trimmed = trim($this->{$codeModifierField});
339
                $this->{$codeModifierField} = preg_replace('/\s+/', ' ', $trimmed);
340
                break;
341
        }
342
343
        $this->FinalPrice = $this->calculateFinalPrice();
344
        $this->FinalCode = $this->calculateFinalCode();
345
346
        if ($this->Product()->hasDatabaseField('Weight')) {
347
            $this->FinalWeight = $this->calculateFinalWeight();
348
        }
349
    }
350
351
    /**
352
     * @return ValidationResult
353
     */
354
    public function validate()
355
    {
356
        $validate = parent::validate();
357
        $product = $this->Product();
358
359
        if (!$this->Title) {
360
            $validate->addFieldError('Title', 'A title is required');
361
        }
362
363
        if (!$this->VariationTypeID) {
364
            $validate->addFieldError('VariationTypeID', 'A variation type is required');
365
        }
366
367
        if ($this->PriceModifierAction == 'Subtract' && $this->PriceModifier > $product->Price) {
368
            $validate->addFieldError('PriceModifier', "You can't subtract more than the price of the product ({$product->Price})");
369
        }
370
371
        if ($this->WeightModifierAction == 'Subtract' && $this->WeightModifier > $product->Weight) {
372
            $validate->addFieldError('WeightModifier', "You can't subtract more than the weight of the product ({$product->Weight})");
373
        }
374
375
        return $validate;
376
    }
377
378
    /**
379
     * @return string
380
     */
381
    public function getGeneratedValue()
382
    {
383
        $modPrice = ($this->PriceModifier) ? (string)$this->PriceModifier : '0';
384
        $modPriceWithSymbol = self::getOptionModifierActionSymbol($this->PriceModifierAction) . $modPrice;
385
        $modWeight = ($this->WeightModifier) ? (string)$this->WeightModifier : '0';
386
        $modWeight = self::getOptionModifierActionSymbol($this->WeightModifierAction) . $modWeight;
387
        $modCode = self::getOptionModifierActionSymbol($this->CodeModifierAction) . $this->CodeModifier;
388
389
        return $this->Title . '{p' . $modPriceWithSymbol . '|w' . $modWeight . '|c' . $modCode . '}';
390
    }
391
392
    /**
393
     * @param $oma
394
     * @param bool $returnWithOnlyPlusMinus
395
     *
396
     * @return string
397
     */
398
    public static function getOptionModifierActionSymbol($oma, $returnWithOnlyPlusMinus = false)
399
    {
400
        switch ($oma) {
401
            case 'Subtract':
402
                $symbol = '-';
403
                break;
404
            case 'Set':
405
                $symbol = ($returnWithOnlyPlusMinus) ? '' : ':';
406
                break;
407
            default:
408
                $symbol = '+';
409
        }
410
411
        return $symbol;
412
    }
413
414
    /**
415
     * @return string
416
     */
417
    protected function getWeightModifierWithSymbol()
418
    {
419
        return $this->getOptionModifierActionSymbol($this->WeightModifierAction) . $this->WeightModifier;
420
    }
421
422
    /**
423
     * @return string
424
     */
425
    protected function getPriceModifierWithSymbol()
426
    {
427
        return $this->getOptionModifierActionSymbol($this->PriceModifierAction) . $this->PriceModifier;
428
    }
429
430
    /**
431
     * @return string
432
     */
433
    protected function getCodeModifierWithSymbol()
434
    {
435
        return $this->getOptionModifierActionSymbol($this->CodeModifierAction) . $this->CodeModifier;
436
    }
437
438
    /**
439
     * @return float
440
     */
441
    protected function calculateFinalPrice()
442
    {
443
        $product = $this->Product();// this relation is set by a developer's data extension
444
445
        if ($this->PriceModifierAction == 'Add') {
446
            return $this->PriceModifier + $product->Price;
447
        } elseif ($this->PriceModifierAction == 'Subtract') {
448
            return $product->Price - $this->PriceModifier;
449
        } elseif ($this->PriceModifierAction == 'Set') {
450
            return $this->PriceModifier;
451
        }
452
453
        return $product->Price;
454
    }
455
456
    /**
457
     * @return float
458
     */
459
    protected function calculateFinalWeight()
460
    {
461
        $product = $this->Product();// this relation is set by a developer's data extension
462
463
        if ($this->WeightModifierAction == 'Add') {
464
            return $this->WeightModifier + $product->Weight;
465
        } elseif ($this->WeightModifierAction == 'Subtract') {
466
            return $product->Weight - $this->WeightModifier;
467
        } elseif ($this->WeightModifierAction == 'Set') {
468
            return $this->WeightModifier;
469
        }
470
471
        return $product->Weight;
472
    }
473
474
    /**
475
     * @return string
476
     */
477
    protected function calculateFinalCode()
478
    {
479
        $product = $this->Product();// this relation is set by a developer's data extension
480
481
        if ($this->CodeModifierAction == 'Add') {
482
            return "{$product->Code}{$this->CodeModifier}";
483
        } elseif ($this->CodeModifierAction == 'Subtract') {
484
            return rtrim($product->Code, $this->CodeModifier);
485
        } elseif ($this->CodeModifierAction == 'Set') {
486
            return $this->CodeModifier;
487
        }
488
489
        return $product->Code;
490
    }
491
}
492