Completed
Push — master ( f8f77e...d2a4ab )
by Jason
05:01
created

ProductPage   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 392
Duplicated Lines 0 %

Test Coverage

Coverage 15.54%

Importance

Changes 0
Metric Value
wmc 29
c 0
b 0
f 0
dl 0
loc 392
ccs 23
cts 148
cp 0.1554
rs 10

14 Methods

Rating   Name   Duplication   Size   Complexity  
A fieldLabels() 0 13 1
A canDelete() 0 3 1
B onBeforeDelete() 0 18 6
A getCartScript() 0 4 1
A validate() 0 17 1
B getCMSFields() 0 126 4
A canPublish() 0 3 1
A getCMSValidator() 0 3 1
A canCreate() 0 3 1
B onBeforeWrite() 0 29 6
A canEdit() 0 3 1
A getGeneratedValue() 0 13 3
A providePermissions() 0 4 1
A onAfterWrite() 0 3 1
1
<?php
2
3
namespace Dynamic\FoxyStripe\Page;
4
5
use Dynamic\FoxyStripe\Model\FoxyCart;
6
use Dynamic\FoxyStripe\Model\OptionItem;
7
use Dynamic\FoxyStripe\Model\OrderDetail;
8
use Dynamic\FoxyStripe\Model\ProductCategory;
9
use Dynamic\FoxyStripe\Model\ProductImage;
10
use SilverStripe\AssetAdmin\Forms\UploadField;
11
use SilverStripe\Assets\Image;
12
use SilverStripe\Forms\CheckboxField;
13
use SilverStripe\Forms\CurrencyField;
14
use SilverStripe\Forms\DropdownField;
15
use SilverStripe\Forms\GridField\GridField;
16
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;
17
use SilverStripe\Forms\HeaderField;
18
use SilverStripe\Forms\LiteralField;
19
use SilverStripe\Forms\NumericField;
20
use SilverStripe\Forms\RequiredFields;
21
use SilverStripe\Forms\TextField;
22
use SilverStripe\Security\Permission;
23
use SilverStripe\Security\PermissionProvider;
24
use SilverStripe\SiteConfig\SiteConfig;
25
use Symbiote\GridFieldExtensions\GridFieldOrderableRows;
26
27
class ProductPage extends \Page implements PermissionProvider
28
{
29
    /**
30
     * @var string
31
     */
32
    //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...
33
34
    /**
35
     * @var string
36
     */
37
    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...
38
39
    /**
40
     * @var bool
41
     */
42
    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...
43
44
    /**
45
     * @var array
46
     */
47
    private static $db = array(
0 ignored issues
show
introduced by
The private property $db is not used, and could be removed.
Loading history...
48
        'Price' => 'Currency',
49
        'Weight' => 'Decimal',
50
        'Code' => 'Varchar(100)',
51
        'ReceiptTitle' => 'HTMLVarchar(255)',
52
        'Featured' => 'Boolean',
53
        'Available' => 'Boolean',
54
    );
55
56
    /**
57
     * @var array
58
     */
59
    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...
60
        'PreviewImage' => Image::class,
61
        'Category' => ProductCategory::class,
62
    );
63
64
    /**
65
     * @var array
66
     */
67
    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...
68
        'ProductImages' => ProductImage::class,
69
        'ProductOptions' => OptionItem::class,
70
        'OrderDetails' => OrderDetail::class,
71
    );
72
73
    /**
74
     * @var array
75
     */
76
    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...
77
        'ProductHolders' => ProductHolder::class,
78
    );
79
80
    /**
81
     * @var string
82
     */
83
    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...
84
85
    /**
86
     * @var string
87
     */
88
    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...
89
90
    /**
91
     * @var string
92
     */
93
    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...
94
95
    /**
96
     * @var array
97
     */
98
    private static $indexes = array(
0 ignored issues
show
introduced by
The private property $indexes is not used, and could be removed.
Loading history...
99
        'Code' => true, // make unique
100
    );
101
102
    /**
103
     * @var array
104
     */
105
    private static $defaults = array(
0 ignored issues
show
introduced by
The private property $defaults is not used, and could be removed.
Loading history...
106
        'ShowInMenus' => false,
107
        'Available' => true,
108
        'Weight' => '1.0',
109
    );
