Passed
Pull Request — master (#309)
by Jason
13:47
created

ProductPage::onBeforeWrite()   B

Complexity

Conditions 6
Paths 14

Size

Total Lines 29
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 29
rs 8.439
c 0
b 0
f 0
cc 6
eloc 19
nc 14
nop 0
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
     * @return array
140
     */
141
    public function fieldLabels($includerelations = true)
142
    {
143
        $labels = parent::fieldLabels();
144
145
        $labels['Title'] = _t('ProductPage.TitleLabel', 'Name');
146
        $labels['Code'] = _t('ProductPage.CodeLabel', "Code");
147
        $labels['Price.Nice'] = _t('ProductPage.PriceLabel', 'Price');
148
        $labels['Featured.Nice'] = _t('ProductPage.NiceLabel', 'Featured');
149
        $labels['Available.Nice'] = _t('ProductPage.AvailableLabel', 'Available');
150
        $labels['Category.ID'] = _t('ProductPage.IDLabel', 'Category');
151
        $labels['Category.Title'] = _t('ProductPage.CategoryTitleLabel', 'Category');
152
153
        return $labels;
154
    }
155
156
    /**
157
     * @return \SilverStripe\Forms\FieldList
158
     */
159
    public function getCMSFields()
160
    {
161
        $fields = parent::getCMSFields();
162
163
        // allow extensions of ProductPage to override the PreviewImage field description
164
        $previewDescription = ($this->stat('customPreviewDescription')) ? $this->stat('customPreviewDescription') : _t('ProductPage.PreviewImageDescription',
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

164
        $previewDescription = (/** @scrutinizer ignore-deprecated */ $this->stat('customPreviewDescription')) ? $this->stat('customPreviewDescription') : _t('ProductPage.PreviewImageDescription',

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...
165
            'Image used throughout site to represent this product');
166
167
        // Cateogry Dropdown field w/ add new
168
        $source = function () {
169
            return ProductCategory::get()->map()->toArray();
170
        };
171
        $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

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

194
            $this->/** @scrutinizer ignore-call */ 
195
                   ProductImages(),
Loading history...
195
            $config
196
        );
197
198
        // Product Options field
199
        $config = GridFieldConfig_RelationEditor::create();
200
        $config->addComponent(new GridFieldOrderableRows('SortOrder'));
201
        $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

201
        $products = $this->/** @scrutinizer ignore-call */ ProductOptions()->sort('SortOrder');
Loading history...
202
        $config->removeComponentsByType('GridFieldAddExistingAutocompleter');
203
        $prodOptField = GridField::create(
204
            'ProductOptions',
205
            _t('ProductPage.ProductOptions', 'Options'),
206
            $products,
207
            $config
208
        );
209
210
        // Details tab
211
        $fields->addFieldsToTab('Root.Details', array(
212
            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

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

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