Completed
Push — master ( e312ae...228662 )
by Nic
10:54
created

Purchasable::onBeforeWrite()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 5
rs 10
1
<?php
2
3
namespace Dynamic\Foxy\Extension;
4
5
use Dynamic\Foxy\Model\FoxyCategory;
6
use Dynamic\Foxy\Model\ProductOption;
7
use SilverStripe\Forms\CheckboxField;
8
use SilverStripe\Forms\CurrencyField;
9
use SilverStripe\Forms\DropdownField;
10
use SilverStripe\Forms\FieldList;
11
use SilverStripe\Forms\GridField\GridField;
12
use SilverStripe\Forms\GridField\GridFieldAddExistingAutocompleter;
13
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;
14
use SilverStripe\Forms\TextField;
15
use SilverStripe\ORM\DataExtension;
16
use SilverStripe\ORM\ValidationResult;
17
use SilverStripe\Security\Permission;
18
use SilverStripe\Security\PermissionProvider;
19
use SilverStripe\Security\Security;
20
use Symbiote\GridFieldExtensions\GridFieldAddExistingSearchButton;
21
use Symbiote\GridFieldExtensions\GridFieldOrderableRows;
22
23
/**
24
 * Class Purchasable
25
 * @package Dynamic\Foxy\Extension
26
 *
27
 * @property double Price
28
 * @property string Code
29
 * @property string ReceiptTitle
30
 * @property bool Available
31
 *
32
 * @property int FoxyCategoryID
33
 * @method FoxyCategory FoxyCategory()
34
 *
35
 * @method \SilverStripe\ORM\ManyManyList Options()
36
 *
37
 * @property-read \SilverStripe\ORM\DataObject|Purchasable $owner
38
 */
39
class Purchasable extends DataExtension implements PermissionProvider
40
{
41
    /**
42
     * @var array
43
     */
44
    private static $db = [
0 ignored issues
show
introduced by
The private property $db is not used, and could be removed.
Loading history...
45
        'Price' => 'Currency',
46
        'Code' => 'Varchar(100)',
47
        'ReceiptTitle' => 'HTMLVarchar(255)',
48
        'Available' => 'Boolean',
49
    ];
50
51
    /**
52
     * @var array
53
     */
54
    private static $has_one = [
0 ignored issues
show
introduced by
The private property $has_one is not used, and could be removed.
Loading history...
55
        'FoxyCategory' => FoxyCategory::class,
56
    ];
57
58
    /**
59
     * @var array
60
     */
61
    private static $many_many = [
0 ignored issues
show
introduced by
The private property $many_many is not used, and could be removed.
Loading history...
62
        'Options' => ProductOption::class,
63
    ];
64
65
    /**
66
     * @var array
67
     */
68
    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...
69
        'Options' => [
70
            'WeightModifier' => 'Decimal(9,3)',
71
            'CodeModifier' => 'Text',
72
            'PriceModifier' => 'Currency',
73
            'WeightModifierAction' => "Enum('Add,Subtract,Set', null)",
74
            'CodeModifierAction' => "Enum('Add,Subtract,Set', null)",
75
            'PriceModifierAction' => "Enum('Add,Subtract,Set', null)",
76
            'Available' => 'Boolean',
77
            'Type' => 'Int',
78
            'OptionModifierKey' => 'Varchar(255)',
79
            'SortOrder' => 'Int',
80
        ],
81
        'OptionTypes' => [
82
            'SortOrder' => 'Int',
83
        ],
84
    ];
85
86
    /**
87
     * @var array
88
     */
89
    private static $indexes = [
0 ignored issues
show
introduced by
The private property $indexes is not used, and could be removed.
Loading history...
90
        'Code' => [
91
            'type' => 'unique',
92
            'columns' => ['Code'],
93
        ],
94
    ];
95
96
    /**
97
     * @var array
98
     */
99
    private static $defaults = [
0 ignored issues
show
introduced by
The private property $defaults is not used, and could be removed.
Loading history...
100
        'ShowInMenus' => false,
101
        'Available' => true,
102
    ];
103
104
    /**
105
     * @var array
106
     */
107
    private static $summary_fields = [
0 ignored issues
show
introduced by
The private property $summary_fields is not used, and could be removed.
Loading history...
108
        'Image.CMSThumbnail',
109
        'Title',
110
        'Code',
111
        'Price.Nice',
112
    ];
113
114
    /**
115
     * @var array
116
     */