110
111
    /**
112
     * @var array
113
     */
114
    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...
115
        'Title',
116
        'Code',
117
        'Price.Nice',
118
        'Category.Title',
119
    );
120
121
    /**
122
     * @var array
123
     */
124
    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...
125
        'Title',
126
        'Code',
127
        'Featured',
128
        'Available',
129
        'Category.ID',
130
    );
131
132
    /**
133
     * @var string
134
     */
135
    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...
136
137
    /**
138
     * @param bool $includerelations
139
     *
140
     * @return array
141
     */
142
    public function fieldLabels($includerelations = true)
143
    {
144
        $labels = parent::fieldLabels();
145
146
        $labels['Title'] = _t('ProductPage.TitleLabel', 'Name');
147
        $labels['Code'] = _t('ProductPage.CodeLabel', 'Code');
148
        $labels['Price.Nice'] = _t('ProductPage.PriceLabel', 'Price');
149
        $labels['Featured.Nice'] = _t('ProductPage.NiceLabel', 'Featured');
150
        $labels['Available.Nice'] = _t('ProductPage.AvailableLabel', 'Available');
151
        $labels['Category.ID'] = _t('ProductPage.IDLabel', 'Category');
152
        $labels['Category.Title'] = _t('ProductPage.CategoryTitleLabel', 'Category');
153
154
        return $labels;
155
    }
156
157
    /**
158
     * @return \SilverStripe\Forms\FieldList
159
     */
160
    public function getCMSFields()
161
    {
162
        $fields = parent::getCMSFields();
163
164
        // allow extensions of ProductPage to override the PreviewImage field description
165
        $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

165
        $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...
166
            'ProductPage.PreviewImageDescription',
167
            'Image used throughout site to represent this product'
168
        );
169
170
        // Cateogry Dropdown field w/ add new
171
        $source = function () {
172
            return ProductCategory::get()->map()->toArray();
173
        };
174
        $catField = DropdownField::create('CategoryID', _t('ProductPage.Category', 'FoxyCart Category'), $source())
0 ignored issues
show
Bug introduced by
'CategoryID' 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

174
        $catField = DropdownField::create(/** @scrutinizer ignore-type */ 'CategoryID', _t('ProductPage.Category', 'FoxyCart Category'), $source())
Loading history...
175
            ->setEmptyString('')
176
            ->setDescription(_t(
177
                'ProductPage.CategoryDescription',
178
                'Required, must also exist in 
179
                    <a href="https://admin.foxycart.com/admin.php?ThisAction=ManageProductCategories" target="_blank">
180
                        FoxyCart Categories
181
                    </a>.
182
                    Used to set category specific options like shipping and taxes. Managed in
183
                        <a href="admin/settings">
184
                            Settings > FoxyStripe > Categories
185
                        </a>'
186
            ));
187
        if (class_exists('QuickAddNewExtension')) {
188
            $catField->useAddNew('ProductCategory', $source);
189
        }
190
191
        // Product Images gridfield
192
        $config = GridFieldConfig_RelationEditor::create();
193
        $config->addComponent(new GridFieldOrderableRows('SortOrder'));
194
        $prodImagesField = GridField::create(
195
            'ProductImages',
196
            _t('ProductPage.ProductImages', 'Images'),
197
            $this->ProductImages(),
0 ignored issues
show
Bug introduced by
The method ProductImages() does not exist on Dynamic\FoxyStripe\Page\ProductPage. 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

197
            $this->/** @scrutinizer ignore-call */ 
198
                   ProductImages(),
Loading history...
198
            $config
199
        );
200
201
        // Product Options field
202
        $config = GridFieldConfig_RelationEditor::create();
203
        $config->addComponent(new GridFieldOrderableRows('SortOrder'));
204
        $products = $this->ProductOptions()->sort('SortOrder');
0 ignored issues
show
Bug introduced by
The method ProductOptions() does not exist on Dynamic\FoxyStripe\Page\ProductPage. 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

204
        $products = $this->/** @scrutinizer ignore-call */ ProductOptions()->sort('SortOrder');
Loading history...
205
        $config->removeComponentsByType('GridFieldAddExistingAutocompleter');
