Completed
Push — master ( 613b2e...a2195f )
by Nicolaas
03:28
created

CartPage_Controller::workOutMessagesAndActions()   F

Complexity

Conditions 60
Paths > 20000

Size

Total Lines 169
Code Lines 84

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 60
dl 0
loc 169
rs 2
c 0
b 0
f 0
eloc 84
nc 11664001
nop 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @description: This is a page that shows the cart content,
5
 * without "leading to" checking out. That is, there is no "next step" functionality
6
 * or a way to submit the order.
7
 * NOTE: both the Account and the Checkout Page extend from this class as they
8
 * share some functionality.
9
 *
10
 *
11
 * @authors: Nicolaas [at] Sunny Side Up .co.nz
12
 * @package: ecommerce
13
 * @sub-package: Pages
14
 * @inspiration: Silverstripe Ltd, Jeremy
15
 **/
16
class CartPage extends Page
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
17
{
18
    /**
19
     * Standard SS variable.
20
     *
21
     * @var string
22
     */
23
    private static $icon = 'ecommerce/images/icons/CartPage';
0 ignored issues
show
Unused Code introduced by
The property $icon is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
24
25
    /**
26
     * Standard SS variable.
27
     *
28
     * @var array
29
     */
30
    private static $db = array(
0 ignored issues
show
Unused Code introduced by
The property $db is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
31
        'ContinueShoppingLabel' => 'Varchar(100)',
32
        'ProceedToCheckoutLabel' => 'Varchar(100)',
33
        'ShowAccountLabel' => 'Varchar(100)',
34
        'CurrentOrderLinkLabel' => 'Varchar(100)',
35
        'LoginToOrderLinkLabel' => 'Varchar(100)',
36
        'SaveOrderLinkLabel' => 'Varchar(100)',
37
        'LoadOrderLinkLabel' => 'Varchar(100)',
38
        'DeleteOrderLinkLabel' => 'Varchar(100)',
39
        'NoItemsInOrderMessage' => 'HTMLText',
40
        'NonExistingOrderMessage' => 'HTMLText',
41
    );
42
43
    /**
44
     * Standard SS variable.
45
     *
46
     * @var array
47
     */
48
    private static $defaults = array(
0 ignored issues
show
Unused Code introduced by
The property $defaults is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
49
        'ContinueShoppingLabel' => 'continue shopping',
50
        'ProceedToCheckoutLabel' => 'proceed to checkout',
51
        'ShowAccountLabel' => 'view account details',
52
        'CurrentOrderLinkLabel' => 'view current order',
53
        'LoginToOrderLinkLabel' => 'you must log in to view this order',
54
        'SaveOrderLinkLabel' => 'save current order',
55
        'DeleteOrderLinkLabel' => 'delete this order',
56
        'LoadOrderLinkLabel' => 'finalise this order',
57
        'NoItemsInOrderMessage' => '<p>You do not have any items in your current order.</p>',
58
        'NonExistingOrderMessage' => '<p>Sorry, the order you are trying to open does not exist.</p>',
59
    );
60
61
    /**
62
     * Standard SS variable.
63
     *
64
     * @var array
65
     */
66
    private static $casting = array(
0 ignored issues
show
Unused Code introduced by
The property $casting is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
67
        'MenuTitle' => 'HTMLVarchar',
68
    );
69
70
    /**
71
     * Standard SS variable.
72
     */
73
    private static $singular_name = 'Cart Page';
0 ignored issues
show
Unused Code introduced by
The property $singular_name is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
74
    public function i18n_singular_name()
75
    {
76
        return _t('CartPage.SINGULARNAME', 'Cart Page');
77
    }
78
79
    /**
80
     * Standard SS variable.
81
     */
82
    private static $plural_name = 'Cart Pages';
0 ignored issues
show
Unused Code introduced by
The property $plural_name is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
83
    public function i18n_plural_name()
84
    {
85
        return _t('CartPage.PLURALNAME', 'Cart Pages');
86
    }
87
88
    /**
89
     * Standard SS variable.
90
     *
91
     * @var string
92
     */
93
    private static $description = 'A page where the customer can view the current order (cart) without finalising the order.';
0 ignored issues
show
Unused Code introduced by
The property $description is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
94
95
    /***
96
     * override core function to turn "checkout" into "Checkout (1)"
97
     * @return DBField
98
     */
99
    public function obj($fieldName, $arguments = null, $forceReturnedObject = true, $cache = false, $cacheName = null)
100
    {
101
        if ($fieldName == 'MenuTitle' && !($this instanceof OrderConfirmationPage)) {
102
            return DBField::create_field('HTMLVarchar', strip_tags($this->EcommerceMenuTitle()), 'MenuTitle', $this);
103
        } else {
104
            return parent::obj($fieldName);
105
        }
106
    }
107
108
    /**
109
     * Standard SS function, we only allow for one CartPage page to exist
110
     * but we do allow for extensions to exist at the same time.
111
     *
112
     * @param Member $member
0 ignored issues
show
Documentation introduced by
Should the type for parameter $member not be Member|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
113
     *
114
     * @return bool
115
     */
116
    public function canCreate($member = null)
117
    {
118
        return CartPage::get()->Filter(array('ClassName' => 'CartPage'))->Count() ? false : $this->canEdit($member);
119
    }
120
121
    /**
122
     * Shop Admins can edit.
123
     *
124
     * @param Member $member
0 ignored issues
show
Documentation introduced by
Should the type for parameter $member not be Member|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
125
     *
126
     * @return bool
127
     */
128
    public function canEdit($member = null)
129
    {
130
        if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) {
131
            return true;
132
        }
133
134
        return parent::canEdit($member);
135
    }
