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

FoxyStripeSiteConfig   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 376
Duplicated Lines 0 %

Test Coverage

Coverage 98.27%

Importance

Changes 0
Metric Value
wmc 17
c 0
b 0
f 0
dl 0
loc 376
ccs 170
cts 173
cp 0.9827
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A onAfterWrite() 0 7 4
A onBeforeWrite() 0 5 4
B updateCMSFields() 0 214 2
A getDataFeedLink() 0 3 1
B getDataMap() 0 25 1
A getCheckoutTypes() 0 7 1
A requireDefaultRecords() 0 14 3
A getSSOLink() 0 3 1
1
<?php
2
3
namespace Dynamic\FoxyStripe\ORM;
4
5
use Dynamic\CountryDropdownField\Fields\CountryDropdownField;
6
use Dynamic\FoxyStripe\Model\FoxyCart;
7
use Dynamic\FoxyStripe\Model\FoxyStripeClient;
8
use Dynamic\FoxyStripe\Model\OptionGroup;
9
use Dynamic\FoxyStripe\Model\ProductCategory;
10
use Psr\Log\LoggerInterface;
11
use SilverStripe\Control\Director;
12
use SilverStripe\Core\Injector\Injector;
13
use SilverStripe\Forms\CheckboxField;
14
use SilverStripe\Forms\DropdownField;
15
use SilverStripe\Forms\FieldList;
16
use SilverStripe\Forms\GridField\GridField;
17
use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
18
use SilverStripe\Forms\HeaderField;
19
use SilverStripe\Forms\LiteralField;
20
use SilverStripe\Forms\NumericField;
21
use SilverStripe\Forms\ReadonlyField;
22
use SilverStripe\Forms\TabSet;
23
use SilverStripe\Forms\TextField;
24
use SilverStripe\ORM\DataExtension;
25
use SilverStripe\ORM\DB;
26
use SilverStripe\SiteConfig\SiteConfig;
27
28
class FoxyStripeSiteConfig extends DataExtension
29
{
30
    private static $db = array(
0 ignored issues
show
introduced by
The private property $db is not used, and could be removed.
Loading history...
31
        'StoreTitle' => 'Varchar(255)',
32
        'StoreName' => 'Varchar(255)',
33
        'StoreURL' => 'Varchar(255)',
34
        'ReceiptURL' => 'Varchar(255)',
35
        'StoreEmail' => 'Varchar(255)',
36
        'FromEmail' => 'Varchar(255)',
37
        'StorePostalCode' => 'Varchar(10)',
38
        'StoreCountry' => 'Varchar(100)',
39
        'StoreRegion' => 'Varchar(100)',
40
        'StoreLocaleCode' => 'Varchar(10)',
41
        'StoreLogoURL' => 'Varchar(255)',
42
        'CheckoutType' => 'Varchar(50)',
43
        'BccEmail' => 'Boolean',
44
        'UseWebhook' => 'Boolean',
45
        'StoreKey' => 'Varchar(60)',
46
        'CartValidation' => 'Boolean',
47
        'UseSingleSignOn' => 'Boolean',
48
        'AllowMultiship' => 'Boolean',
49
        'StoreTimezone' => 'Varchar(100)',
50
        'MultiGroup' => 'Boolean',
51
        'ProductLimit' => 'Int',
52
        'MaxQuantity' => 'Int',
53
        'client_id' => 'Varchar(255)',
54
        'client_secret' => 'Varchar(255)',
55
        'access_token' => 'Varchar(255)',
56
        'refresh_token' => 'Varchar(255)',
57
    );
58
59
    // Set Default values
60
    private static $defaults = array(
0 ignored issues
show
introduced by
The private property $defaults is not used, and could be removed.
Loading history...
61
        'ProductLimit' => 10,
62
    );
63
64 1
    public function updateCMSFields(FieldList $fields)
65
    {
66
67
        // set TabSet names to avoid spaces from camel case
68 1
        $fields->addFieldToTab('Root', new TabSet('FoxyStripe', 'FoxyStripe'));
69
70
        // settings tab
71 1
        $fields->addFieldsToTab('Root.FoxyStripe.Settings', array(
72
            // Store Details
73 1
            HeaderField::create('StoreDetails', _t('FoxyStripeSiteConfig.StoreDetails', 'Store Settings'), 3),
0 ignored issues
show
Bug introduced by
3 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

73
            HeaderField::create('StoreDetails', _t('FoxyStripeSiteConfig.StoreDetails', 'Store Settings'), /** @scrutinizer ignore-type */ 3),
Loading history...
Bug introduced by
'StoreDetails' 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

73
            HeaderField::create(/** @scrutinizer ignore-type */ 'StoreDetails', _t('FoxyStripeSiteConfig.StoreDetails', 'Store Settings'), 3),
Loading history...
74 1
            LiteralField::create('DetailsIntro', _t(
75 1
                'FoxyStripeSiteConfig.DetailsIntro',
76 1
                '<p>Maps to data in your 
77
                        <a href="https://admin.foxycart.com/admin.php?ThisAction=EditStore" target="_blank">
78
                            FoxyCart store settings
79
                        </a>.'
80
            )),
81 1
            TextField::create('StoreTitle')
82 1
                ->setTitle(_t('FoxyStripeSiteConfig.StoreTitle', 'Store Name'))
83 1
                ->setDescription(_t(
84 1
                    'FoxyStripeSiteConfig.StoreTitleDescription',
85 1
                    'The name of your store as you\'d like it displayed to your customers'
86
                )),
87 1
            TextField::create('StoreName')
88 1
                ->setTitle(_t('FoxyStripeSiteConfig.StoreName', 'Store Domain'))
89 1
                ->setDescription(_t(
90 1
                    'FoxyStripeSiteConfig.StoreNameDescription',
91 1
                    'This is a unique FoxyCart subdomain for your cart, checkout, and receipt'
92
                )),
93 1
            TextField::create('StoreURL')
94 1
                ->setTitle(_t('FoxyStripeSiteConfig.StoreURL', 'Store URL'))
95 1
                ->setDescription(_t(
96 1
                    'FoxyStripeSiteConfig.StoreURLDescription',
97 1
                    'The URL of your online store'
98
                )),
99 1
            TextField::create('ReceiptURL')
100 1
                ->setTitle(_t('FoxyStripeSiteConfig.ReceiptURL', 'Receipt URL'))
101 1
                ->setDescription(_t(
102 1
                    'FoxyStripeSiteConfig.ReceiptURLDescription',
103 1
                    'By default, FoxyCart sends customers back to the page referrer after completing a purchase. 
104
                            Instead, you can set a specific URL here.'
105
                )),
106 1
            TextField::create('StoreEmail')
107 1
                ->setTitle(_t('FoxyStripeSiteConfig.StoreEmail', 'Store Email'))
108 1
                ->setDescription(_t(
109 1
                    'FoxyStripeSiteConfig.StoreEmailDescription',
110 1
                    'This is the email address of your store. By default, this will be the from address for your 
111
                            store receipts. '
112
                )),
113 1
            TextField::create('FromEmail')
114 1
                ->setTitle(_t('FoxyStripeSiteConfig.FromEmail', 'From Email'))
115 1
                ->setDescription(_t(
116 1
                    'FoxyStripeSiteConfig.FromEmailDescription',
117 1
                    'Used for when you want to specify a different from email than your store\'s email address'
118
                )),
119 1
            TextField::create('StorePostalCode', 'Postal Code'),
120 1
            CountryDropdownField::create('StoreCountry', 'Country'),
121 1
            TextField::create('StoreRegion', 'State/Region'),
122 1
            TextField::create('StoreLocaleCode', 'Locale Code')
123 1
                ->setDescription('example: en_US'),
124 1
            TextField::create('StoreTimezone', 'Store timezone'),
125 1
            TextField::create('StoreLogoURL', 'Logo URL')
126 1
                ->setAttribute('placeholder', 'http://'),
127
128
            // Advanced Settings
129
            /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% 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...
130
            HeaderField::create('AdvanceHeader', _t('FoxyStripeSiteConfig.AdvancedHeader', 'Advanced Settings'), 3),
131
            LiteralField::create('AdvancedIntro', _t(
132
                'FoxyStripeSiteConfig.AdvancedIntro',
133
                '<p>Maps to data in your <a href="https://admin.foxycart.com/admin.php?ThisAction=EditAdvancedFeatures"
134
                     target="_blank">FoxyCart advanced store settings</a>.</p>'
135
            )),
136
            ReadonlyField::create(
137
                'DataFeedLink',
138
                _t('FoxyStripeSiteConfig.DataFeedLink', 'FoxyCart DataFeed URL'),
139
                self::getDataFeedLink()
140
            )->setDescription(_t('FoxyStripeSiteConfig.DataFeedLinkDescription', 'copy/paste to FoxyCart')),
141
            CheckboxField::create('CartValidation')
142
                ->setTitle(_t('FoxyStripeSiteConfig.CartValidation', 'Enable Cart Validation'))
143
                ->setDescription(_t(
144
                    'FoxyStripeSiteConfig.CartValidationDescription',
145
                    'You must
146
                    <a href="https://admin.foxycart.com/admin.php?ThisAction=EditAdvancedFeatures#use_cart_validation"
147
                        target="_blank">enable cart validation</a> in the FoxyCart admin.'
148
            )),
149
            ReadonlyField::create('StoreKey')
150
                ->setTitle(_t('FoxyStripeSiteConfig.StoreKey', 'FoxyCart API Key'))
151
                ->setDescription(_t('FoxyStripeSiteConfig.StoreKeyDescription', 'copy/paste to FoxyCart')),
152
            ReadonlyField::create('SSOLink', _t(
153
            'FoxyStripeSiteConfig.SSOLink',
154
            'Single Sign On URL'), self::getSSOLink()
155
            )
156
                ->setDescription(_t('FoxyStripeSiteConfig.SSOLinkDescription', 'copy/paste to FoxyCart'))
157
            */
158
        ));
159
160 1
        $fields->addFieldsToTab('Root.FoxyStripe.Advanced', [
161 1
            HeaderField::create('AdvanceHeader', _t(
162 1
                'FoxyStripeSiteConfig.AdvancedHeader',
163 1
                'Advanced Settings'
164 1
            ), 3),
165 1
            LiteralField::create('AdvancedIntro', _t(
166 1
                'FoxyStripeSiteConfig.AdvancedIntro',
167 1
                '<p>Maps to data in your 
168
                    <a href="https://admin.foxycart.com/admin.php?ThisAction=EditAdvancedFeatures" target="_blank">
169
                        FoxyCart advanced store settings
170
                    </a>.</p>'
171
            )),
172 1
            DropdownField::create('CheckoutType', 'Checkout Type', $this->getCheckoutTypes()),
173 1
            CheckboxField::create('BccEmail', 'BCC Admin Email')
174 1
                ->setDescription('bcc all receipts to store\'s email address'),
175 1
            CheckboxField::create('UseWebhook', 'Use Webhook')
176 1
                ->setDescription('record order history in CMS, allows customers to view their order history'),
177 1
            ReadonlyField::create('WebhookURL', 'Webhook URL', self::getDataFeedLink()),
178 1
            ReadonlyField::create('StoreKey', 'Webhook Key', self::getDataFeedLink()),
179 1
            CheckboxField::create('CartValidation', 'Use cart validation'),
180 1
            CheckboxField::create('UseSingleSignOn', 'Use single sign on')
181 1
                ->setDescription('Sync user accounts between FoxyCart and your website'),
182 1
            ReadonlyField::create('SingleSignOnURL', 'Single sign on URL', self::getSSOLink()),
183 1
            CheckboxField::create('AllowMultiship', 'Allow multiple shipments per order'),
184
        ]);
185
186
        // configuration warning
187 1
        if (FoxyCart::store_name_warning() !== null) {
188 1
            $fields->insertBefore(LiteralField::create(
189 1
                'StoreSubDomainHeaderWarning',
190 1
                _t(
191 1
                    'FoxyStripeSiteConfig.StoreSubDomainHeadingWarning',
192 1
                    '<p class="message error">Store sub-domain must be entered in the <a href="/admin/settings/">
193
                            site settings
194
                        </a></p>'
195
                )
196 1
            ), 'StoreDetails');
0 ignored issues
show
Bug introduced by
'StoreDetails' of type string is incompatible with the type SilverStripe\Forms\FormField expected by parameter $item of SilverStripe\Forms\FieldList::insertBefore(). ( Ignorable by Annotation )

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

196
            ), /** @scrutinizer ignore-type */ 'StoreDetails');
Loading history...
197
        }