117
    private static $searchable_fields = [
0 ignored issues
show
introduced by
The private property $searchable_fields is not used, and could be removed.
Loading history...
118
        'Title',
119
        'Code',
120
        'Available',
121
    ];
122
123
    /**
124
     * @param bool $includerelations
125
     *
126
     * @return array
127
     */
128
    public function updateFieldLabels(&$labels)
129
    {
130
        $labels['Title'] = _t(__CLASS__ . '.TitleLabel', 'Product Name');
131
        $labels['Code'] = _t(__CLASS__ . '.CodeLabel', 'Code');
132
        $labels['Price'] = _t(__CLASS__ . '.PriceLabel', 'Price');
133
        $labels['Price.Nice'] = _t(__CLASS__ . '.PriceLabel', 'Price');
134
        $labels['Available'] = _t(__CLASS__ . '.AvailableLabel', 'Available for purchase');
135
        $labels['Available.Nice'] = _t(__CLASS__ . '.AvailableLabelNice', 'Available');
136
        $labels['Image.CMSThumbnail'] = _t(__CLASS__ . '.ImageLabel', 'Image');
137
        $labels['ReceiptTitle'] = _t(__CLASS__ . '.ReceiptTitleLabel', 'Product title for receipt');
138
        $labels['FoxyCategoryID'] = _t(__CLASS__ . '.FoxyCategoryLabel', 'Foxy Category');
139
    }
140
141
    /**
142
     * @param FieldList $fields
143
     */
144
    public function updateCMSFields(FieldList $fields)
145
    {
146
        $fields->removeByName([
147
            'SKU',
148
        ]);
149
150
        $fields->addFieldsToTab(
151
            'Root.Ecommerce',
152
            [
153
                CurrencyField::create('Price')
154
                    ->setDescription(_t(
155
                        __CLASS__ . '.PriceDescription',
156
                        'Base price for this product. Can be modified using Product Options'
157
                    )),
158
                TextField::create('Code')
159
                    ->setDescription(_t(
160
                        __CLASS__ . '.CodeDescription',
161
                        'Required, must be unique. Product identifier used by FoxyCart in transactions. All leading and trailing spaces are removed on save.'
162
                    )),
163
                DropdownField::create('FoxyCategoryID')
164
                    ->setTitle($this->owner->fieldLabel('FoxyCategoryID'))
0 ignored issues
show
Bug introduced by
The method fieldLabel() does not exist on Dynamic\Foxy\Extension\Purchasable. ( Ignorable by Annotation )

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

164
                    ->setTitle($this->owner->/** @scrutinizer ignore-call */ fieldLabel('FoxyCategoryID'))

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
165
                    ->setSource(FoxyCategory::get()->map())
166
                    ->setDescription(_t(
167
                        __CLASS__ . '.FoxyCategoryDescription',
168
                        'Required. Must also exist in
169
                        <a href="https://admin.foxycart.com/admin.php?ThisAction=ManageProductCategories"
170
                            target="_blank">
171
                            Foxy Categories
172
                        </a>.
173
                        Used to set category specific options like shipping and taxes. Managed in Foxy > Categories'
174
                    ))
175
                    ->setEmptyString(''),
176
                TextField::create('ReceiptTitle')
177
                    ->setDescription(_t(
178
                        __CLASS__ . '.ReceiptTitleDescription',
179
                        'Optional. Alternate title to display on order receipt'
180
                    )),
181
            ],
182
            'Content'
183
        );
184
185
        if ($this->owner->ID) {
0 ignored issues
show
Bug Best Practice introduced by
The property ID does not exist on Dynamic\Foxy\Extension\Purchasable. Did you maybe forget to declare it?
Loading history...
186
            $config = GridFieldConfig_RelationEditor::create();
187
            $config
188
                ->addComponents([
189
                    new GridFieldOrderableRows('SortOrder'),
190
                    new GridFieldAddExistingSearchButton(),
191
                ])
192
                ->removeComponentsByType([
193
                    GridFieldAddExistingAutocompleter::class,
194
                ]);
195
            $options = GridField::create(
196
                'Options',
197
                'Options',
198
                $this->owner->Options()->sort('SortOrder'),
199
                $config
200
            );
201
202
            $fields->addFieldsToTab(
203
                'Root.Options',
204
                [
205
                    $options,
206
                ]
207
            );
208
        }
209
210
        $fields->addFieldsToTab(
211
            'Root.Inventory',
212
            [
213
                CheckboxField::create('Available')
214
                    ->setDescription(_t(
215
                        __CLASS__ . '.AvailableDescription',
216
                        'If unchecked, will remove "Add to Cart" form and instead display "Currently unavailable"'
217
                    )),
218
            ]
219
        );
220
    }
