Passed
Push — master ( f6b8eb...4dcbe5 )
by Jason
02:36
created

Purchasable::getIsAvailable()   A

Complexity

Conditions 6
Paths 4

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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

152
                    ->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...
153
                    ->setSource(FoxyCategory::get()->map())
154
                    ->setDescription(_t(
155
                        __CLASS__ . '.FoxyCategoryDescription',
156
                        'Required. Must also exist in
157
                        <a href="https://admin.foxycart.com/admin.php?ThisAction=ManageProductCategories"
158
                            target="_blank">
159
                            Foxy Categories
160
                        </a>.
161
                        Used to set category specific options like shipping and taxes. Managed in Foxy > Categories'
162
                    ))
163
                    ->setEmptyString(''),
164
                TextField::create('ReceiptTitle')
165
                    ->setDescription(_t(
166
                        __CLASS__ . '.ReceiptTitleDescription',
167
                        'Optional. Alternate title to display on order receipt'
168
                    )),
169
            ],
170
            'Content'
171
        );
172
173
        if ($this->owner->exists()) {
0 ignored issues
show
Bug introduced by
The method exists() 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

173
        if ($this->owner->/** @scrutinizer ignore-call */ exists()) {

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...
174
            $variationsConfig = GridFieldConfig_RelationEditor::create()
175
                ->removeComponentsByType([
176
                    GridFieldAddExistingAutocompleter::class,
177
                    GridFieldPaginator::class,
178
                    GridFieldPageCount::class,
179
                    GridFieldSortableHeader::class,
180
                ])
181
                ->addComponents([
182
                    new GridFieldOrderableRows('SortOrder'),
183
                    new GridFieldTitleHeader(),
184
                    new GridFieldGroupable(
185
                        'VariationTypeID',    // The fieldname to set the Group
186
                        'Variation Type',   // A description of the function of the group
187
                        'none',         // A title/header for items without a group/unassigned
188
                        VariationType::get()->sort('SortOrder')->map()->toArray()
189
                    )
190
                ]);
191
192
            $fields->addFieldToTab(
193
                'Root.Variations',
194
                GridField::create(
195
                    'Variations',
196
                    'Variations',
197
                    $this->owner->Variations(),
198
                    $variationsConfig
199
                )
200
            );
201
        }
202
203
        $fields->addFieldsToTab(
204
            'Root.Inventory',
205
            [
206
                NumericField::create('QuantityMax')
207
                    ->setTitle('Maximum quantity allowed in the cart')
208
                    ->setDescription('For unlimited enter 0')
209
                    ->addExtraClass('stacked'),
210
                CheckboxField::create('Available')
211
                    ->setDescription(_t(
212
                        __CLASS__ . '.AvailableDescription',
213
                        'If unchecked, will remove "Add to Cart" form and instead display "Currently unavailable"'
214
                    )),
215
            ]
216
        );
217
    }
218
219
    /**
220
     * @return RequiredFields
221
     */
222
    public function getCMSValidator()
223
    {
224
        return new RequiredFields([
225
            "Price",
226
            "Code",
227
            "FoxyCategoryID",
228
        ]);
229
    }
230
231
    /**
232
     * @return bool
233
     */
234
    public function getIsAvailable()
235
    {
236
        $available = true;
237
238
        if (!$this->owner->Available) {
239
            $available = false;
240
        }
241
242
        if ($available && $this->owner->Variations()->count()) {
243
            $available = false;
244
            foreach ($this->owner->Variations() as $variation) {
245
                if ($variation->Available) {
246
                    $available = true;
247
                }
248
            }
249
        }
250
251
        $this->owner->extend('updateGetIsAvailable', $available);
0 ignored issues
show
Bug introduced by
The method extend() 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

251
        $this->owner->/** @scrutinizer ignore-call */ 
252
                      extend('updateGetIsAvailable', $available);

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...
252
253
        return $available;
254
    }
255
256
    /**
257
     * @return mixed
258
     */
259
    public function isAvailable()
260
    {
261
        Deprecation::notice('1.4', 'Use getIsAvailable() instead');
262
        return $this->getIsAvailable();
263
    }
264
265
    /**
266
     * @return bool
267
     */
268
    public function isProduct()
269
    {
270
        return true;
271
    }
272
273
    /**
274
     * @return array
275
     */
276
    public function providePermissions()
277
    {
278
        return [
279
            'MANAGE_FOXY_PRODUCTS' => [
280
                'name' => _t(
281
                    __CLASS__ . '.PERMISSION_MANAGE_PRODUCTS_DESCRIPTION',
282
                    'Manage products'
283
                ),
284
                'category' => _t(
285
                    __CLASS__ . '.PERMISSIONS_CATEGORY',
286
                    'Foxy'
287
                ),
288
                'help' => _t(
289
                    __CLASS__ . '.PERMISSION_MANAGE_PRODUCTS_HELP',
290
                    'Manage products and related settings'
291
                ),
292
                'sort' => 400,
293
            ],
294
        ];
295
    }
296
297
    /**
298
     * @param $member
299
     * @return bool|int|void
300
     */
301
    public function canCreate($member)
302
    {
303
        if (!$member) {
304
            $member = Security::getCurrentUser();
305
        }
306
307
        return Permission::checkMember($member, 'MANAGE_FOXY_PRODUCTS');
308
    }
309
310
    /**
311
     * @param $member
312
     * @return bool|int|void|null
313
     */
314
    public function canEdit($member)
315
    {
316
        if (!$member) {
317
            $member = Security::getCurrentUser();
318
        }
319
320
        return Permission::checkMember($member, 'MANAGE_FOXY_PRODUCTS');
321
    }
322
323
    /**
324
     * @param $member
325
     * @return bool|int|void
326
     */
327
    public function canDelete($member)
328
    {
329
        if (!$member) {
330
            $member = Security::getCurrentUser();
331
        }
332
333
        return Permission::checkMember($member, 'MANAGE_FOXY_PRODUCTS');
334
    }
335
336
    /**
337
     * @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...
338
     * @return bool|int
339
     */
340
    public function canUnpublish($member = null)
341
    {
342
        if (!$member) {
0 ignored issues
show
introduced by
$member is of type null, thus it always evaluated to false.
Loading history...
343
            $member = Security::getCurrentUser();
344
        }
345
346
        return Permission::checkMember($member, 'MANAGE_FOXY_PRODUCTS');
347
    }
348
349
    /**
350
     * @param $member
351
     * @return bool|int
352
     */
353
    public function canArchive($member = null)
354
    {
355
        if (!$member) {
356
            $member = Security::getCurrentUser();
357
        }
358
359
        return Permission::checkMember($member, 'MANAGE_FOXY_PRODUCTS');
360
    }
361
362
    /**
363
     *
364
     */
365
    public function onBeforeWrite()
366
    {
367
        // trim spaces and replace duplicate spaces
368
        $trimmed = trim($this->owner->Code);
369
        $this->owner->Code = preg_replace('/\s+/', ' ', $trimmed);
370
    }
371
}
372