Passed
Push — master ( 38d31e...10c38a )
by Jason
03:20
created

ProductPage   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 395
Duplicated Lines 0 %

Test Coverage

Coverage 14.19%

Importance

Changes 0
Metric Value
wmc 29
eloc 185
dl 0
loc 395
rs 10
c 0
b 0
f 0
ccs 21
cts 148
cp 0.1419

14 Methods

Rating   Name   Duplication   Size   Complexity  
A canDelete() 0 3 1
A getCartScript() 0 4 1
A getCMSValidator() 0 3 1
A canCreate() 0 3 1
A canEdit() 0 3 1
A providePermissions() 0 4 1
A onAfterWrite() 0 3 1
A onBeforeDelete() 0 18 6
A validate() 0 17 1
B getCMSFields() 0 126 4
A canPublish() 0 3 1
A fieldLabels() 0 13 1
A onBeforeWrite() 0 29 6
A getGeneratedValue() 0 13 3
1
<?php
2
3
namespace Dynamic\FoxyStripe\Page;
4
5
use Dynamic\FoxyStripe\Model\FoxyCart;
6
use Dynamic\FoxyStripe\Model\FoxyStripeSetting;
7
use Dynamic\FoxyStripe\Model\OptionItem;
8
use Dynamic\FoxyStripe\Model\OrderDetail;
9
use Dynamic\FoxyStripe\Model\ProductCategory;
10
use Dynamic\FoxyStripe\Model\ProductImage;
11
use SilverStripe\AssetAdmin\Forms\UploadField;
12
use SilverStripe\Assets\Image;
13
use SilverStripe\Forms\CheckboxField;
14
use SilverStripe\Forms\CurrencyField;
15
use SilverStripe\Forms\DropdownField;
16
use SilverStripe\Forms\GridField\GridField;
17
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;
18
use SilverStripe\Forms\HeaderField;
19
use SilverStripe\Forms\LiteralField;
20
use SilverStripe\Forms\NumericField;
21
use SilverStripe\Forms\RequiredFields;
22
use SilverStripe\Forms\TextField;
23
use SilverStripe\Security\Permission;
24
use SilverStripe\Security\PermissionProvider;
25
use SilverStripe\SiteConfig\SiteConfig;
26
use Symbiote\GridFieldExtensions\GridFieldOrderableRows;
27
28
/**
29
 * Class ProductPage
30
 * @package Dynamic\FoxyStripe\Page
31
 *
32
 * @property \SilverStripe\ORM\FieldType\DBCurrency Price
33
 * @property \SilverStripe\ORM\FieldType\DBDecimal Weight
34
 * @property \SilverStripe\ORM\FieldType\DBVarchar Code
35
 * @property \SilverStripe\ORM\FieldType\DBVarchar ReceiptTitle
36
 * @property \SilverStripe\ORM\FieldType\DBBoolean Featured
37
 * @property \SilverStripe\ORM\FieldType\DBBoolean Available
38
 *
39
 * @property int PreviewImageID
40
 * @method Image PreviewImage
41
 * @property int CategoryID
42
 * @method ProductCategory Category
43
 *
44
 *
45
 * @method \SilverStripe\ORM\HasManyList ProductImages
46
 * @method \SilverStripe\ORM\HasManyList ProductOptions
47
 * @method \SilverStripe\ORM\HasManyList OrderDetails
48
 *
49
 * @method \SilverStripe\ORM\ManyManyList ProductHolders
50
 */