206
        $prodOptField = GridField::create(
207
            'ProductOptions',
208
            _t('ProductPage.ProductOptions', 'Options'),
209
            $products,
210
            $config
211
        );
212
213
        // Details tab
214
        $fields->addFieldsToTab('Root.Details', array(
215
            HeaderField::create('DetailHD', 'Product Details', 2),
0 ignored issues
show
Bug introduced by
2 of type integer 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

215
            HeaderField::create('DetailHD', 'Product Details', /** @scrutinizer ignore-type */ 2),
Loading history...
216
            CheckboxField::create('Available')
217
                ->setTitle(_t('ProductPage.Available', 'Available for purchase'))
218
                ->setDescription(_t(
219
                    'ProductPage.AvailableDescription',
220
                    'If unchecked, will remove "Add to Cart" form and instead display "Currently unavailable"'
221
                )),
222
            TextField::create('Code')
223
                ->setTitle(_t('ProductPage.Code', 'Product Code'))
224
                ->setDescription(_t(
225
                    'ProductPage.CodeDescription',
226
                    'Required, must be unique. Product identifier used by FoxyCart in transactions'
227
                )),
228
            $catField,
229
            CurrencyField::create('Price')
230
                ->setTitle(_t('ProductPage.Price', 'Price'))
231
                ->setDescription(_t(
232
                    'ProductPage.PriceDescription',
233
                    'Base price for this product. Can be modified using Product Options'
234
                )),
235
            NumericField::create('Weight')
236
                ->setTitle(_t('ProductPage.Weight', 'Weight'))
237
                ->setDescription(_t(
238
                    'ProductPage.WeightDescription',
239
                    'Base weight for this product in lbs. Can be modified using Product Options'
240
                )),
241
            CheckboxField::create('Featured')
242
                ->setTitle(_t('ProductPage.Featured', 'Featured Product')),
243
            TextField::create('ReceiptTitle')
244
                ->setTitle(_t('ProductPage.ReceiptTitle', 'Product Title for Receipt'))
245
                ->setDescription(_t(
246
                    'ProductPage.ReceiptTitleDescription',
247
                    'Optional'
248
                )),
249
        ));
250
251
        // Images tab
252
        $fields->addFieldsToTab('Root.Images', array(
253
            HeaderField::create('MainImageHD', _t('ProductPage.MainImageHD', 'Product Image'), 2),
254
            UploadField::create('PreviewImage', '')
255
                ->setDescription($previewDescription)
256
                ->setFolderName('Uploads/Products')
257
                ->setAllowedExtensions(array('jpg', 'jpeg', 'gif', 'png')),
258
            HeaderField::create('ProductImagesHD', _t('ProductPage.ProductImagesHD', 'Product Image Gallery'), 2),
259
            $prodImagesField
260
                ->setDescription(_t(
261
                    'ProductPage.ProductImagesDescription',
262
                    'Additional Product Images, shown in gallery on Product page'
263
                )),
264
        ));
265
266
        // Options Tab
267
        $fields->addFieldsToTab('Root.Options', array(
268
            HeaderField::create('OptionsHD', _t('ProductPage.OptionsHD', 'Product Options'), 2),
269
            LiteralField::create('OptionsDescrip', _t(
270
                'Page.OptionsDescrip',
271
                '<p>Product Options allow products to be customized by attributes such as size or color.
272
                    Options can also modify the product\'s price, weight or code.</p>'
273
            )),
274
            $prodOptField,
275
        ));
276
277
        if (FoxyCart::store_name_warning() !== null) {
278
            $fields->addFieldToTab('Root.Main', LiteralField::create('StoreSubDomainHeaderWarning', _t(
279
                'ProductPage.StoreSubDomainHeaderWarning',
280
                '<p class="message error">Store sub-domain must be entered in the 
281
                        <a href="/admin/settings/">site settings</a></p>'
282
            )), 'Title');
283
        }
284
285
        return $fields;
286
    }
287
288 49
    public function onBeforeWrite()