198
199
        // products tab
200 1
        $fields->addFieldsToTab('Root.FoxyStripe.Products', array(
201 1
            HeaderField::create('ProductHeader', _t(
202 1
                'FoxyStripeSiteConfig.ProductHeader',
203 1
                'Products'
204 1
            ), 3),
205 1
            CheckboxField::create('MultiGroup')
206 1
                ->setTitle(_t('FoxyStripeSiteConfig.MultiGroup', 'Multiple Groups'))
207 1
                ->setDescription(_t(
208 1
                    'FoxyStripeSiteConfig.MultiGroupDescription',
209 1
                    'Allows products to be shown in multiple Product Groups'
210
                )),
211 1
            HeaderField::create('ProductGroupHD', _t(
212 1
                'FoxyStripeSiteConfig.ProductGroupHD',
213 1
                'Product Groups'
214 1
            ), 3),
215 1
            NumericField::create('ProductLimit')
216 1
                ->setTitle(_t('FoxyStripeSiteConfig.ProductLimit', 'Products per Page'))
217 1
                ->setDescription(_t(
218 1
                    'FoxyStripeSiteConfig.ProductLimitDescription',
219 1
                    'Number of Products to show per page on a Product Group'
220
                )),
221 1
            HeaderField::create('ProductQuantityHD', _t(
222 1
                'FoxyStripeSiteConfig.ProductQuantityHD',
223 1
                'Product Form Max Quantity'
224 1
            ), 3),
225 1
            NumericField::create('MaxQuantity')
226 1
                ->setTitle(_t('FoxyStripeSiteConfig.MaxQuantity', 'Max Quantity'))
227 1
                ->setDescription(_t(
228 1
                    'FoxyStripeSiteConfig.MaxQuantityDescription',
229 1
                    'Sets max quantity for product form dropdown (add to cart form - default 10)'
230
                )),
231
        ));