221
222
    /**
223
     * @return \SilverStripe\ORM\ValidationResult
224
     */
225
    public function validate(ValidationResult $validationResult)
226
    {
227
        /*
228
        if (!$this->owner->Price) {
229
            $validationResult->addError(
230
                _t(__CLASS__ . '.PriceRequired', 'You must set a product price in the Foxy tab')
231
            );
232
        }
233
234
        if (!$this->owner->Code) {
235
            $validationResult->addError(
236
                _t(__CLASS__ . '.CodeRequired', 'You must set a product code in the Foxy tab')
237
            );
238
        }
239
240
        if (!$this->owner->FoxyCategoryID) {
241
            $validationResult->addError(
242
                _t(__CLASS__ . '.FoxyCategoryRequired', 'You must set a foxy category in the Foxy tab.')
243
            );
244
        }
245
        */
246
    }
247
248
    /**
249
     * @return bool
250
     */
251
    public function isAvailable()
252
    {
253
        if (!$this->owner->Available) {
254
            return false;
255
        }
256
257
        if (!$this->owner->Options()->exists()) {
258
            return true;
259
        }
260
261
        foreach ($this->owner->Options() as $option) {
262
            if ($option->Available) {
263
                return true;
264
            }
265
        }
266
267
        return false;
268
    }
269
270
    /**
271
     * @return bool
272
     */
273
    public function isProduct()
274
    {
275
        return true;
276
    }
277
278
    /**
279
     * @return array
280
     */
281
    public function providePermissions()
282
    {
283
        return [
284
            'MANAGE_FOXY_PRODUCTS' => [
285
                'name' => _t(
286
                    __CLASS__ . '.PERMISSION_MANAGE_PRODUCTS_DESCRIPTION',
287
                    'Manage products'
288
                ),
289
                'category' => _t(
290
                    __CLASS__ . '.PERMISSIONS_CATEGORY',
291
                    'Foxy'
292
                ),
293
                'help' => _t(
294
                    __CLASS__ . '.PERMISSION_MANAGE_PRODUCTS_HELP',
295
                    'Manage products and related settings'
296
                ),
297
                'sort' => 400,
298
            ],
299
        ];
300
    }
301
302
    /**
303
     * @param $member
304
     * @return bool|int|void
305
     */
306
    public function canCreate($member)
307
    {
308
        if (!$member) {
309
            $member = Security::getCurrentUser();
310
        }
311
312
        return Permission::checkMember($member, 'MANAGE_FOXY_PRODUCTS');
313
    }
314
315
    /**
316
     * @param $member
317
     * @return bool|int|void|null
318
     */
319
    public function canEdit($member)
320
    {
321
        if (!$member) {
322
            $member = Security::getCurrentUser();
323
        }
324
325
        return Permission::checkMember($member, 'MANAGE_FOXY_PRODUCTS');
326
    }
327
328
    /**
329
     * @param $member
330
     * @return bool|int|void
331
     */
332
    public function canDelete($member)
333
    {
334
        if (!$member) {
335
            $member = Security::getCurrentUser();
336
        }
337
338
        return Permission::checkMember($member, 'MANAGE_FOXY_PRODUCTS');
339
    }
340
341
    /**
342
     * @param null $member
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $member is correct as it would always require null to be passed?
Loading history...
343
     * @return bool|int
344
     */
345
    public function canUnpublish($member = null)
346
    {
347
        if (!$member) {
0 ignored issues
show
introduced by
$member is of type null, thus it always evaluated to false.
Loading history...
348
            $member = Security::getCurrentUser();
349
        }
350
351
        return Permission::checkMember($member, 'MANAGE_FOXY_PRODUCTS');
352
    }
353
354
    /**
355
     * @param $member
356
     * @return bool|int
357
     */
358
    public function canArchive($member = null)
359
    {
360
        if (!$member) {
361
            $member = Security::getCurrentUser();
362
        }
363
364
        return Permission::checkMember($member, 'MANAGE_FOXY_PRODUCTS');
365
    }
366
367
    /**
368
     *
369
     */
370
    public function onBeforeWrite()
371
    {
372
        // trim spaces and replace duplicate spaces
373
        $trimmed = trim($this->owner->Code);
374
        $this->owner->Code = preg_replace('/\s+/', ' ', $trimmed);
375
    }
376
}
377