136
137
    /**
138
     * Standard SS method.
139
     *
140
     * @param Member $member
0 ignored issues
show
Documentation introduced by
Should the type for parameter $member not be Member|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
141
     *
142
     * @return bool
143
     */
144
    public function canDelete($member = null)
145
    {
146
        return $this->canEdit($member);
147
    }
148
149
    /**
150
     * Standard SS method.
151
     *
152
     * @param Member $member
0 ignored issues
show
Documentation introduced by
Should the type for parameter $member not be Member|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
153
     *
154
     * @return bool
155
     */
156
    public function canPublish($member = null)
157
    {
158
        return $this->canEdit($member);
159
    }
160
161
    /**
162
     *@return FieldList
163
     **/
164
    public function getCMSFields()
165
    {
166
        $fields = parent::getCMSFields();
167
        $fields->addFieldsToTab(
168
            'Root.Messages',
169
            array(
170
                new TabSet(
171
                    'Messages',
172
                    Tab::create(
173
                        'Actions',
174
                        _t('CartPage.ACTIONS', 'Actions'),
175
                        new TextField('ContinueShoppingLabel', _t('CartPage.CONTINUESHOPPINGLABEL', 'Label on link to continue shopping - e.g. click here to continue shopping')),
176
                        new TextField('ProceedToCheckoutLabel', _t('CartPage.PROCEEDTOCHECKOUTLABEL', 'Label on link to proceed to checkout - e.g. click here to finalise your order')),
177
                        new TextField('ShowAccountLabel', _t('CartPage.SHOWACCOUNTLABEL', 'Label on the link \'view account details\' - e.g. click here to view your account details')),
178
                        new TextField('CurrentOrderLinkLabel', _t('CartPage.CURRENTORDERLINKLABEL', 'Label for the link pointing to the current order - e.g. click here to view current order')),
179
                        new TextField('LoginToOrderLinkLabel', _t('CartPage.LOGINTOORDERLINKLABEL', 'Label for the link pointing to the order which requires a log in - e.g. you must login to view this order')),
180
                        new TextField('SaveOrderLinkLabel', _t('CartPage.SAVEORDERLINKLABEL', 'Label for the saving an order - e.g. click here to save current order')),
181
                        new TextField('LoadOrderLinkLabel', _t('CartPage.LOADORDERLINKLABEL', 'Label for the loading an order into the cart - e.g. click here to finalise this order')),
182
                        new TextField('DeleteOrderLinkLabel', _t('CartPage.DELETEORDERLINKLABEL', 'Label for the deleting an order - e.g. click here to delete this order'))
183
                    ),
184
                    Tab::create(
185
                        'Errors',
186
                        _t('CartPage.ERRORS', 'Errors'),
187
                        $htmlEditorField1 = new HTMLEditorField('NoItemsInOrderMessage', _t('CartPage.NOITEMSINORDERMESSAGE', 'No items in order - shown when the customer tries to view an order without items.')),
188
                        $htmlEditorField2 = new HTMLEditorField('NonExistingOrderMessage', _t('CartPage.NONEXISTINGORDERMESSAGE', 'Non-existing Order - shown when the customer tries to load a non-existing order.'))
189
                    )
190
                ),
191
            )
192
        );
193
        $htmlEditorField1->setRows(3);
194
        $htmlEditorField2->setRows(3);
195
196
        return $fields;
197
    }