232
233
        // categories tab
234 1
        $fields->addFieldsToTab('Root.FoxyStripe.Categories', array(
235 1
            HeaderField::create('CategoryHD', _t('FoxyStripeSiteConfig.CategoryHD', 'FoxyStripe Categories'), 3),
236 1
            LiteralField::create('CategoryDescrip', _t(
237 1
                'FoxyStripeSiteConfig.CategoryDescrip',
238 1
                '<p>FoxyCart Categories offer a way to give products additional behaviors that cannot be 
239
                        accomplished by product options alone, including category specific coupon codes, 
240
                        shipping and handling fees, and email receipts. 
241
                        <a href="https://wiki.foxycart.com/v/2.0/categories" target="_blank">
242
                            Learn More
243
                        </a></p>
244
                        <p>Categories you\'ve created in FoxyStripe must also be created in your 
245
                            <a href="https://admin.foxycart.com/admin.php?ThisAction=ManageProductCategories" 
246
                                target="_blank">FoxyCart Categories</a> admin panel.</p>'
247
            )),
248 1
            GridField::create(
249 1
                'ProductCategory',
250 1
                _t('FoxyStripeSiteConfig.ProductCategory', 'FoxyCart Categories'),
251 1
                ProductCategory::get(),
0 ignored issues
show
Bug introduced by
Dynamic\FoxyStripe\Model\ProductCategory::get() of type SilverStripe\ORM\DataList 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

251
                /** @scrutinizer ignore-type */ ProductCategory::get(),
Loading history...
252 1
                GridFieldConfig_RecordEditor::create()
253
            ),
254
        ));
