RepeatOrderForm::doSave()   F
last analyzed

Complexity

Conditions 23
Paths 651

Size

Total Lines 112

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 112
rs 0.3877
c 0
b 0
f 0
cc 23
nc 651
nop 3

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
class RepeatOrderForm extends Form
5
{
6
7
    private static $number_of_product_alternatives = 0;
8
9
    public function __construct($controller, $name, $repeatOrderID = 0, $originatingOrder = 0, $showTable = false)
10
    {
11
12
        if ($repeatOrderID) {
13
            $repeatOrder = DataObject::get_one('RepeatOrder', "ID = ".$repeatOrderID);
14
            $items = $repeatOrder->OrderItems();
0 ignored issues
show
Unused Code introduced by
$items 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...
15
        } else {
16
            $repeatOrder = null;
17
        }
18
19
        $fields = RepeatOrderForm::repeatOrderFormFields($repeatOrderID, $originatingOrder, false, $showTable);
20
        $actions = RepeatOrderForm::repeatOrderFormActions('', $repeatOrder);
21
22
        //required fields
23
        $requiredArray = array('Start', 'Period');
24
        $requiredFields = RequiredFields::create($requiredArray);
25
26
        //make form
27
        parent::__construct($controller, $name, $fields, $actions, $requiredFields);
28
        //load data
29
        if ($repeatOrder) {
30
            $this->loadDataFrom(
31
                [
32
                    'Start' => $repeatOrder->Start,
33
                    'End' => $repeatOrder->End,
34
                    'Period' => $repeatOrder->Period,
35
                    'Notes' => $repeatOrder->Notes,
36
                    'PaymentMethod' => $repeatOrder->PaymentMethod,
37
                ]
38
            );
39
        }
40
    }
41
42
    public static function repeatOrderFormFields($repeatOrderID = 0, $originatingOrder = 0, $isCheckout = false, $showTable = false)
43
    {
44
        $order = null;
45
        $repeatOrder = null;
46
        //create vs edit
47
        if ($repeatOrderID) {
48
            $repeatOrder = DataObject::get_one('RepeatOrder', "ID = ".$repeatOrderID);
49
            $items = $repeatOrder->OrderItems();
50
        }
51
52
        if(is_null($repeatOrder) || $isCheckout){
53
            $repeatOrder = null;
54
            if ($originatingOrder) {
55
                $order = Order::get_by_id_if_can_view($originatingOrder);
56
            }
57
            if (!$order) {
58
                $order = ShoppingCart::current_order();
59
            }
60
            if ($order) {
61
                $items = $order->Items();
62
            } else {
63
                $items = null;
64
            }
65
        }
66
67
        //build fields
68
        $fields = FieldList::create();
69
70
        //products!
71
        if ($items) {
72
            // $fields->push(HeaderField::create('ProductsHeader', 'Products'));
73
            if($repeatOrder && $showTable) {
74
                $fields->push(
75
                    LiteralField::create(
76
                        'OverviewTable',
77
                        $repeatOrder->renderWith('RepeatOrder_Order')
78
                    )
79
                );
80
            }
81
            else {
82
                $products = Product::get()->filter(["AllowPurchase" => 1]);
83
                $productsMap = $products->map('ID', 'Title')->toArray();
84
                $arr1 = [0 => "--- Please select ---"] + $productsMap;
0 ignored issues
show
Unused Code introduced by
$arr1 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...
85
                foreach ($productsMap as $id => $title) {
86
                    if ($product = Product::get()->byID($id)) {
87
                        if (!$product->canPurchase()) {
88
                            unset($productsMap[$id]);
89
                        }
90
                    }
91
                }
92
                $j = 0;
93
                foreach ($items as $key => $item) {
0 ignored issues
show
Bug introduced by
The variable $items does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
94
                    $j++;
95
                    $alternativeItemsMap = $productsMap;
96
                    $defaultProductID =  $item->ProductID ? $item->ProductID : $item->BuyableID;
97
                    $itemID = $defaultProductID;
98
                    unset($alternativeItemsMap[$defaultProductID]);
99
                    $fields->push(
100
                        HiddenField::create(
101
                            'Product[ID]['.$itemID.']',
102
                            "Preferred Product #$j",
103
                            $defaultProductID
104
                        )
105
                    );
106
                    $fields->push(
107
                        HiddenField::create(
108
                            'Product[Quantity]['.$itemID.']',
109
                            " ... quantity",
110
                            $item->Quantity
111
                        )
112
                    );
113
                    $altCount = Config::inst()->get('RepeatOrderForm', 'number_of_product_alternatives');
114
                    if($altCount > 9) {
115
                        user_error('You can only have up to nine alternatives buyables');
116
                    } elseif($altCount > 0) {
117
                        for ($i = 1; $i <= $altCount; $i++) {
118
                            $alternativeField = "Alternative".$i."ID";
119
                            $fields->push(
120
                                DropdownField::create(
121
                                    'Product['.$alternativeField.']['.$itemID.']',
122
                                    " ... alternative $i",
123
                                    $alternativeItemsMap,
124
                                    (isset($item->$alternativeField) ? $item->$alternativeField : 0)
125
                                )
126
                            );
127
                        }
128
                    }
129
                }
130
            }
131
        } else {
132
            $fields->push(HeaderField::create('items', 'There are no products in this repeating order'));
133
        }
134
135
        //other details
136
        $fields->push(
137
            HeaderField::create(
138
                'DetailsHeader',
139
                'Repeat Order Details'
140
            )
141
        );
142
        $fields->push(
143
            DropdownField::create(
144
                'PaymentMethod',
145
                'Payment Method',
146
                Config::inst()->get('RepeatOrder', 'payment_methods'),
147
                $repeatOrder ? $repeatOrder->PaymentMethod : ''
148
            )
149
        );
150
151
        $startField = DateField::create(
152
            'Start',
153
            'Start Date',
154
            $repeatOrder ? $repeatOrder->Start : date('d-m-Y')
155
        );
156
        $startField->setAttribute('autocomplete', 'off');
157
        $startField->setConfig('showcalendar', true);
158
        $fields->push($startField);
159
160
        $endField = DateField::create(
161
            'End',
162
            'End Date',
163
            $repeatOrder ? $repeatOrder->End : ''
164
        );
165
        $endField->setAttribute('autocomplete', 'off');
166
        $endField->setConfig('showcalendar', true);
167
        $fields->push($endField);
168
169
        $fields->push(
170
            DropdownField::create(
171
                'Period',
172
                'Period',
173
                Config::inst()->get('RepeatOrder', 'period_fields'),
174
                $repeatOrder ? $repeatOrder->Period : ''
175
            )
176
        );
177
178
        $fields->push(
179
            TextareaField::create(
180
                'Notes',
181
                'Notes',
182
                $repeatOrder ? $repeatOrder->Notes : ''
183
            )
184
        );
185
186
        $repeatOrderFormLink = RepeatOrdersPage::get_repeat_order_link('ajaxcreateorder', $order ? $order->ID : 0);
187
        $fields->push(
188
            HiddenField::create('AjaxSubmissionLink', 'AjaxSubmissionLink', $repeatOrderFormLink)
189
        );
190
191
        //hidden field
192
        if (isset($order->ID)) {
193
            $fields->push(
194
                HiddenField::create('OrderID', 'OrderID', $order->ID)
195
            );
196
        }
197
        if ($repeatOrder) {
198
            $fields->push(
199
                HiddenField::create('RepeatOrderID', 'RepeatOrderID', $repeatOrder->ID)
200
            );
201
        }
202
        return $fields;
203
    }
204
205
    public static function repeatOrderFormActions($label = '', $repeatOrder = null)
206
    {
207
        //actions
208
        $actions = FieldList::create();
209
        if ($repeatOrder) {
210
            if(!$label){
211
                $label = 'Save';
212
            }
213
            $actions->push(FormAction::create('doSave', $label));
214
        } else {
215
            if(!$label){
216
                $label = 'Create';
217
            }
218
            $actions->push(FormAction::create('doCreate', $label));
219
        }
220
        return $actions;
221
    }
222
223
    /**
224
     * same as save!
225
     * @param  [type] $data    [description]
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
226
     * @param  [type] $form    [description]
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
227
     * @param  [type] $request [description]
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
228
     * @return [type]          [description]
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
229
     */
230
    public function doCreate($data, $form, $request)
231
    {
232
        return $this->doSave($data, $form, $request);
233
    }
234
235
    /**
236
     * Save the changes
237
     */
238
    public function doSave($data, $form, $request)
239
    {
240
        $data = Convert::raw2sql($data);
241
        $member = Member::currentUser();
242
        $allowNonMembers = Config::inst()->get('RepeatOrder', 'allow_non_members');
243
        if (!$member && !$allowNonMembers) {
244
            $form->sessionMessage('Could not find customer details.', 'bad');
245
            $this->controller->redirectBack();
246
247
            return false;
248
        }
249
        if ($member && $member->IsShopAdmin()) {
250
            $form->sessionMessage('Repeat orders can not be created by Shop Administrators.  Only customers can create repeat orders.', 'bad');
251
            $this->controller->redirectBack();
252
253
            return false;
254
        }
255
        if (isset($data['OrderID'])) {
256
257
            $orderID = intval($data['OrderID']);
258
            if($orderID) {
259
260
                if ($member) {
261
                    $order = DataObject::get_one('Order', 'Order.ID = \''.$orderID.'\' AND MemberID = \''.$member->ID.'\'');
262
                }
263
                else {
264
                    $order = DataObject::get_one('Order', 'Order.ID = \''.$orderID.'\'');
265
                }
266
267
                if ($order) {
268
                    $repeatOrder = RepeatOrder::create_repeat_order_from_order($order);
0 ignored issues
show
Compatibility introduced by
$order of type object<DataObject> is not a sub-type of object<Order>. It seems like you assume a child class of the class DataObject to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
269
                    if($repeatOrder) {
270
                        $repeatOrder->OriginatingOrderID = $order->ID;
0 ignored issues
show
Documentation introduced by
The property OriginatingOrderID does not exist on object<RepeatOrder>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
271
                        $repeatOrder->write();
272
273
                        $order->RepeatOrderID = $repeatOrder->ID;
274
                        $order->write();
275
                    } else {
276
                        $form->sessionMessage('Sorry, an error occured - we could not create your subscribtion order. Please try again.', 'bad');
277
                        $this->controller->redirectBack();
278
279
                        return false;
280
                    }
281
                } else {
282
                    $form->sessionMessage('Could not find originating order.', 'bad');
283
                    $this->controller->redirectBack();
284
285
                    return false;
286
                }
287
            }
288
        } else {
289
            $repeatOrderID = intval($data['RepeatOrderID']);
290
            if ($member) {
291
                $repeatOrder = DataObject::get_one('RepeatOrder', 'RepeatOrder.ID = \''.$repeatOrderID.'\' AND MemberID = \''.$member->ID.'\'');
292
            }
293
            else {
294
                $repeatOrder = DataObject::get_one('RepeatOrder', 'RepeatOrder.ID = \''.$repeatOrderID.'\'');
295
            }
296
297
        }
298
        if ($repeatOrder) {
299
            if ($repeatOrderItems = $repeatOrder->OrderItems()) {
0 ignored issues
show
Bug introduced by
The variable $repeatOrder does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
300
                foreach ($repeatOrderItems as $repeatOrderItem) {
301
                    $repeatOrderItem->ProductID = $data["Product"]["ID"][$repeatOrderItem->ProductID];
302
                    $repeatOrderItem->Quantity = $data["Product"]["Quantity"][$repeatOrderItem->ProductID];
303
                    $altCount = Config::inst()->get('RepeatOrderForm', 'number_of_product_alternatives');
304
                    for ($i = 1; $i <= $altCount; $i++) {
305
                        $alternativeField = "Alternative".$i."ID";
306
                        $repeatOrderItem->$alternativeField = $data["Product"][$alternativeField][$repeatOrderItem->ProductID];
307
                    }
308
                    $repeatOrderItem->write();
309
                }
310
            }
311
            $params = [];
312
            if (isset($data['Start']) && strtotime($data['Start']) > strtotime(Date("Y-m-d"))) {
313
                $params['Start'] = $data['Start'];
314
            } else {
315
                $params["Start"] = Date("Y-m-d");
316
            }
317
            if (isset($data['End'])  && strtotime($data['End']) > strtotime($params["Start"])) {
318
                $params['End'] = $data['End'];
319
            }
320
            if (isset($data['Period'])) {
321
                $params['Period'] = $data['Period'];
322
            } else {
323
                $data['Period'] = RepeatOrder::default_period_key();
324
            }
325
            if (isset($data['PaymentMethod'])) {
326
                $params['PaymentMethod'] = $data['PaymentMethod'];
327
            } else {
328
                $params['PaymentMethod'] = RepeatOrder::default_payment_method_key();
329
            }
330
            if (isset($data['Notes'])) {
331
                $params['Notes'] = $data['Notes'];
332
            }
333
            $repeatOrder->update($params);
334
            $repeatOrder->Status = 'Pending';
335
            $repeatOrder->write();
336
        } else {
337
            $form->sessionMessage('Could not find repeat order.', 'bad');
338
            $this->controller->redirectBack();
339
340
            return false;
341
        }
342
343
        if(!$request->isAjax()){
344
            $this->controller->redirect(
345
                RepeatOrdersPage::get_repeat_order_link('view', $repeatOrder->ID)
346
            );
347
        }
348
        return true;
349
    }
350
}
351