Passed
Push — 1.0 ( 024343...5b8585 )
by Morven
10:07
created

ShoppingCart   B

Complexity

Total Complexity 51

Size/Duplication

Total Lines 496
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 177
dl 0
loc 496
rs 7.92
c 0
b 0
f 0
wmc 51

23 Methods

Rating   Name   Duplication   Size   Complexity  
A setDataRecord() 0 4 1
A getShowDiscountForm() 0 3 1
A DiscountForm() 0 25 1
B usediscount() 0 32 8
B doUpdate() 0 36 9
A ShowTax() 0 4 1
A CartForm() 0 17 1
A getMenu() 0 5 2
A getMetaTitle() 0 3 1
A Link() 0 5 1
A index() 0 5 1
A init() 0 14 6
A getTitle() 0 6 2
A remove() 0 25 3
A RelativeLink() 0 5 1
A __construct() 0 8 1
A emptycart() 0 11 1
A checkout() 0 13 2
A doAddDiscount() 0 19 3
A getDataRecord() 0 3 1
A Menu() 0 3 1
A AbsoluteLink() 0 3 1
A PostageForm() 0 21 2

How to fix   Complexity   

Complex Class

Complex classes like ShoppingCart often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ShoppingCart, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace SilverCommerce\ShoppingCart\Control;
4
5
use SilverStripe\i18n\i18n;
6
use SilverStripe\Forms\Form;
7
use SilverStripe\View\SSViewer;
8
use SilverStripe\Forms\FieldList;
9
use SilverStripe\Forms\TextField;
10
use SilverStripe\Control\Director;
11
use SilverStripe\Forms\FormAction;
12
use SilverStripe\Control\Controller;
13
use SilverStripe\ORM\ValidationResult;
14
use SilverStripe\SiteConfig\SiteConfig;
15
use SilverStripe\Core\Injector\Injector;
16
use SilverStripe\Subsites\Model\Subsite;
0 ignored issues
show
Bug introduced by
The type SilverStripe\Subsites\Model\Subsite 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...
17
use SilverStripe\ORM\ValidationException;
18
use SilverCommerce\Checkout\Control\Checkout;
0 ignored issues
show
Bug introduced by
The type SilverCommerce\Checkout\Control\Checkout 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...
19
use SilverCommerce\Postage\Forms\PostageForm;
20
use SilverCommerce\OrdersAdmin\Model\Estimate;
21
use SilverStripe\CMS\Controllers\ContentController;
0 ignored issues
show
Bug introduced by
The type SilverStripe\CMS\Controllers\ContentController 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...
22
use SilverCommerce\ShoppingCart\ShoppingCartFactory;
23
24
/**
25
 * Holder for items in the shopping cart and interacting with them, as
26
 * well as rendering these items into an interface that allows editing
27
 * of items,
28
 *
29
 * @author ilateral (http://www.ilateral.co.uk)
30
 * @package shoppingcart
31
 */