289
    {
290 49
        parent::onBeforeWrite();
291 49
        if (!$this->CategoryID) {
292
            $default = ProductCategory::get()->filter(array('Code' => 'DEFAULT'))->first();
293
            $this->CategoryID = $default->ID;
0 ignored issues
show
Bug Best Practice introduced by
The property CategoryID does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
294
        }
295
296
        //update many_many lists when multi-group is on
297 49
        if (SiteConfig::current_site_config()->MultiGroup) {
298
            $holders = $this->ProductHolders();
0 ignored issues
show
Bug introduced by
The method ProductHolders() does not exist on Dynamic\FoxyStripe\Page\ProductPage. 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

298
            /** @scrutinizer ignore-call */ 
299
            $holders = $this->ProductHolders();
Loading history...
299
            $product = self::get()->byID($this->ID);
300
            if (isset($product->ParentID)) {
301
                $origParent = $product->ParentID;
302
            } else {
303
                $origParent = null;
304
            }
305
            $currentParent = $this->ParentID;
306
            if ($origParent != $currentParent) {
307
                if ($holders->find('ID', $origParent)) {
308
                    $holders->removeByID($origParent);
309
                }
310
            }
311
            $holders->add($currentParent);
312
        }
313
314 49
        $title = ltrim($this->Title);
315 49
        $title = rtrim($title);
316 49
        $this->Title = $title;
317
    }
318
319 49
    public function onAfterWrite()
320
    {
321 49
        parent::onAfterWrite();
322
    }
323
324 2
    public function onBeforeDelete()
325
    {
326 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...
327 2
            if ($this->ProductOptions()) {
328 2
                $options = $this->getComponents('ProductOptions');
329 2
                foreach ($options as $option) {
330
                    $option->delete();
331
                }
332
            }
333 2
            if ($this->ProductImages()) {
334
                //delete product image dataobjects, not the images themselves.
335 2
                $images = $this->getComponents('ProductImages');
336 2
                foreach ($images as $image) {
337
                    $image->delete();
338
                }
339
            }
340
        }
341 2
        parent::onBeforeDelete();
342
    }
343
344 5
    public function validate()
345
    {
346 5
        $result = parent::validate();
347
348
        /*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...
349
            if($this->Price <= 0) {
350
                $result->error('Must set a positive price value');
351
            }
352
            if($this->Weight <= 0){
353
                $result->error('Must set a positive weight value');
354
            }
355
            if($this->Code == ''){
356
                $result->error('Must set a product code');
357
            }
358
        }*/
359
360 5
        return $result;
361
    }
362
363
    public function getCMSValidator()
364
    {
365
        return new RequiredFields(array('CategoryID', 'Price', 'Weight', 'Code'));
366
    }
367
368
    public static function getGeneratedValue(
369
        $productCode = null,
370
        $optionName = null,
371
        $optionValue = null,
372
        $method = 'name',
373
        $output = false,
374
        $urlEncode = false
375
    ) {
376
        $optionName = ($optionName !== null) ? preg_replace('/\s/', '_', $optionName) : $optionName;
377
378
        return (SiteConfig::current_site_config()->CartValidation)
379
            ? \FoxyCart_Helper::fc_hash_value($productCode, $optionName, $optionValue, $method, $output, $urlEncode) :
380
            $optionValue;
381
    }
382
383
    // get FoxyCart Store Name for JS call
384
    public function getCartScript()
385
    {
386
        $store = FoxyCart::getFoxyCartStoreName();
387
        return '<script src="https://cdn.foxycart.com/'.$store.'/loader.js" async defer></script>';
388
    }
389
390
    /**
391
     * @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...
392
     *
393
     * @return bool
394
     */
395
    public function canEdit($member = null)
396
    {
397
        return Permission::check('Product_CANCRUD', 'any', $member);
398
    }
399
400
    public function canDelete($member = null)
401
    {
402
        return Permission::check('Product_CANCRUD', 'any', $member);
403
    }
404
405
    public function canCreate($member = null, $context = [])
406
    {
407
        return Permission::check('Product_CANCRUD', 'any', $member);
408
    }
409
410 2
    public function canPublish($member = null)
411
    {
412 2
        return Permission::check('Product_CANCRUD', 'any', $member);
413
    }
414
415
    public function providePermissions()
416
    {
417
        return array(
418
            'Product_CANCRUD' => 'Allow user to manage Products and related objects',
419
        );
420
    }
421
}
422