51
class ProductPage extends \Page implements PermissionProvider
52
{
53
    /**
54
     * @var string
55
     */
56
    //private static $allowed_children = [];
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
57
58
    /**
59
     * @var string
60
     */
61
    private static $default_parent = ProductHolder::class;
0 ignored issues
show
introduced by
The private property $default_parent is not used, and could be removed.
Loading history...
62
63
    /**
64
     * @var bool
65
     */
66
    private static $can_be_root = false;
0 ignored issues
show
introduced by
The private property $can_be_root is not used, and could be removed.
Loading history...
67
68
    /**
69
     * @var array
70
     */
71
    private static $db = array(
0 ignored issues
show
introduced by
The private property $db is not used, and could be removed.
Loading history...
72
        'Price' => 'Currency',
73
        'Weight' => 'Decimal',
74
        'Code' => 'Varchar(100)',
75
        'ReceiptTitle' => 'HTMLVarchar(255)',
76
        'Featured' => 'Boolean',
77
        'Available' => 'Boolean',
78
    );
79
80
    /**
81
     * @var array
82
     */
83
    private static $has_one = array(
0 ignored issues
show
introduced by
The private property $has_one is not used, and could be removed.
Loading history...
84
        'PreviewImage' => Image::class,
85
        'Category' => ProductCategory::class,
86
    );
87
88
    /**
89
     * @var array
90
     */
91
    private static $has_many = array(
0 ignored issues
show
introduced by
The private property $has_many is not used, and could be removed.
Loading history...
92
        'ProductImages' => ProductImage::class,
93
        'ProductOptions' => OptionItem::class,
94
        'OrderDetails' => OrderDetail::class,
95
    );
96
97
    /**
98
     * @var array
99
     */
100
    private static $belongs_many_many = array(
0 ignored issues
show
introduced by
The private property $belongs_many_many is not used, and could be removed.
Loading history...
101
        'ProductHolders' => ProductHolder::class,
102
    );
103
104
    /**
105
     * @var string
106
     */
107
    private static $singular_name = 'Product';
0 ignored issues
show
introduced by
The private property $singular_name is not used, and could be removed.
Loading history...
108
109
    /**
110
     * @var string
111
     */
112
    private static $plural_name = 'Products';
0 ignored issues
show
introduced by
The private property $plural_name is not used, and could be removed.
Loading history...
113
114
    /**
115
     * @var string
116
     */
117
    private static $description = 'A product that can be added to the shopping cart';
0 ignored issues
show
introduced by
The private property $description is not used, and could be removed.
Loading history...
118
119
    /**
120
     * @var array
121
     */
122
    private static $indexes = array(
0 ignored issues
show
introduced by
The private property $indexes is not used, and could be removed.
Loading history...
123
        'Code' => true, // make unique
124
    );
125
126
    /**
127
     * @var array
128
     */
129
    private static $defaults = array(
0 ignored issues
show
introduced by
The private property $defaults is not used, and could be removed.
Loading history...
130
        'ShowInMenus' => false,
131
        'Available' => true,
132
        'Weight' => '1.0',
133
    );
134
135
    /**
136
     * @var array
137
     */
138
    private static $summary_fields = array(
0 ignored issues
show
introduced by
The private property $summary_fields is not used, and could be removed.
Loading history...
139
        'Title',
140
        'Code',
141
        'Price.Nice',
142
        'Category.Title',
143
    );
144
145
    /**
146
     * @var array
147
     */
148
    private static $searchable_fields = array(
0 ignored issues
show
introduced by
The private property $searchable_fields is not used, and could be removed.
Loading history...
149
        'Title',
150
        'Code',
151
        'Featured',
152
        'Available',
153
        'Category.ID',
154
    );
155
156
    /**
157
     * @var string
158
     */
159
    private static $table_name = 'FS_ProductPage';
0 ignored issues
show
introduced by
The private property $table_name is not used, and could be removed.
Loading history...
160
161
    /**
162
     * @param bool $includerelations
163
     *
164
     * @return array
165
     */
166
    public function fieldLabels($includerelations = true)
167
    {
168
        $labels = parent::fieldLabels();
169
170
        $labels['Title'] = _t('ProductPage.TitleLabel', 'Name');
171
        $labels['Code'] = _t('ProductPage.CodeLabel', 'Code');
172
        $labels['Price.Nice'] = _t('ProductPage.PriceLabel', 'Price');
173
        $labels['Featured.Nice'] = _t('ProductPage.NiceLabel', 'Featured');
174
        $labels['Available.Nice'] = _t('ProductPage.AvailableLabel', 'Available');
175
        $labels['Category.ID'] = _t('ProductPage.IDLabel', 'Category');
176
        $labels['Category.Title'] = _t('ProductPage.CategoryTitleLabel', 'Category');
177
178
        return $labels;
179
    }
180
181
    /**
182
     * @return \SilverStripe\Forms\FieldList
183
     */
184
    public function getCMSFields()
185
    {
186
        $fields = parent::getCMSFields();
187
188
        // allow extensions of ProductPage to override the PreviewImage field description
189
        $previewDescription = ($this->stat('customPreviewDescription')) ? $this->stat('customPreviewDescription') : _t(
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\View\ViewableData::stat() has been deprecated: 5.0 Use ->config()->get() instead ( Ignorable by Annotation )

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

189
        $previewDescription = ($this->stat('customPreviewDescription')) ? /** @scrutinizer ignore-deprecated */ $this->stat('customPreviewDescription') : _t(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
190
            'ProductPage.PreviewImageDescription',
191
            'Image used throughout site to represent this product'
192
        );
193
194
        // Cateogry Dropdown field w/ add new
195
        $source = function () {
196
            return ProductCategory::get()->map()->toArray();
197
        };
198
        $catField = DropdownField::create('CategoryID', _t('ProductPage.Category', 'FoxyCart Category'), $source())
199
            ->setEmptyString('')
200
            ->setDescription(_t(
201
                'ProductPage.CategoryDescription',
202
                'Required, must also exist in 
203
                    <a href="https://admin.foxycart.com/admin.php?ThisAction=ManageProductCategories" target="_blank">
204
                        FoxyCart Categories
205
                    </a>.
206
                    Used to set category specific options like shipping and taxes. Managed in
207
                        <a href="admin/settings">
208
                            Settings > FoxyStripe > Categories
209
                        </a>'
210
            ));
211
        if (class_exists('QuickAddNewExtension')) {
212
            $catField->useAddNew('ProductCategory', $source);
213
        }
214
215
        // Product Images gridfield
216
        $config = GridFieldConfig_RelationEditor::create();
217
        $config->addComponent(new GridFieldOrderableRows('SortOrder'));
218
        $prodImagesField = GridField::create(
219
            'ProductImages',
220
            _t('ProductPage.ProductImages', 'Images'),
221
            $this->ProductImages(),
222
            $config
223
        );
224
225
        // Product Options field
226
        $config = GridFieldConfig_RelationEditor::create();
227
        $config->addComponent(new GridFieldOrderableRows('SortOrder'));
228
        $products = $this->ProductOptions()->sort('SortOrder');
229
        $config->removeComponentsByType('GridFieldAddExistingAutocompleter');
230
        $prodOptField = GridField::create(
231
            'ProductOptions',
232
            _t('ProductPage.ProductOptions', 'Options'),
233
            $products,
234
            $config
235
        );
236
237
        // Details tab
238
        $fields->addFieldsToTab('Root.Details', array(
239
            HeaderField::create('DetailHD', 'Product Details', 2),
240
            CheckboxField::create('Available')
241
                ->setTitle(_t('ProductPage.Available', 'Available for purchase'))
242
                ->setDescription(_t(
243
                    'ProductPage.AvailableDescription',
244
                    'If unchecked, will remove "Add to Cart" form and instead display "Currently unavailable"'
245
                )),
246
            TextField::create('Code')
247
                ->setTitle(_t('ProductPage.Code', 'Product Code'))
248
                ->setDescription(_t(
249
                    'ProductPage.CodeDescription',
250
                    'Required, must be unique. Product identifier used by FoxyCart in transactions'
251
                )),
252
            $catField,
253
            CurrencyField::create('Price')
254
                ->setTitle(_t('ProductPage.Price', 'Price'))
255
                ->setDescription(_t(
256
                    'ProductPage.PriceDescription',
257
                    'Base price for this product. Can be modified using Product Options'
258
                )),
259
            NumericField::create('Weight')
260
                ->setTitle(_t('ProductPage.Weight', 'Weight'))
261
                ->setDescription(_t(
262
                    'ProductPage.WeightDescription',
263
                    'Base weight for this product in lbs. Can be modified using Product Options'
264
                )),
265
            CheckboxField::create('Featured')
266
                ->setTitle(_t('ProductPage.Featured', 'Featured Product')),
267
            TextField::create('ReceiptTitle')
268
                ->setTitle(_t('ProductPage.ReceiptTitle', 'Product Title for Receipt'))
269
                ->setDescription(_t(
270
                    'ProductPage.ReceiptTitleDescription',
271
                    'Optional'
272
                )),
273
        ));
274
275
        // Images tab
276
        $fields->addFieldsToTab('Root.Images', array(
277
            HeaderField::create('MainImageHD', _t('ProductPage.MainImageHD', 'Product Image'), 2),
278
            UploadField::create('PreviewImage', '')
279
                ->setDescription($previewDescription)
280
                ->setFolderName('Uploads/Products')
281
                ->setAllowedExtensions(array('jpg', 'jpeg', 'gif', 'png')),
282
            HeaderField::create('ProductImagesHD', _t('ProductPage.ProductImagesHD', 'Product Image Gallery'), 2),
283
            $prodImagesField
284
                ->setDescription(_t(
285
                    'ProductPage.ProductImagesDescription',
286
                    'Additional Product Images, shown in gallery on Product page'
287
                )),
288
        ));
289
290
        // Options Tab
291
        $fields->addFieldsToTab('Root.Options', array(
292
            HeaderField::create('OptionsHD', _t('ProductPage.OptionsHD', 'Product Options'), 2),
293
            LiteralField::create('OptionsDescrip', _t(
294
                'Page.OptionsDescrip',
295
                '<p>Product Options allow products to be customized by attributes such as size or color.
296
                    Options can also modify the product\'s price, weight or code.</p>'
297
            )),
298
            $prodOptField,
299
        ));
300
301
        if (FoxyCart::store_name_warning() !== null) {
302
            $fields->addFieldToTab('Root.Main', LiteralField::create('StoreSubDomainHeaderWarning', _t(
303
                'ProductPage.StoreSubDomainHeaderWarning',
304
                '<p class="message error">Store sub-domain must be entered in the 
305
                        <a href="/admin/settings/">site settings</a></p>'
306
            )), 'Title');
307
        }
308
309
        return $fields;
310
    }
311
312
    /**
313
     * @throws \SilverStripe\ORM\ValidationException
314
     */
315 13
    public function onBeforeWrite()
316
    {
317 13
        parent::onBeforeWrite();
318 13
        if (!$this->CategoryID) {
319
            $default = ProductCategory::get()->filter(array('Code' => 'DEFAULT'))->first();
320
            $this->CategoryID = $default->ID;
321
        }
322
323
        //update many_many lists when multi-group is on
324 13
        if (FoxyStripeSetting::current_foxystripe_setting()->MultiGroup) {
0 ignored issues
show
Bug Best Practice introduced by
The property MultiGroup does not exist on Dynamic\FoxyStripe\Model\FoxyStripeSetting. Since you implemented __get, consider adding a @property annotation.
Loading history...
325
            $holders = $this->ProductHolders();
326
            $product = self::get()->byID($this->ID);
327
            if (isset($product->ParentID)) {
328
                $origParent = $product->ParentID;
329
            } else {
330
                $origParent = null;
331
            }
332
            $currentParent = $this->ParentID;
333
            if ($origParent != $currentParent) {
334
                if ($holders->find('ID', $origParent)) {
335
                    $holders->removeByID($origParent);
336
                }
337
            }
338
            $holders->add($currentParent);
339
        }
340
341 13
        $title = ltrim($this->Title);
342 13
        $title = rtrim($title);
343 13
        $this->Title = $title;
344
    }
345
346 13
    public function onAfterWrite()
347
    {
348 13
        parent::onAfterWrite();
349
    }
350
351 2
    public function onBeforeDelete()
352
    {
353 2
        if ($this->Status != 'Published') {
0 ignored issues
show
Bug Best Practice introduced by
The property Status does not exist on Dynamic\FoxyStripe\Page\ProductPage. Since you implemented __get, consider adding a @property annotation.
Loading history...
354 2
            if ($this->ProductOptions()) {
355 2
                $options = $this->getComponents('ProductOptions');
356 2
                foreach ($options as $option) {
357
                    $option->delete();
358
                }
359
            }
360 2
            if ($this->ProductImages()) {
361
                //delete product image dataobjects, not the images themselves.
362 2
                $images = $this->getComponents('ProductImages');
363 2
                foreach ($images as $image) {
364
                    $image->delete();
365
                }
366
            }
367
        }
368 2
        parent::onBeforeDelete();
369
    }
370
371 5
    public function validate()
372
    {
373 5
        $result = parent::validate();
374
375
        /*if($this->ID>0){
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
376
            if($this->Price <= 0) {
377
                $result->error('Must set a positive price value');
378
            }
379
            if($this->Weight <= 0){
380
                $result->error('Must set a positive weight value');
381
            }
382
            if($this->Code == ''){
383
                $result->error('Must set a product code');
384
            }
385
        }*/
386
387 5
        return $result;
388
    }
389
390
    public function getCMSValidator()
391
    {
392
        return new RequiredFields(array('CategoryID', 'Price', 'Weight', 'Code'));
393
    }
394
395
    public static function getGeneratedValue(
396
        $productCode = null,
397
        $optionName = null,
398
        $optionValue = null,
399
        $method = 'name',
400
        $output = false,
401
        $urlEncode = false
402
    ) {
403
        $optionName = ($optionName !== null) ? preg_replace('/\s/', '_', $optionName) : $optionName;
404
405
        return (FoxyStripeSetting::current_foxystripe_setting()->CartValidation)
0 ignored issues
show
Bug Best Practice introduced by
The property CartValidation does not exist on Dynamic\FoxyStripe\Model\FoxyStripeSetting. Since you implemented __get, consider adding a @property annotation.
Loading history...
406
            ? \FoxyCart_Helper::fc_hash_value($productCode, $optionName, $optionValue, $method, $output, $urlEncode) :
407
            $optionValue;
408
    }
409
410
    // get FoxyCart Store Name for JS call
411
    public function getCartScript()
412
    {
413
        $store = FoxyCart::getFoxyCartStoreName();
414
        return '<script src="https://cdn.foxycart.com/'.$store.'/loader.js" async defer></script>';
415
    }
416
417
    /**
418
     * @param Member $member
0 ignored issues
show
Bug introduced by
The type Dynamic\FoxyStripe\Page\Member 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...
419
     *
420
     * @return bool
421
     */
422
    public function canEdit($member = null)
423
    {
424
        return Permission::check('Product_CANCRUD', 'any', $member);
425
    }
426
427
    public function canDelete($member = null)
428
    {
429
        return Permission::check('Product_CANCRUD', 'any', $member);
430
    }
431
432
    public function canCreate($member = null, $context = [])
433
    {
434
        return Permission::check('Product_CANCRUD', 'any', $member);
435
    }
436
437
    public function canPublish($member = null)
438
    {
439
        return Permission::check('Product_CANCRUD', 'any', $member);
440
    }
441
442
    public function providePermissions()
443
    {
444
        return array(
445
            'Product_CANCRUD' => 'Allow user to manage Products and related objects',
446
        );
447
    }
448
}
449