198
199
    /**
200
     * Returns the Link to the CartPage on this site.
201
     *
202
     * @return string (URLSegment)
203
     */
204
    public static function find_link()
205
    {
206
        $page = CartPage::get()->Filter(array('ClassName' => 'CartPage'))->First();
207
        if ($page) {
208
            return $page->Link();
209
        } else {
210
            return CheckoutPage::find_link();
211
        }
212
    }
213
214
    /**
215
     * Returns the "new order" link.
216
     *
217
     * @param int | String $orderID - not used in CartPage
218
     *
219
     * @return string (URLSegment)
220
     */
221
    public static function new_order_link($orderID)
222
    {
223
        return self::find_link().'startneworder/';
224
    }
225
226
    /**
227
     * Returns the "copy order" link.
228
     *
229
     * @param int | String $orderID - not used in CartPage
230
     *
231
     * @return string (URLSegment)
232
     */
233
    public static function copy_order_link($orderID)
234
    {
235
        return OrderConfirmationPage::find_link().'copyorder/'.$orderID.'/';
236
    }
237
238
    /**
239
     * Return a link to view the order on this page.
240
     *
241
     * @param int|string $orderID ID of the order
242
     *
243
     * @return int | String (URLSegment)
0 ignored issues
show
Documentation introduced by
Should the return type not be string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
244
     */
245
    public static function get_order_link($orderID)
246
    {
247
        return self::find_link().'showorder/'.$orderID.'/';
248
    }
249
250
    /**
251
     * Return a link to view the order on this page.
252
     *
253
     * @param int|string $orderID ID of the order
254
     *
255
     * @return string (URLSegment)
256
     */
257
    public function getOrderLink($orderID)
258
    {
259
        return self::get_order_link($orderID);
260
    }
261
262
    /**
263
     * tells us if the current page is part of e-commerce.
264
     *
265
     * @return bool
266
     */
267
    public function IsEcommercePage()
268
    {
269
        return true;
270
    }
271
272
    /**
273
     *@return string (HTML Snippet)
274
     **/
275
    public function EcommerceMenuTitle()
276
    {
277
        $count = 0;
0 ignored issues
show
Unused Code introduced by
$count is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
278
        $order = ShoppingCart::current_order();
279
        if ($order) {
280
            $count = $order->TotalItems();
281
            $oldSSViewer = Config::inst()->get('SSViewer', 'source_file_comments');
282
            Config::inst()->update('SSViewer', 'source_file_comments', false);
283
            $this->customise(array('Count' => $count, 'OriginalMenuTitle' => $this->MenuTitle));
284
            $s = $this->renderWith('AjaxNumItemsInCart');
285
            Config::inst()->update('SSViewer', 'source_file_comments', $oldSSViewer);
286
287
            return $s;
288
        }
289
290
        return $this->OriginalMenuTitle();
291
    }
292
293
    /**
294
     * The original menu title of the page.
295
     *
296
     * @return string
297
     */
298
    public function OriginalMenuTitle()
299
    {
300
        return $this->MenuTite;
301
    }
302
303
    /***********************
304
     * For use in templates
305
     ***********************/
306
307
    /**
308
     * standard SS method for use in templates.
309
     *
310
     * @return string
311
     */
312
    public function LinkingMode()
313
    {
314
        return parent::LinkingMode().' cartlink cartlinkID_'.$this->ID;
315
    }
316
317
    /**
318
     * standard SS method for use in templates.
319
     *
320
     * @return string
321
     */
322
    public function LinkOrSection()
323
    {
324
        return parent::LinkOrSection().' cartlink';
325
    }
326
327
    /**
328
     * standard SS method for use in templates.
329
     *
330
     * @return string
331
     */
332
    public function LinkOrCurrent()
333
    {
334
        return parent::LinkOrCurrent().' cartlink';
335
    }