32
class ShoppingCart extends Controller
33
{
34
35
    /**
36
     * URL Used to access this controller
37
     *
38
     * @var string
39
     * @config
40
     */
41
    private static $url_segment = 'shoppingcart';
42
43
    /**
44
     * Setup default templates for this controller
45
     *
46
     * @var array
47
     */
48
    protected $templates = [
49
        "index" => [ShoppingCart::class, "Page"],
50
        "usediscount" => [ShoppingCart::class . "_usediscount", ShoppingCart::class, "Page"]
51
    ];
52
    
53
    /**
54
     * Overwrite the default title for this controller which is taken
55
     * from the translation files. This is used for Title and MetaTitle
56
     * variables in templates.
57
     *
58
     * @var string
59
     * @config
60
     */
61
    private static $title;
62
63
    /**
64
     * Class Name of object we use as an assotiated estimate.
65
     * This defaults to Estimate
66
     *
67
     * @var string
68
     * @config
69
     */
70
    private static $checkout_class = Checkout::class;
71
72
    /**
73
     * Show the discount form on the shopping cart
74
     *
75
     * @var boolean
76
     * @config
77
     */
78
    private static $show_discount_form = false;
79
80
    /**
81
     * Redirect the user to the cart when an item is added?
82
     * 
83
     * @var boolean
84
     */
85
    private static $redirect_on_add = false;
0 ignored issues
show
introduced by
The private property $redirect_on_add is not used, and could be removed.
Loading history...
86
87
    /**
88
     * The associated dataRecord
89
     *
90
     * @var ShoppingCartModel
0 ignored issues
show
Bug introduced by
The type SilverCommerce\ShoppingC...ntrol\ShoppingCartModel 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...
91
     */
92
    protected $dataRecord;
93
94
    /**
95
     * These methods are mapped to sub URLs of this
96
     * controller.
97
     *
98
     * @var array
99
     */
100
    private static $allowed_actions = [
0 ignored issues
show
introduced by
The private property $allowed_actions is not used, and could be removed.
Loading history...
101
        "remove",
102
        "emptycart",
103
        "usediscount",
104
        "setdeliverytype",
105
        "checkout",
106
        "CartForm",
107
        "PostageForm",
108
        "DiscountForm"
109
    ];
110
111
    /**
112
     * Create this controller and attach the relevent ShoppingCart
113
     *
114
     * @return null
115
     */
116
    public function __construct()
117
    {
118
        $dataRecord = ShoppingCartFactory::create()->getCurrent();
119
        $this->setDataRecord($dataRecord);
120
121
        parent::__construct();
122
123
        $this->setFailover($this->dataRecord);
124
    }
125
126
    /**
127
     * Overwrite default init to support subsites (if installed)
128
     * 
129
     * @return void 
130
     */
131
    protected function init()
132
    {
133
        parent::init();
134
135
        # Check for subsites and add support
136
        if (class_exists(Subsite::class)) {
137
            $subsite = Subsite::currentSubsite();
138
139
            if ($subsite && $subsite->Theme) {
140
                SSViewer::add_themes([$subsite->Theme]);
141
            }
142
143
            if ($subsite && i18n::getData()->validate($subsite->Language)) {
144
                i18n::set_locale($subsite->Language);
145
            }
146
        }
147
    }
148
    
149
    public function getTitle()
150
    {
151
        if ($this->config()->title) {
152
            return $this->config()->title;
153
        } else {
154
            _t("SilverCommerce\ShoppingCart.CartName", "Shopping Cart");
155
        }
156
    }
157
158
    public function getMetaTitle()
159
    {
160
        return $this->getTitle();
161
    }
162
163
    public function getShowDiscountForm()
164
    {
165
        return $this->config()->show_discount_form;
166
    }
167
168
    public function getDataRecord()
169
    {
170
        return $this->dataRecord;
171
    }
172
173
    public function setDataRecord($record)
174
    {
175
        $this->dataRecord = $record;
176
        return $this;
177
    }
178
179
    /**
180
     * Get the link to this controller
181
     *
182
     * @param string $action The action you want to add to the link
183
     * @return string
184
     */
185
    public function Link($action = null)
186
    {
187
        return Controller::join_links(
188
            $this->config()->url_segment,
189
            $action
190
        );
191
    }
192
193
    /**
194
     * Get an absolute link to this controller
195
     *
196
     * @param string $action The action you want to add to the link
197
     * @return string
198
     */
199
    public function AbsoluteLink($action = null)
200
    {
201
        return Director::absoluteURL($this->Link($action));
202
    }
203
204
    /**
205
     * Get a relative (to the root url of the site) link to this
206
     * controller
207
     *
208
     * @param string $action The action you want to add to the link
209
     * @return string
210
     */
211
    public function RelativeLink($action = null)
212
    {
213
        return Controller::join_links(
214
            Director::baseURL(),
215
            $this->Link($action)
216
        );
217
    }
218
219
    /**
220
     * If content controller exists, return it's menu function
221
     * @param int $level Menu level to return.
222
     * @return ArrayList
0 ignored issues
show
Bug introduced by
The type SilverCommerce\ShoppingCart\Control\ArrayList 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...
223
     */
224
    public function getMenu($level = 1)
225
    {
226
        if (class_exists(ContentController::class)) {
227
            $controller = ContentController::singleton();
228
            return $controller->getMenu($level);
229
        }
230
    }
231
232
    public function Menu($level)
0 ignored issues
show
Unused Code introduced by
The parameter $level is not used and could be removed. ( Ignorable by Annotation )

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

232
    public function Menu(/** @scrutinizer ignore-unused */ $level)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
233
    {
234
        return $this->getMenu();
235
    }
236
237
    /**
238
     * Default acton for the shopping cart
239
     */
240
    public function index()
241
    {
242
        $this->extend("onBeforeIndex");
243
244
        return $this->render();
245
    }
246
247
    /**
248
     * Remove a product from ShoppingCart Via its ID. This action
249
     * expects an ID to be sent through the URL that matches a specific
250
     * key added to an item in the cart
251
     *
252
     * @return Redirect
0 ignored issues
show
Bug introduced by
The type SilverCommerce\ShoppingCart\Control\Redirect 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...
253
     */
254
    public function remove()
255
    {
256
        $key = $this->request->param('ID');
257
        $item = null;
258
        $title = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $title is dead and can be removed.
Loading history...
259
260
        if (isset($key)) {
261
            $item = $this
262
                ->Items()
0 ignored issues
show
Bug introduced by
The method Items() does not exist on SilverCommerce\ShoppingCart\Control\ShoppingCart. 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

262
                ->/** @scrutinizer ignore-call */ Items()
Loading history...
263
                ->find("Key", $key);
264
        }
265
266
        if (isset($item)) {
267
            $title = $item->Title;
268
            ShoppingCartFactory::create()->removeItem($item);
269
270
            $form = $this->CartForm();
271
            $form->sessionMessage(_t(
272
                "ShoppingCart.RemovedItem",
273
                "Removed '{title}' from your cart",
274
                ["title" => $title]
275
            ));
276
        }
277
278
        return $this->redirectBack();
279
    }
280
    
281
    /**
282
     * Action that will clear shopping cart and associated items
283
     *
284
     */
285
    public function emptycart()
286
    {
287
        ShoppingCartFactory::create()->delete();
288
        
289
        $form = $this->CartForm();
290
        $form->sessionMessage(_t(
291
            "ShoppingCart.EmptiedCart",
292
            "Shopping cart emptied"
293
        ));
294
295
        return $this->redirectBack();
296
    }
297
    
298
    
299
    /**
300
     * Action used to add a discount to the users session via a URL.
301
     * This is preferable to using the dicount form as disount code
302
     * forms seem to provide a less than perfect user experience
303
     *
304
     */
305
    public function usediscount()
306
    {   
307
        $code_to_search = $this->request->param("ID");
308
        $code = false;
309
        $curr = $this->getDiscount();
0 ignored issues
show
Bug introduced by
The method getDiscount() does not exist on SilverCommerce\ShoppingCart\Control\ShoppingCart. 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

309
        /** @scrutinizer ignore-call */ 
310
        $curr = $this->getDiscount();
Loading history...
310
        
311
        if (!$code_to_search) {
312
            return $this->httpError(404, "Page not found");
313
        }
314
        
315
        // First check if the discount is already added (so we don't
316
        // query the DB if we don't have to).
317
        if (!$curr || ($curr && $curr->Code != $code_to_search)) {
318
            $code = Discount::get()
0 ignored issues
show
Bug introduced by
The type SilverCommerce\ShoppingCart\Control\Discount 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...
319
                ->filter("Code", $code_to_search)
320
                ->exclude("Expires:LessThan", date("Y-m-d"))
321
                ->first();
322
            
323
            if ($code) {
324
                $this->setDiscount($code);
0 ignored issues
show
Bug introduced by
The method setDiscount() does not exist on SilverCommerce\ShoppingCart\Control\ShoppingCart. 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

324
                $this->/** @scrutinizer ignore-call */ 
325
                       setDiscount($code);
Loading history...
325
                $this->save();
0 ignored issues
show
Bug introduced by
The method save() does not exist on SilverCommerce\ShoppingCart\Control\ShoppingCart. 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

325
                $this->/** @scrutinizer ignore-call */ 
326
                       save();
Loading history...
326
            }
327
        } elseif ($curr && $code->Code == $code_to_search) {
0 ignored issues
show
Bug introduced by
The property Code does not exist on false.
Loading history...
328
            $code = $this->getDiscount();
329
        }
330
331
        $this->extend("onBeforeUseDiscount");
332
333
        return $this
334
            ->customise([
335
                "Discount" => $code
336
            ])->render();
337
    }
338
339
    /**
340
     * Setup the checkout and redirect to it
341
     *
342
     * @return Redirect
343
     */
344
    public function checkout()
345
    {
346
        if (!class_exists($this->config()->checkout_class)) {
347
            return $this->httpError(404);
348
        }
349
350
        $checkout = Injector::inst()
351
            ->get($this->config()->checkout_class);
352
        $checkout->setEstimate($this->dataRecord);
353
354
        $this->extend("onBeforeCheckout");
355
356
        $this->redirect($checkout->Link());
357
    }
358
    
359
    /**
360
     * Shortcut to checkout config, to allow us to access it via
361
     * templates
362
     *
363
     * @return boolean
364
     */
365
    public function ShowTax()
366
    {
367
        $config = SiteConfig::current_site_config();
368
        return $config->ShowPriceAndTax;
369
    }
370
371
    /**
372
     * Form responsible for listing items in the shopping cart and
373
     * allowing management (such as addition, removal, etc)
374
     *
375
     * @return Form
376
     */
377
    public function CartForm()
378
    {   
379
        $form = Form::create(
380
            $this,
381
            "CartForm",
382
            FieldList::create(),
383
            FieldList::create(
384
                FormAction::create(
385
                    'doUpdate',
386
                    _t('ShoppingCart.UpdateCart', 'Update Cart')
387
                )->addExtraClass('btn btn-info')
388
            )
389
        )->setTemplate("SilverCommerce\ShoppingCart\Forms\Includes\ShoppingCartForm");
390
        
391
        $this->extend("updateCartForm", $form);
392
        
393
        return $form;
394
    }
395
    
396
    /**
397
     * Form that allows you to add a discount code which then gets added
398
     * to the cart's list of discounts.
399
     *
400
     * @return Form
401
     */
402
    public function DiscountForm()
403
    {
404
        $form = Form::create(
405
            $this,
406
            "DiscountForm",
407
            FieldList::create(
408
                TextField::create(
409
                    "DiscountCode",
410
                    _t("ShoppingCart.DiscountCode", "Discount Code")
411
                )->setAttribute(
412
                    "placeholder",
413
                    _t("ShoppingCart.EnterDiscountCode", "Enter a discount code")
414
                )
415
            ),
416
            FieldList::create(
417
                FormAction::create(
418
                    'doAddDiscount',
419
                    _t('ShoppingCart.Add', 'Add')
420
                )->addExtraClass('btn btn-info')
421
            )
422
        );
423
        
424
        $this->extend("updateDiscountForm", $form);
425
        
426
        return $form;
427
    }
428
    
429
    /**
430
     * Form responsible for estimating shipping based on location and
431
     * postal code
432
     *
433
     * @return Form
434
     */
435
    public function PostageForm()
436
    {
437
        if ($this->isDeliverable()) {
0 ignored issues
show
Bug introduced by
The method isDeliverable() does not exist on SilverCommerce\ShoppingCart\Control\ShoppingCart. 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

437
        if ($this->/** @scrutinizer ignore-call */ isDeliverable()) {
Loading history...
438
            $form = PostageForm::create(
439
                $this,
440
                "PostageForm",
441
                $this->dataRecord,
442
                $this->dataRecord->SubTotal,
443
                $this->dataRecord->TotalWeight,
444
                $this->dataRecord->TotalItems
445
            );
446
447
            $form->setLegend(_t(
448
                "SilverCommerce\ShoppingCart.EstimatePostage",
449
                "Estimate Postage"
450
            ));
451
452
            // Extension call
453
            $this->extend("updatePostageForm", $form);
454
455
            return $form;
456
        }
457
    }
458
459
    /**
460
     * Action that will update cart
461
     *
462
     * @param type $data
463
     * @param type $form
0 ignored issues
show
Bug introduced by
The type SilverCommerce\ShoppingCart\Control\type 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...
464
     */
465
    public function doUpdate($data, $form)
466
    {
467
        try {
468
            foreach ($this->Items() as $item) {
469
                foreach ($data as $key => $value) {
470
                    $sliced_key = explode("_", $key);
471
                    if ($sliced_key[0] == "Quantity") {
472
                        if (isset($item) && ($item->Key == $sliced_key[1])) {
473
                            if ($value > 0) {
474
                                ShoppingCartFactory::create()->updateItem(
475
                                    $item,
476
                                    $value
477
                                );
478
                            } else {
479
                                $item->delete();
480
                            }
481
482
                            $form->sessionMessage(
483
                                _t("ShoppingCart.UpdatedShoppingCart", "Shopping cart updated"),
484
                                ValidationResult::TYPE_GOOD
485
                            );
486
                        }
487
                    }
488
                }
489
            }
490
        } catch (ValidationException $e) {
491
            $form->sessionMessage(
492
                $e->getMessage()
493
            );
494
        } catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The type SilverCommerce\ShoppingCart\Control\Exception was not found. Did you mean Exception? If so, make sure to prefix the type with \.
Loading history...
495
            $form->sessionMessage(
496
                $e->getMessage()
497
            );
498
        }
499
        
500
        return $this->redirectBack();
501
    }
502
    
503
    /**
504
     * Action that will find a discount based on the code
505
     *
506
     * @param type $data
507
     * @param type $form
508
     */
509
    public function doAddDiscount($data, $form)
0 ignored issues
show
Unused Code introduced by
The parameter $form is not used and could be removed. ( Ignorable by Annotation )

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

509
    public function doAddDiscount($data, /** @scrutinizer ignore-unused */ $form)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
510
    {
511
        $code_to_search = $data['DiscountCode'];
512
        
513
        // First check if the discount is already added (so we don't
514
        // query the DB if we don't have to).
515
        if ($this->getDiscount()->Code != $code_to_search) {
516
            $code = Discount::get()
517
                ->filter("Code", $code_to_search)
518
                ->exclude("Expires:LessThan", date("Y-m-d"))
519
                ->first();
520
            
521
            if ($code) {
522
                $this->setDiscount($code);
523
                $this->save();
524
            }
525
        }
526
        
527
        return $this->redirectBack();
528
    }
529
}
530