Completed
Pull Request — master (#356)
by Jason
13:59
created

ProductPage::getImage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2.5

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 7
ccs 2
cts 4
cp 0.5
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 2.5
1
<?php
2
3
namespace Dynamic\FoxyStripe\Page;
4
5
use Bummzack\SortableFile\Forms\SortableUploadField;
0 ignored issues
show
Bug introduced by
The type Bummzack\SortableFile\Forms\SortableUploadField 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...
6
use Dynamic\FoxyStripe\Model\FoxyCart;
7
use Dynamic\FoxyStripe\Model\FoxyStripeSetting;
8
use Dynamic\FoxyStripe\Model\OptionItem;
9
use Dynamic\FoxyStripe\Model\OrderDetail;
10
use Dynamic\FoxyStripe\Model\ProductCategory;
11
use Dynamic\FoxyStripe\Model\ProductImage;
12
use SilverStripe\AssetAdmin\Forms\UploadField;
13
use SilverStripe\Assets\Image;
14
use SilverStripe\Forms\CheckboxField;
15
use SilverStripe\Forms\CurrencyField;
16
use SilverStripe\Forms\DropdownField;
17
use SilverStripe\Forms\GridField\GridField;
18
use SilverStripe\Forms\GridField\GridFieldAddExistingAutocompleter;
19
use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
20
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;
21
use SilverStripe\Forms\GridField\GridFieldDeleteAction;
22
use SilverStripe\Forms\HeaderField;
23
use SilverStripe\Forms\LiteralField;
24
use SilverStripe\Forms\NumericField;
25
use SilverStripe\Forms\RequiredFields;
26
use SilverStripe\Forms\TextField;
27
use SilverStripe\Security\Member;
28
use SilverStripe\Security\Permission;
29
use SilverStripe\Security\PermissionProvider;
30
use Symbiote\GridFieldExtensions\GridFieldOrderableRows;
31
32
/**
33
 * Class ProductPage
34
 * @package Dynamic\FoxyStripe\Page
35
 *
36
 * @property \SilverStripe\ORM\FieldType\DBCurrency Price
37
 * @property \SilverStripe\ORM\FieldType\DBDecimal Weight
38
 * @property \SilverStripe\ORM\FieldType\DBVarchar Code
39
 * @property \SilverStripe\ORM\FieldType\DBVarchar ReceiptTitle
40
 * @property \SilverStripe\ORM\FieldType\DBBoolean Featured
41
 * @property \SilverStripe\ORM\FieldType\DBBoolean Available
42
 *
43
 * @property int PreviewImageID
44
 * @method Image PreviewImage
45
 * @property int CategoryID
46
 * @method ProductCategory Category
47
 *
48
 *
49
 * @method \SilverStripe\ORM\HasManyList ProductImages
50
 * @method \SilverStripe\ORM\HasManyList ProductOptions
51
 * @method \SilverStripe\ORM\HasManyList OrderDetails
52
 *
53
 * @method \SilverStripe\ORM\ManyManyList ProductHolders
54
 */
55
class ProductPage extends \Page implements PermissionProvider
56
{
57
    /**
58
     * @var string
59
     */
60
    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...
61
62
    /**
63
     * @var bool
64
     */
65
    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...
66
67
    /**
68
     * @var array
69
     */
70
    private static $db = [
0 ignored issues
show
introduced by
The private property $db is not used, and could be removed.
Loading history...
71
        'Price' => 'Currency',
72
        'Weight' => 'Decimal',
73
        'Code' => 'Varchar(100)',
74
        'ReceiptTitle' => 'HTMLVarchar(255)',
75
        'Available' => 'Boolean',
76
    ];
77
78
    /**
79
     * @var array
80
     */
81
    private static $has_one = [
0 ignored issues
show
introduced by
The private property $has_one is not used, and could be removed.
Loading history...
82
        'Category' => ProductCategory::class,
83
    ];
84
85
    /**
86
     * @var array
87
     */
88
    private static $has_many = [
0 ignored issues
show
introduced by
The private property $has_many is not used, and could be removed.
Loading history...
89
        'ProductOptions' => OptionItem::class,
90
        'OrderDetails' => OrderDetail::class,
91
    ];
92
93
    /**
94
     * @var array
95
     */
96
    private static $many_many = [
0 ignored issues
show
introduced by
The private property $many_many is not used, and could be removed.
Loading history...
97
        'Images' => Image::class,
98
    ];
99
100
    /**
101
     * @var array
102
     */
103
    private static $many_many_extraFields = [
0 ignored issues
show
introduced by
The private property $many_many_extraFields is not used, and could be removed.
Loading history...
104
        'Images' => [
105
            'SortOrder' => 'Int',
106
        ],
107
    ];
108
109
    /**
110
     * @var array
111
     */
112
    private static $owns = [
0 ignored issues
show
introduced by
The private property $owns is not used, and could be removed.
Loading history...
113
        'Images',
114
    ];
115
116
    /**
117
     * @var array
118
     */
119
    private static $belongs_many_many = [
0 ignored issues
show
introduced by
The private property $belongs_many_many is not used, and could be removed.
Loading history...
120
        'ProductHolders' => ProductHolder::class,
121
    ];
122
123
    /**
124
     * @var string
125
     */
126
    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...
127
128
    /**
129
     * @var string
130
     */
131
    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...
132
133
    /**
134
     * @var string
135
     */
136
    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...
137
138
    /**
139
     * @var array
140
     */
141
    private static $indexes = [
0 ignored issues
show
introduced by
The private property $indexes is not used, and could be removed.
Loading history...
142
        'Code' => true, // make unique
143
    ];
144
145
    /**
146
     * @var array
147
     */
148
    private static $defaults = [
0 ignored issues
show
introduced by
The private property $defaults is not used, and could be removed.
Loading history...
149
        'ShowInMenus' => false,
150
        'Available' => true,
151
        'Weight' => '1.0',
152
    ];
153
154
    /**
155
     * @var array
156
     */
157
    private static $summary_fields = [
0 ignored issues
show
introduced by
The private property $summary_fields is not used, and could be removed.
Loading history...
158
        'Image.CMSThumbnail',
159
        'Title',
160
        'Code',
161
        'Price.Nice',
162
        'Category.Title',
163
    ];
164
165
    /**
166
     * @var array
167
     */
168
    private static $searchable_fields = [
0 ignored issues
show
introduced by
The private property $searchable_fields is not used, and could be removed.
Loading history...
169
        'Title',
170
        'Code',
171
        'Available',
172
        'Category.ID',
173
    ];
174
175
    /**
176
     * @var string
177
     */
178
    private static $table_name = 'ProductPage';
0 ignored issues
show
introduced by
The private property $table_name is not used, and could be removed.
Loading history...
179
180
    /**
181
     * @param bool $includerelations
182
     *
183
     * @return array
184
     */
185
    public function fieldLabels($includerelations = true)
186
    {
187
        $labels = parent::fieldLabels();
188
189
        $labels['Title'] = _t('ProductPage.TitleLabel', 'Name');
190
        $labels['Code'] = _t('ProductPage.CodeLabel', 'Code');
191
        $labels['Price.Nice'] = _t('ProductPage.PriceLabel', 'Price');
192
        $labels['Available.Nice'] = _t('ProductPage.AvailableLabel', 'Available');
193
        $labels['Category.ID'] = _t('ProductPage.IDLabel', 'Category');
194
        $labels['Category.Title'] = _t('ProductPage.CategoryTitleLabel', 'Category');
195
        $labels['Image.CMSThumbnail'] = _t('ProductPage.ImageLabel', 'Image');
196
197
        return $labels;
198
    }
199
200
    /**
201
     * @return \SilverStripe\Forms\FieldList
202
     */
203
    public function getCMSFields()
204
    {
205
        $fields = parent::getCMSFields();
206
207
        // Cateogry Dropdown field w/ add new
208
        $source = function () {
209
            return ProductCategory::get()->map()->toArray();
210
        };
211
        $catField = DropdownField::create('CategoryID', _t('ProductPage.Category', 'FoxyCart Category'), $source())
212
            ->setEmptyString('')
213
            ->setDescription(_t(
214
                'ProductPage.CategoryDescription',
215
                'Required, must also exist in 
216
                    <a href="https://admin.foxycart.com/admin.php?ThisAction=ManageProductCategories" target="_blank">
217
                        FoxyCart Categories
218
                    </a>.
219
                    Used to set category specific options like shipping and taxes. Managed in
220
                        <a href="admin/settings">
221
                            Settings > FoxyStripe > Categories
222
                        </a>'
223
            ));
224
        if (class_exists('QuickAddNewExtension')) {
225
            $catField->useAddNew('ProductCategory', $source);
226
        }
227
228
        $fields->addFieldsToTab(
229
            'Root.Main',
230
            [
231
                TextField::create('Code')
232
                    ->setTitle(_t('ProductPage.Code', 'Product Code'))
233
                    ->setDescription(_t(
234
                        'ProductPage.CodeDescription',
235
                        'Required, must be unique. Product identifier used by FoxyCart in transactions'
236
                    )),
237
                CurrencyField::create('Price')
238
                    ->setTitle(_t('ProductPage.Price', 'Price'))
239
                    ->setDescription(_t(
240
                        'ProductPage.PriceDescription',
241
                        'Base price for this product. Can be modified using Product Options'
242
                    )),
243
                $catField,
244
            ],
245
            'Content'
246
        );
247
248
        // Product Options field
249
        $config = GridFieldConfig_RelationEditor::create();
250
        $config->addComponent(new GridFieldOrderableRows('SortOrder'));
251
        $products = $this->ProductOptions()->sort('SortOrder');
252
        $config->removeComponentsByType(GridFieldAddExistingAutocompleter::class);
253
        $prodOptField = GridField::create(
254
            'ProductOptions',
255
            _t('ProductPage.ProductOptions', 'Options'),
256
            $products,
257
            $config
258
        );
259
260
        // Details tab
261
        $fields->addFieldsToTab('Root.Details', [
262
            CheckboxField::create('Available')
263
                ->setTitle(_t('ProductPage.Available', 'Available for purchase'))
264
                ->setDescription(_t(
265
                    'ProductPage.AvailableDescription',
266
                    'If unchecked, will remove "Add to Cart" form and instead display "Currently unavailable"'
267
                )),
268
            NumericField::create('Weight')
269
                ->setTitle(_t('ProductPage.Weight', 'Weight'))
270
                ->setDescription(_t(
271
                    'ProductPage.WeightDescription',
272
                    'Base weight for this product in lbs. Can be modified using Product Options'
273
                ))
274
                ->setScale(2),
275
            TextField::create('ReceiptTitle')
276
                ->setTitle(_t('ProductPage.ReceiptTitle', 'Product Title for Receipt'))
277
                ->setDescription(_t(
278
                    'ProductPage.ReceiptTitleDescription',
279
                    'Optional'
280
                )),
281
        ]);
282
283
        // Options Tab
284
        $fields->addFieldsToTab('Root.Options', [
285
            $prodOptField
286
                ->setDescription(_t(
287
                    'Page.OptionsDescrip',
288
                    '<p>Product Options allow products to be customized by attributes such as size or color.
289
                    Options can also modify the product\'s price, weight or code.<br></p>'
290
                )),
291
        ]);
292
293
        // Images tab
294
        $images = SortableUploadField::create('Images')
295
            ->setSortColumn('SortOrder')
296
            ->setIsMultiUpload(true)
297
            ->setAllowedFileCategories('image')
298
            ->setFolderName('Uploads/Products/Images')
299
        ;
300
301
        $fields->addFieldsToTab('Root.Images', [
302
            $images,
303
        ]);
304
305
        if (FoxyCart::store_name_warning() !== null) {
306
            $fields->addFieldToTab('Root.Main', LiteralField::create('StoreSubDomainHeaderWarning', _t(
307
                'ProductPage.StoreSubDomainHeaderWarning',
308
                '<p class="message error">Store sub-domain must be entered in the 
309
                        <a href="/admin/settings/">site settings</a></p>'
310
            )), 'Title');
311
        }
312
313
        return $fields;
314
    }
315
316
    /**
317
     * @return bool
318 13
     */
319
    public function getImage()
320 13
    {
321 13
        if ($this->Images()->count() > 0) {
0 ignored issues
show
Bug introduced by
The method Images() 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

321
        if ($this->/** @scrutinizer ignore-call */ Images()->count() > 0) {
Loading history...
322
            return $this->Images()->first();
323
        }
324
325
        return false;
326
    }
327 13
328
    /**
329
     * @throws \Exception
330
     */
331
    public function onBeforeWrite()
332
    {
333
        parent::onBeforeWrite();
334
        if (!$this->CategoryID) {
335
            $default = ProductCategory::get()->filter(['Code' => 'DEFAULT'])->first();
336
            $this->CategoryID = $default->ID;
337
        }
338
339
        //update many_many lists when multi-group is on
340
        if (FoxyStripeSetting::current_foxystripe_setting()->MultiGroup) {
341
            $holders = $this->ProductHolders();
342
            $product = self::get()->byID($this->ID);
343
            if (isset($product->ParentID)) {
344 13
                $origParent = $product->ParentID;
345 13
            } else {
346 13
                $origParent = null;
347
            }
348
            $currentParent = $this->ParentID;
349 13
            if ($origParent != $currentParent) {
350
                if ($holders->find('ID', $origParent)) {
351 13
                    $holders->removeByID($origParent);
352
                }
353
            }
354 2
            $holders->add($currentParent);
355
        }
356 2
357 2
        $this->Title = trim($this->Title);
358 2
        $this->Code = trim($this->Code);
0 ignored issues
show
Documentation Bug introduced by
It seems like trim($this->Code) of type string is incompatible with the declared type SilverStripe\ORM\FieldType\DBVarchar of property $Code.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
359 2
        $this->ReceiptTitle = trim($this->ReceiptTitle);
0 ignored issues
show
Documentation Bug introduced by
It seems like trim($this->ReceiptTitle) of type string is incompatible with the declared type SilverStripe\ORM\FieldType\DBVarchar of property $ReceiptTitle.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
360
    }
361
362
    public function onAfterWrite()
363 2
    {
364
        parent::onAfterWrite();
365 2
    }
366 2
367
    public function onBeforeDelete()
368
    {
369
        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...
370
            if ($this->ProductOptions()) {
371 2
                $options = $this->getComponents('ProductOptions');
372
                foreach ($options as $option) {
373
                    $option->delete();
374 5
                }
375
            }
376 5
            if ($this->ProductImages()) {
377
                //delete product image dataobjects, not the images themselves.
378
                $images = $this->getComponents('ProductImages');
379
                foreach ($images as $image) {
380
                    $image->delete();
381
                }
382
            }
383
        }
384
        parent::onBeforeDelete();
385
    }
386
387
    public function validate()
388
    {
389
        $result = parent::validate();
390 5
391
        /*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...
392
            if($this->Price <= 0) {
393
                $result->error('Must set a positive price value');
394
            }
395
            if($this->Weight <= 0){
396
                $result->error('Must set a positive weight value');
397
            }
398
            if($this->Code == ''){
399
                $result->error('Must set a product code');
400
            }
401
        }*/
402
403
        return $result;
404
    }
405
406
    public function getCMSValidator()
407
    {
408
        return new RequiredFields(['CategoryID', 'Price', 'Weight', 'Code']);
409
    }
410
411
    /**
412
     * @param null $productCode
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $productCode is correct as it would always require null to be passed?
Loading history...
413
     * @param null $optionName
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $optionName is correct as it would always require null to be passed?
Loading history...
414
     * @param null $optionValue
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $optionValue is correct as it would always require null to be passed?
Loading history...
415
     * @param string $method
416
     * @param bool $output
417
     * @param bool $urlEncode
418
     *
419
     * @return null|string
420
     */
421
    public static function getGeneratedValue(
422
        $productCode = null,
423
        $optionName = null,
424
        $optionValue = null,
425
        $method = 'name',
426
        $output = false,
427
        $urlEncode = false
428
    ) {
429
        $optionName = ($optionName !== null) ? preg_replace('/\s/', '_', $optionName) : $optionName;
0 ignored issues
show
introduced by
The condition $optionName !== null is always false.
Loading history...
430
431
        return (FoxyStripeSetting::current_foxystripe_setting()->CartValidation)
432
            ? \FoxyCart_Helper::fc_hash_value($productCode, $optionName, $optionValue, $method, $output, $urlEncode) :
433
            $optionValue;
434
    }
435
436
    /**
437
     * @param Member $member
438
     *
439
     * @return bool
440
     */
441
    public function canEdit($member = null)
442
    {
443
        return Permission::check('Product_CANCRUD', 'any', $member);
444
    }
445
446
    public function canDelete($member = null)
447
    {
448
        return Permission::check('Product_CANCRUD', 'any', $member);
449
    }
450
451
    public function canCreate($member = null, $context = [])
452
    {
453
        return Permission::check('Product_CANCRUD', 'any', $member);
454
    }
455
456
    public function canPublish($member = null)
457
    {
458
        return Permission::check('Product_CANCRUD', 'any', $member);
459
    }
460
461
    public function providePermissions()
462
    {
463
        return [
464
            'Product_CANCRUD' => 'Allow user to manage Products and related objects',
465
        ];
466
    }
467
}
468