255
256
        // option groups tab
257 1
        $fields->addFieldsToTab('Root.FoxyStripe.Groups', array(
258 1
            HeaderField::create('OptionGroupsHead', _t('FoxyStripeSiteConfig', 'Product Option Groups'), 3),
259 1
            LiteralField::create('OptionGroupsDescrip', _t(
260 1
                'FoxyStripeSiteConfig.OptionGroupsDescrip',
261 1
                '<p>Product Option Groups allow you to name a set of product options.</p>'
262
            )),
263 1
            GridField::create(
264 1
                'OptionGroup',
265 1
                _t('FoxyStripeSiteConfig.OptionGroup', 'Product Option Groups'),
266 1
                OptionGroup::get(),
267 1
                GridFieldConfig_RecordEditor::create()
268
            ),
269
        ));
270
271
        // api tab
272 1
        $fields->addFieldsToTab('Root.FoxyStripe.API', [
273 1
            HeaderField::create('APIHD', 'FoxyCart API Settings', 3),
274 1
            TextField::create('client_id', 'FoxyCart Client ID'),
275 1
            TextField::create('client_secret', 'FoxyCart Client Secret'),
276 1
            TextField::create('access_token', 'FoxyCart Access Token'),
277 1
            TextField::create('refresh_token', 'FoxyCart Refresh Token'),
278
        ]);
279
    }
280
281
    /**
282
     * @return string
283
     */
284 2
    private static function getSSOLink()
285
    {
286 2
        return Director::absoluteBaseURL().'foxystripe/sso/';
287
    }
288
289
    /**
290
     * @return string
291
     */
292 2
    private static function getDataFeedLink()