336
}
337
338
class CartPage_Controller extends Page_Controller
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
339
{
340
    /**
341
     * @static array
342
     * standard SS variable
343
     * it is important that we list all the options here
344
     */
345
    private static $allowed_actions = array(
0 ignored issues
show
Unused Code introduced by
The property $allowed_actions is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
346
        'saveorder',
347
        'CreateAccountForm',
348
        'retrieveorder',
349
        'loadorder',
350
        'deleteorder',
351
        'startneworder',
352
        'showorder',
353
        'share',
354
        'LoginForm'
355
    );
356
357
    /**
358
     * This ArraList holds DataObjects with a Link and Title each....
359
     *
360
     * @var ArraList
361
     **/
362
    protected $actionLinks = null;
363
364
    /**
365
     * to ensure messages and actions links are only worked out once...
366
     *
367
     * @var Boolean
368
     **/
369
    protected $workedOutMessagesAndActions = false;
370
371
    /**
372
     * order currently being shown on this page.
373
     *
374
     * @var DataObject
375
     **/
376
    protected $currentOrder = null;
377
378
    /**
379
     * Message shown (e.g. no current order, could not find order, order updated, etc...).
380
     *
381
     *@var String
382
     * @todo: check if we need this....!
383
     **/
384
    private $message = '';
385
    public static function set_message($s)
386
    {
387
        $sessionCode = EcommerceConfig::get('CartPage_Controller', 'session_code');
388
        Session::set($sessionCode, $s);
389
    }
390
391
    /**
392
     * show the order even if canView returns false.
393
     *
394
     * @var bool
395
     */
396
    protected $overrideCanView = false;
397
398
    /**
399
     * @standard SS method
400
     */
401
    public function init()
0 ignored issues
show
Coding Style introduced by
init uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
402
    {
403
        HTTP::set_cache_age(0);
404
        parent::init();
405
        // find the current order if any
406
        $orderID = 0;
0 ignored issues
show
Unused Code introduced by
$orderID is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
407
        //WE HAVE THIS FOR SUBMITTING FORMS!
408
        if (isset($_REQUEST['OrderID'])) {
409
            $orderID = intval($_REQUEST['OrderID']);
410
            if ($orderID) {
411
                $this->currentOrder = Order::get()->byID($orderID);
412
            }
413
        } elseif ($this->request && $this->request->param('ID') && $this->request->param('Action')) {
414
            //we can not do intval here!
415
            $id = $this->request->param('ID');
416
            $action = $this->request->param('Action');
417
            $otherID = intval($this->request->param('OtherID'));
418
            //the code below is for submitted orders, but we still put it here so
419
            //we can do all the retrieval options in once.
420
            if (($action == 'retrieveorder') && $id && $otherID) {
421
                $sessionID = Convert::raw2sql($id);
422
                $retrievedOrder = Order::get()
423
                    ->Filter(array(
424
                        'SessionID' => $sessionID,
425
                        'ID' => $otherID,
426
                    ))
427
                    ->First();
428
                $this->currentOrder = $retrievedOrder;
429
                $this->overrideCanView = true;
430
            } elseif (intval($id) && in_array($action, $this->stat('allowed_actions'))) {
431
                $this->currentOrder = Order::get()->byID(intval($id));
432
            }
433
        }
434
        if (!$this->currentOrder) {
435
            $this->currentOrder = ShoppingCart::current_order();
436
            if ($this->currentOrder) {
437
                if ($this->currentOrder->IsSubmitted()) {
438
                    $this->overrideCanView = true;
439
                }
440
            }
441
        }
442
        //redirect if we are viewing the order with the wrong page!
443
        if ($this->currentOrder) {
444
            if ($this->overrideCanView) {
445
                $canView = $this->currentOrder->canOverrideCanView();
0 ignored issues
show
Bug introduced by
The method canOverrideCanView() does not exist on DataObject. Did you maybe mean canView()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
446
            } else {
447
                $canView = $this->currentOrder->canView();
448
            }
449
            //IMPORTANT SECURITY QUESTION!
450
            if ($canView) {
451
                if ($this->currentOrder->IsSubmitted() && $this->onlyShowUnsubmittedOrders()) {
452
                    $this->redirect($this->currentOrder->Link());
453
                } elseif ((!$this->currentOrder->IsSubmitted()) && $this->onlyShowSubmittedOrders()) {
454
                    $this->redirect($this->currentOrder->Link());
455
                }
456
            } else {
457
                if (!$this->LoginToOrderLinkLabel) {
458
                    $this->LoginToOrderLinkLabel = _t('CartPage.LOGINFIRST', 'You will need to log in before you can access the requested order order. ');
459
                }
460
                $messages = array(
461
                    'default' => '<p class="message good">'.$this->LoginToOrderLinkLabel.'</p>',
462
                    'logInAgain' => _t('CartPage.LOGINAGAIN', 'You have been logged out. If you would like to log in again, please do so below.'),
463
                );
464
                Security::permissionFailure($this, $messages);
465
466
                return false;
467
            }
468
            if (!$this->currentOrder->IsSubmitted()) {
469
                //we always want to make sure the order is up-to-date.
470
                $this->currentOrder->init($force = false);
471
                $this->currentOrder->calculateOrderAttributes($force = true);
472
                $this->currentOrder->calculateOrderAttributes($force = true);
473
            }
474
        } else {
475
            $this->message = _t('CartPage.ORDERNOTFOUND', 'Order can not be found.');
476
        }
477
    }
478
479
    /***********************
480
     * Actions
481
     ***********************
482
483
484
485
486
    /**
487
     * shows an order and loads it if it is not submitted.
488
     * @todo: do we still need loadorder controller method????
489
     * @param SS_HTTPRequest
490
     * @return array just so that template shows
491
     **/
492
    public function showorder(SS_HTTPRequest $request)
493
    {
494
        if (!$this->currentOrder) {
495
            $this->message = _t('CartPage.ORDERNOTFOUND', 'Order can not be found.');
496
        } else {
497
            if (!$this->currentOrder->IsSubmitted()) {
498
                $shoppingCart = ShoppingCart::current_order();
499
                if ($shoppingCart->ID != $this->currentOrder->ID) {
500
                    if (ShoppingCart::singleton()->loadOrder($this->currentOrder)) {
501
                        $this->message = _t('CartPage.ORDERHASBEENLOADED', 'Order has been loaded.');
502
                    } else {
503
                        $this->message = _t('CartPage.ORDERNOTLOADED', 'Order could not be loaded.');
504
                    }
505
                }
506
            }
507
        }
508
509
        return array();
510
    }
511
512
    /**
513
     * share an order ...
514
     * @todo: do we still need loadorder controller method????
515
     * @param SS_HTTPRequest
516
     * @return array just so that template shows
517
     **/
518
    public function share(SS_HTTPRequest $request)
519
    {
520
        $codes = Convert::raw2sql($request->param('ID'));
521
        $buyables = explode('-', $codes);
522
        if (count($buyables)) {
523
            $sc = ShoppingCart::singleton();
524
            $order = $sc->currentOrder();
525
            foreach ($buyables as $buyable) {
526
                $details = explode(",", $buyable);
527
                if (count($details) == 3) {
528
                    $className = $details[0];
529
                    $className = class_exists($className) ? $className : null;
530
                    $id = intval($details[1]);
531
                    $quantity = floatval($details[2]);
532
                    if ($className && $id && $quantity) {
533
                        $buyable = $className::get()->byID($id);
534
                        if ($buyable && $buyable->canPurchase()) {
535
                            $sc->addBuyable($buyable, $quantity);
536
                            $sc->setQuantity($buyable, $quantity);
537
                        }
538
                    }
539
                }
540
            }
541
            $order->calculateOrderAttributes(false);
542
            if (! $request->getVar('done')) {
543
                return $this->redirect($this->Link('share/'.$codes).'?done=1');
544
            }
545
        }
546
547
        return array();
548
    }
549
550
    /**
551
     * Loads either the "current order""into the shopping cart.
552
     *
553
     * TO DO: untested
554
     * TO DO: what to do with old order
555
     *
556
     * @param SS_HTTPRequest
557
     *
558
     * @return array
559
     */
560
    public function loadorder(SS_HTTPRequest $request)
561
    {
562
        self::set_message(_t('CartPage.ORDERLOADED', 'Order has been loaded.'));
563
        ShoppingCart::singleton()->loadOrder($this->currentOrder->ID);
564
        $this->redirect($this->Link());
565
566
        return array();
567
    }
568
569
    /**
570
     * save the order to a member. If no member exists then create the member first using the ShopAccountForm.
571
     *
572
     * @param SS_HTTPRequest
573
     *
574
     * @return array
575
     *               TO DO: untested
576
     */
577
    public function saveorder(SS_HTTPRequest $request)
578
    {
579
        $member = Member::currentUser();
580
        if (!$member) {
581
            $this->showCreateAccountForm = true;
582
583
            return array();
584
        }
585
        if ($this->currentOrder && $this->currentOrder->getTotalItems()) {
586
            $this->currentOrder->write();
587
            self::set_message(_t('CartPage.ORDERSAVED', 'Your order has been saved.'));
588
        } else {
589
            self::set_message(_t('CartPage.ORDERCOULDNOTBESAVED', 'Your order could not be saved.'));
590
        }
591
        $this->redirectBack();
592
593
        return array();
594
    }
595
596
    /**
597
     * Delete the currently viewed order.
598
     *
599
     * TO DO: untested
600
     *
601
     * @param SS_HTTPRequest
602
     *
603
     * @return array
604
     */
605
    public function deleteorder(SS_HTTPRequest $request)
606
    {
607
        if (!$this->CurrentOrderIsInCart()) {
608
            if ($this->currentOrder->canDelete()) {
609
                $this->currentOrder->delete();
610
                self::set_message(_t('CartPage.ORDERDELETED', 'Order has been deleted.'));
611
            }
612
        }
613
        self::set_message(_t('CartPage.ORDERNOTDELETED', 'Order could not be deleted.'));
614
615
        return array();
616
    }
617
618
    /**
619
     * Start a new order.
620
     *
621
     * @param SS_HTTPRequest
622
     *
623
     * @return array
624
     *               TO DO: untested
625
     */
626
    public function startneworder(SS_HTTPRequest $request)
627
    {
628
        ShoppingCart::singleton()->clear();
629
        self::set_message(_t('CartPage.NEWORDERSTARTED', 'New order has been started.'));
630
        $this->redirect($this->Link());
631
632
        return array();
633
    }
634
635
    /**
636
     * This returns a ArraList, each dataobject has two vars: Title and Link.
637
     *
638
     * @return ArraList
0 ignored issues
show
Documentation introduced by
Should the return type not be ArraList|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
639
     **/
640
    public function ActionLinks()
641
    {
642
        $this->workOutMessagesAndActions();
643
        if ($this->actionLinks && $this->actionLinks->count()) {
644
            return $this->actionLinks;
645
        }
646
647
        return;
648
    }
649
650
    /**
651
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be DBField?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
652
     **/
653
    public function Message()
654
    {
655
        $this->workOutMessagesAndActions();
656
        if (!$this->message) {
657
            $sessionCode = EcommerceConfig::get('CartPage_Controller', 'session_code');
658
            if ($sessionMessage = Session::get($sessionCode)) {
659
                $this->message = $sessionMessage;
660
                Session::set($sessionCode, '');
661
                Session::clear($sessionCode);
662
            }
663
        }
664
        $field = DBField::create_field('HTMLText', $this->message);
665
666
        return $field;
667
    }
668
669
    /**
670
     * @return DataObject | Null - Order
671
     **/
672
    public function Order()
673
    {
674
        return $this->currentOrder;
675
    }
676
677
    /**
678
     * @return bool
679
     **/
680
    public function CanEditOrder()
681
    {
682
        if ($this->currentOrder) {
683
            if ($this->currentOrder->canEdit()) {
684
                if ($this->currentOrder->getTotalItems()) {
685
                    return true;
686
                }
687
            }
688
        }
689
690
        return false;
691
    }
692
693
    /**
694
     * Tells you if the order you are viewing at the moment is also in the cart.
695
     *
696
     * @return bool
697
     **/
698
    public function CurrentOrderIsInCart()
699
    {
700
        $viewingRealCurrentOrder = false;
701
        $realCurrentOrder = ShoppingCart::current_order();
702
        if ($this->currentOrder && $realCurrentOrder) {
703
            if ($realCurrentOrder->ID == $this->currentOrder->ID) {
704
                $viewingRealCurrentOrder = true;
705
            }
706
        }
707
708
        return $viewingRealCurrentOrder;
709
    }
710
711
    /**
712
     * @var bool
713
     */
714
    protected $showCreateAccountForm = false;
715
716
    /**
717
     * Do we need to show the Create Account Form?
718
     *
719
     * @return bool
720
     */
721
    public function ShowCreateAccountForm()
722
    {
723
        if (Session::get('CartPageCreateAccountForm')) {
724
            Session::set('CartPageCreateAccountForm', false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
725
726
            return true;
727
        }
728
        if (Member::currentUser() || $this->currentOrder->MemberID) {
729
            return false;
730
        } else {
731
            Session::set('CartPageCreateAccountForm', true);
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
732
733
            return true;
734
        }
735
    }
736
737
    /**
738
     * Returns the CreateAccountForm.
739
     *
740
     * @return ShopAccountForm
741
     */
742
    public function CreateAccountForm()
743
    {
744
        return ShopAccountForm::create($this, 'CreateAccountForm');
745
    }
746
747
    /**
748
     * work out the options for the user.
749
     **/
750
    protected function workOutMessagesAndActions()
751
    {
752
        if (!$this->workedOutMessagesAndActions) {
753
            $this->actionLinks = new ArrayList(array());
0 ignored issues
show
Documentation Bug introduced by
It seems like new \ArrayList(array()) of type object<ArrayList> is incompatible with the declared type object<ArraList> of property $actionLinks.

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...
754
            //what order are we viewing?
755
            $viewingRealCurrentOrder = $this->CurrentOrderIsInCart();
756
            $currentUserID = Member::currentUserID();
757
758
            //Continue Shopping
759
            if (isset($this->ContinueShoppingLabel) && $this->ContinueShoppingLabel) {
760
                if ($viewingRealCurrentOrder) {
761
                    if ($this->isCartPage()) {
762
                        $continueLink = $this->ContinueShoppingLink();
763
                        if ($continueLink) {
764
                            $this->actionLinks->push(
765
                                ArrayData::create(
766
                                    array(
767
                                        'Title' => $this->ContinueShoppingLabel,
768
                                        'Link' => $continueLink,
769
                                    )
770
                                )
771
                            );
772
                        }
773
                    }
774
                }
775
            }
776
777
            //Proceed To CheckoutLabel
778
            if (isset($this->ProceedToCheckoutLabel) && $this->ProceedToCheckoutLabel) {
779
                if ($viewingRealCurrentOrder) {
780
                    if ($this->isCartPage()) {
781
                        $checkoutPageLink = CheckoutPage::find_link();
782
                        if ($checkoutPageLink && $this->currentOrder && $this->currentOrder->getTotalItems()) {
783
                            $this->actionLinks->push(new ArrayData(array(
784
                                'Title' => $this->ProceedToCheckoutLabel,
785
                                'Link' => $checkoutPageLink,
786
                            )));
787
                        }
788
                    }
789
                }
790
            }
791
792
            //view account details
793
            if (isset($this->ShowAccountLabel) && $this->ShowAccountLabel) {
794
                if ($this->isOrderConfirmationPage() || $this->isCartPage()) {
795
                    if (AccountPage::find_link()) {
796
                        if ($currentUserID) {
797
                            $this->actionLinks->push(new ArrayData(array(
798
                                'Title' => $this->ShowAccountLabel,
799
                                'Link' => AccountPage::find_link(),
800
                            )));
801
                        }
802
                    }
803
                }
804
            }
805
            //go to current order
806
            if (isset($this->CurrentOrderLinkLabel) && $this->CurrentOrderLinkLabel) {
807
                if ($this->isCartPage()) {
808
                    if (!$viewingRealCurrentOrder) {
809
                        $this->actionLinks->push(new ArrayData(array(
810
                            'Title' => $this->CurrentOrderLinkLabel,
811
                            'Link' => ShoppingCart::current_order()->Link(),
812
                        )));
813
                    }
814
                }
815
            }
816
817
            //Save order - we assume only current ones can be saved.
818
            if (isset($this->SaveOrderLinkLabel) && $this->SaveOrderLinkLabel) {
819
                if ($viewingRealCurrentOrder) {
820
                    if ($currentUserID && $this->currentOrder->MemberID == $currentUserID) {
821
                        if ($this->isCartPage()) {
822
                            if ($this->currentOrder && $this->currentOrder->getTotalItems() && !$this->currentOrder->IsSubmitted()) {
823
                                $this->actionLinks->push(new ArrayData(array(
824
                                    'Title' => $this->SaveOrderLinkLabel,
825
                                    'Link' => $this->Link('saveorder').'/'.$this->currentOrder->ID.'/',
826
                                )));
827
                            }
828
                        }
829
                    }
830
                }
831
            }
832
833
            //load order
834
            if (isset($this->LoadOrderLinkLabel) && $this->LoadOrderLinkLabel) {
835
                if ($this->isCartPage() && $this->currentOrder) {
836
                    if (!$viewingRealCurrentOrder) {
837
                        $this->actionLinks->push(new ArrayData(array(
838
                            'Title' => $this->LoadOrderLinkLabel,
839
                            'Link' => $this->Link('loadorder').'/'.$this->currentOrder->ID.'/',
840
                        )));
841
                    }
842
                }
843
            }
844
845
            //delete order
846
            if (isset($this->DeleteOrderLinkLabel) && $this->DeleteOrderLinkLabel) {
847
                if ($this->isCartPage() && $this->currentOrder) {
848
                    if (!$viewingRealCurrentOrder) {
849
                        $this->actionLinks->push(new ArrayData(array(
850
                            'Title' => $this->DeleteOrderLinkLabel,
851
                            'Link' => $this->Link('deleteorder').'/'.$this->currentOrder->ID.'/',
852
                        )));
853
                    }
854
                }
855
            }
856
857
            //Start new order
858
            //Strictly speaking this is only part of the
859
            //OrderConfirmationPage but we put it here for simplicity's sake
860
            if (isset($this->StartNewOrderLinkLabel) && $this->StartNewOrderLinkLabel) {
861
                if ($this->isOrderConfirmationPage()) {
862
                    $this->actionLinks->push(new ArrayData(array(
863
                        'Title' => $this->StartNewOrderLinkLabel,
864
                        'Link' => CartPage::new_order_link($this->currentOrder->ID),
865
                    )));
866
                }
867
            }
868
869
            //copy order
870
            //Strictly speaking this is only part of the
871
            //OrderConfirmationPage but we put it here for simplicity's sake
872
            if (isset($this->CopyOrderLinkLabel) && $this->CopyOrderLinkLabel) {
873
                if ($this->isOrderConfirmationPage() && $this->currentOrder->ID) {
874
                    $this->actionLinks->push(new ArrayData(array(
875
                        'Title' => $this->CopyOrderLinkLabel,
876
                        'Link' => OrderConfirmationPage::copy_order_link($this->currentOrder->ID),
877
                    )));
878
                }
879
            }
880
881
            //actions from modifiers
882
            if ($this->isOrderConfirmationPage() && $this->currentOrder->ID) {
883
                $modifiers = $this->currentOrder->Modifiers();
884
                if ($modifiers->count()) {
885
                    foreach ($modifiers as $modifier) {
886
                        $array = $modifier->PostSubmitAction();
887
                        if (is_array($array) && count($array)) {
888
                            $this->actionLinks->push(new ArrayData($array));
889
                        }
890
                    }
891
                }
892
            }
893
894
            //log out
895
            //Strictly speaking this is only part of the
896
            //OrderConfirmationPage but we put it here for simplicity's sake
897
            if (Member::currentUser()) {
898
                if ($this->isOrderConfirmationPage()) {
899
                    $this->actionLinks->push(new ArrayData(array(
900
                        'Title' => _t('CartPage.LOGOUT', 'log out'),
901
                        'Link' => '/Security/logout/',
902
                    )));
903
                }
904
            }
905
906
            //no items
907
            if ($this->currentOrder) {
908
                if (!$this->currentOrder->getTotalItems()) {
909
                    $this->message = $this->NoItemsInOrderMessage;
910
                }
911
            } else {
912
                $this->message = $this->NonExistingOrderMessage;
913
            }
914
915
            $this->workedOutMessagesAndActions = true;
916
            //does nothing at present....
917
        }
918
    }
919
920
    /***********************
921
     * HELPER METHOD (PROTECTED)
922
     ***********************
923
924
925
926
927
928
929
    /**
930
     * Is this a CartPage or is it another type (Checkout / OrderConfirmationPage)?
931
     * @return Boolean
932
     */
933
    protected function isCartPage()
934
    {
935
        if (($this->isCheckoutPage()) || ($this->isOrderConfirmationPage())) {
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return !($this->isChecko...derConfirmationPage());.
Loading history...
936
            return false;
937
        }
938
939
        return true;
940
    }
941
942
    /**
943
     * Is this a CheckoutPage or is it another type (CartPage / OrderConfirmationPage)?
944
     *
945
     * @return bool
946
     */
947
    protected function isCheckoutPage()
948
    {
949
        if ($this->dataRecord instanceof CheckoutPage) {
0 ignored issues
show
Coding Style introduced by
The if-else statement can be simplified to return $this->dataRecord...stanceof \CheckoutPage;.
Loading history...
950
            return true;
951
        } else {
952
            return false;
953
        }
954
    }
955
956
    /**
957
     * Is this a OrderConfirmationPage or is it another type (CartPage / CheckoutPage)?
958
     *
959
     * @return bool
960
     */
961
    protected function isOrderConfirmationPage()
962
    {
963
        if ($this->dataRecord instanceof OrderConfirmationPage) {
0 ignored issues
show
Coding Style introduced by
The if-else statement can be simplified to return $this->dataRecord...\OrderConfirmationPage;.
Loading history...
964
            return true;
965
        } else {
966
            return false;
967
        }
968
    }
969
970
    /**
971
     * Can this page only show Submitted Orders (e.g. OrderConfirmationPage) ?
972
     *
973
     * @return bool
974
     */
975
    protected function onlyShowSubmittedOrders()
976
    {
977
        return false;
978
    }
979
980
    /**
981
     * Can this page only show Unsubmitted Orders (e.g. CartPage) ?
982
     *
983
     * @return bool
984
     */
985
    protected function onlyShowUnsubmittedOrders()
986
    {
987
        return true;
988
    }
989
}
990