cleanupUnlinkedOrderObjects()   B
last analyzed

Complexity

Conditions 10
Paths 18

Size

Total Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
dl 0
loc 39
rs 7.6666
c 0
b 0
f 0
nc 18
nop 0

How to fix   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
/**
5
 * @description (see $this->description)
6
 *
7
 * @authors: Nicolaas [at] Sunny Side Up .co.nz
8
 * @package: ecommerce
9
 * @sub-package: tasks
10
 * @inspiration: Silverstripe Ltd, Jeremy
11
 **/
12
class EcommerceTaskDeleteAllOrders extends BuildTask
13
{
14
    private static $allowed_actions = array(
15
        '*' => 'ADMIN',
16
    );
17
18
    protected $title = 'Deletes all orders - CAREFUL!';
19
20
    protected $description = 'Deletes all the orders and payments ever placed - CAREFULL!';
21
22
    public $verbose = false;
23
24
    /**
25
     *key = table where OrderID is saved
26
     *value = table where LastEdited is saved.
27
     **/
28
    private static $linked_objects_array = array(
29
        'OrderAttribute' => 'OrderAttribute',
30
        'BillingAddress' => 'OrderAddress',
31
        'ShippingAddress' => 'OrderAddress',
32
        'OrderStatusLog' => 'OrderStatusLog',
33
        'OrderEmailRecord' => 'OrderEmailRecord',
34
        'EcommercePayment' => 'EcommercePayment',
35
    );
36
37
    /**
38
     *key = table where OrderID is saved
39
     *value = table where LastEdited is saved.
40
     **/
41
    private static $double_check_objects = array(
42
        'Order',
43
        'OrderItem',
44
        'OrderModifier',
45
        'EcommercePayment',
46
    );
47
48
    /*******************************************************
49
         * DELETE OLD SHOPPING CARTS
50
    *******************************************************/
51
52
    /**
53
     *@return int - number of carts destroyed
0 ignored issues
show
Documentation introduced by
Should the return type not be null|string|integer?

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...
54
     **/
55
    public function run($request)
56
    {
57
        if (!Director::isDev() || Director::isLive()) {
58
            DB::alteration_message('you can only run this in dev mode!');
59
        } else {
60
            if (!isset($_REQUEST['i-am-sure'])) {
61
                $_REQUEST['i-am-sure'] = '';
62
            }
63
            if ('yes' != $_REQUEST['i-am-sure']) {
64
                die("<h1>ARE YOU SURE?</h1><br /><br /><br /> please add the 'i-am-sure' get variable to your request and set it to 'yes' ... e.g. <br />http://www.mysite.com/dev/ecommerce/ecommercetaskdeleteallorders/?i-am-sure=yes");
65
            }
66
            $oldCarts = Order::get();
67
            $count = 0;
68
            if ($oldCarts->count()) {
69
                if ($this->verbose) {
70
                    $totalToDeleteSQLObject = DB::query('SELECT COUNT(*) FROM "Order"');
71
                    $totalToDelete = $totalToDeleteSQLObject->value();
72
                    DB::alteration_message('<h2>Total number of orders: '.$totalToDelete.' .... now deleting: </h2>', 'deleted');
73
                }
74
                foreach ($oldCarts as $oldCart) {
75
                    ++$count;
76
                    if ($this->verbose) {
77
                        DB::alteration_message("$count ... deleting abandonned order #".$oldCart->ID, 'deleted');
78
                    }
79
                    $oldCart->delete();
80
                    $oldCart->destroy();
81
                }
82
            } else {
83
                if ($this->verbose) {
84
                    $count = DB::query('SELECT COUNT("ID") FROM "Order"')->value();
85
                    DB::alteration_message("There are no abandonned orders. There are $count 'live' Orders.", 'created');
86
                }
87
            }
88
            $countCheck = DB::query('Select COUNT(ID) FROM "Order"')->value();
89
            if ($countCheck) {
90
                DB::alteration_message('ERROR: in testing <i>Orders</i> it appears there are '.$countCheck.' records left.', 'deleted');
91
            } else {
92
                DB::alteration_message('PASS: in testing <i>Orders</i> there seem to be no records left.', 'created');
93
            }
94
            $this->cleanupUnlinkedOrderObjects();
95
            $this->doubleCheckModifiersAndItems();
96
97
            return $count;
98
        }
99
    }
100
101
    public function cleanupUnlinkedOrderObjects()
102
    {
103
        $classNames = $this->Config()->get('linked_objects_array');
104
        if (is_array($classNames) && count($classNames)) {
105
            foreach ($classNames as $classWithOrderID => $classWithLastEdited) {
106
                if ($this->verbose) {
107
                    DB::alteration_message("looking for $classWithOrderID objects without link to order.", 'deleted');
108
                }
109
                $where = '"Order"."ID" IS NULL ';
110
                $join = ' LEFT JOIN "Order" ON ';
0 ignored issues
show
Unused Code introduced by
$join 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...
111
                //the code below is a bit of a hack, but because of the one-to-one relationship we
112
                //want to check both sides....
113
                $unlinkedObjects = $classWithLastEdited::get();
114
                if ($classWithLastEdited != $classWithOrderID) {
115
                    $unlinkedObjects = $unlinkedObjects
116
                        ->leftJoin($classWithOrderID, "\"OrderAddress\".\"ID\" = \"$classWithOrderID\".\"ID\"");
117
                }
118
                $unlinkedObjects = $unlinkedObjects
119
                    ->where($where)
120
                    ->leftJoin('Order', "\"Order\".\"ID\" = \"$classWithOrderID\".\"OrderID\"");
121
122
                if ($unlinkedObjects->count()) {
123
                    foreach ($unlinkedObjects as $unlinkedObject) {
124
                        if ($this->verbose) {
125
                            DB::alteration_message('Deleting '.$unlinkedObject->ClassName.' with ID #'.$unlinkedObject->ID.' because it does not appear to link to an order.', 'deleted');
126
                        }
127
                        //HACK FOR DELETING
128
                        $this->deleteObject($unlinkedObject);
129
                    }
130
                }
131
                $countCheck = DB::query("Select COUNT(ID) FROM \"$classWithLastEdited\"")->value();
132
                if ($countCheck) {
133
                    DB::alteration_message('ERROR: in testing <i>'.$classWithOrderID.'</i> it appears there are '.$countCheck.' records left.', 'deleted');
134
                } else {
135
                    DB::alteration_message('PASS: in testing <i>'.$classWithOrderID.'</i> there seem to be no records left.', 'created');
136
                }
137
            }
138
        }
139
    }
140
141
    private function doubleCheckModifiersAndItems()
142
    {
143
        DB::alteration_message('<hr />double-check:</hr />');
144
        foreach ($this->config()->get('double_check_objects') as $table) {
145
            $countCheck = DB::query("Select COUNT(ID) FROM \"$table\"")->value();
146
            if ($countCheck) {
147
                DB::alteration_message('ERROR: in testing <i>'.$table.'</i> it appears there are '.$countCheck.' records left.', 'deleted');
148
            } else {
149
                DB::alteration_message('PASS: in testing <i>'.$table.'</i> there seem to be no records left.', 'created');
150
            }
151
        }
152
    }
153
154
    private function deleteObject($unlinkedObject)
155
    {
156
        if ($unlinkedObject) {
157
            if ($unlinkedObject->ClassName) {
158
                if (class_exists($unlinkedObject->ClassName) && $unlinkedObject instanceof DataObject) {
159
                    $unlinkedObjectClassName = $unlinkedObject->ClassName;
160
                    $objectToDelete = $unlinkedObjectClassName::get()->byID($unlinkedObject->ID);
161
                    if ($objectToDelete) {
162
                        $objectToDelete->delete();
163
                        $objectToDelete->destroy();
164
                    } elseif ($this->verbose) {
165
                        DB::alteration_message('ERROR: could not find '.$unlinkedObject->ClassName.' with ID = '.$unlinkedObject->ID, 'deleted');
166
                    }
167
                } elseif ($this->verbose) {
168
                    DB::alteration_message('ERROR: trying to delete an object that is not a dataobject: '.$unlinkedObject->ClassName, 'deleted');
169
                }
170
            } elseif ($this->verbose) {
171
                DB::alteration_message('ERROR: trying to delete object without a class name', 'deleted');
172
            }
173
        } elseif ($this->verbose) {
174
            DB::alteration_message('ERROR: trying to delete non-existing object.', 'deleted');
175
        }
176
    }
177
}
178