293
    {
294 2
        return Director::absoluteBaseURL().'foxystripe/';
295
    }
296
297
    /**
298
     * generate key on install.
299
     *
300
     * @throws \SilverStripe\ORM\ValidationException
301
     */
302 3
    public function requireDefaultRecords()
303
    {
304 3
        parent::requireDefaultRecords();
305
306 3
        $siteConfig = SiteConfig::current_site_config();
307
308 3
        if (!$siteConfig->StoreKey) {
309 3
            $key = FoxyCart::setStoreKey();
310 3
            while (!ctype_alnum($key)) {
311
                $key = FoxyCart::setStoreKey();
312
            }
313 3
            $siteConfig->StoreKey = $key;
314 3
            $siteConfig->write();
315 3
            DB::alteration_message($siteConfig->ClassName.': created FoxyCart Store Key '.$key, 'created');
316
        }
317
    }
318
319
    /**
320
     * @return array
321
     */
322 1
    public function getCheckoutTypes()
323
    {
324
        return [
325 1
            'default_account' => 'Allow guest and customer accounts, default to account',
326
            'default_guest' => 'Allow guest and customer accounts, default to guest',
327
            'account_only' => 'Allow customer accounts only',
328
            'guest_only' => 'Allow guests only',
329
        ];
330
    }
331
332
    /**
333
     * @return array
334
     */
335 1
    public function getDataMap()
336
    {
337
        return [
338 1
            'store_name' => $this->owner->StoreTitle,
339 1
            'store_domain' => $this->owner->StoreName,
340 1
            'store_url' => $this->owner->StoreURL,
341 1
            'receipt_continue_url' => $this->owner->ReceiptURL,
342 1
            'store_email' => $this->owner->StoreEmail,
343 1
            'from_email' => $this->owner->FromEmail,
344 1
            'postal_code' => $this->owner->StorePostalCode,
345 1
            'country' => $this->owner->StoreCountry,
346 1
            'region' => $this->owner->StoreRegion,
347 1
            'locale_code' => $this->owner->StoreLocaleCode,
348 1
            'logo_url' => $this->owner->StoreLogoURL,
349 1
            'checkout_type' => $this->owner->CheckoutType,
350 1
            'bcc_on_receipt_email' => $this->owner->BccEmail,
351 1
            'use_webhook' => $this->owner->UseWebhook,
352 1
            'webhook_url' => $this->getDataFeedLink(),
353 1
            'webhook_key' => $this->owner->StoreKey,
354 1
            'use_cart_validation' => $this->owner->CartValidation,
355 1
            'use_single_sign_on' => $this->owner->UseSingleSignOn,
356 1
            'single_sign_on_url' => $this->getSSOLink(),
357 1
            'customer_password_hash_type' => 'sha1_salted_suffix',
358 1
            'customer_password_hash_config' => 40,
359 1
            'features_multiship' => $this->owner->AllowMultiship,
360
            //'timezone' => $this->StoreTimezone,
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...
361
        ];
362
    }
363
364
    /**
365
     * if StoreTitle is empty, grab values from FoxyCart.
366
     *
367
     * example of 2 way sync for future reference
368
     *
369
     * @throws \Psr\Container\NotFoundExceptionInterface
370
     */
371 49
    public function onBeforeWrite()
372
    {
373 49
        parent::onBeforeWrite();
374
375 49
        if ($this->owner->ID && !$this->owner->StoreTitle && $this->owner->access_token) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
376
            /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% 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...
377
            if ($fc = new FoxyStripeClient()) {
378
                $client = $fc->getClient();
379
                $errors = [];
380
381
                $result = $client->get($fc->getCurrentStore());
382
                $this->owner->StoreTitle = $result['store_name'];
383
384
                $errors = array_merge($errors, $client->getErrors($result));
385
                if (count($errors)) {
386
                    Injector::inst()->get(LoggerInterface::class)
387
                        ->error('FoxyStripeSiteConfig::onBeforeWrite errors - ' . json_encode($errors));
388
                }
389
            }
390
            */
391
        }
392
    }
393
394
    /**
395
     * @throws \Psr\Container\NotFoundExceptionInterface
396
     */
397 49
    public function onAfterWrite()
398
    {
399 49
        parent::onAfterWrite();
400
401 49
        if ($this->owner->isChanged() && $this->owner->access_token) {
402
            if ($fc = new FoxyStripeClient()) {
403
                $fc->updateStore($this->getDataMap());
404
            }
405
        }
406
    }
407
}
408