BasketEvaluation::run()   F
last analyzed

Complexity

Conditions 28
Paths 1133

Size

Total Lines 116
Code Lines 86

Duplication

Lines 83
Ratio 71.55 %

Code Coverage

Tests 38
CRAP Score 197.3439

Importance

Changes 0
Metric Value
cc 28
eloc 86
nc 1133
nop 2
dl 83
loc 116
rs 2
c 0
b 0
f 0
ccs 38
cts 95
cp 0.4
crap 197.3439

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
 * This filter will be added to the basket to do various actions on the
4
 * basket such as adding product
5
 *
6
 * running_index: number for the running order
7
 * evaluate_target_key: price, weight, webshop_coupon (later: (array)product_id, customer_id ...)
8
 * evaluate_method: > < == != [maybe (>= <=) ??]
9
 * evaluate_value: the number or value e.g. 600 if price.
10
 * go_to_index_after: makes i possible to jump further in the filter.
11
 *
12
 * action_key: no_action, add_product_id, (later: add_order_text, ...?)
13
 * action_value: id or text
14
 * action_quantity: number of times the action e.g 10 x product_id
15
 * action_unit: quantity or percentage.
16
 *
17
 * PHP version 5
18
 *
19
 * @category Application
20
 * @package  Intraface_Shop
21
 * @author   Sune Jensen <[email protected]>
22
 * @version @package-version@
23
 */
24
class BasketEvaluation extends Intraface_Standard
25
{
26
    public $kernel;
27
    public $error;
28
    private $db;
29
    private $id;
30
    private $values;
0 ignored issues
show
Unused Code introduced by
The property $values 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
    private $settings;
0 ignored issues
show
Unused Code introduced by
The property $settings 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...
32
33
    /**
34
     * Constructor
35
     *
36
     * @param object $kernel Kernel registry
37
     * @param int    $id     Id of the BasketEvaluation
38
     *
39
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
40
     */
41 5
    public function __construct($kernel, $id = 0)
42
    {
43 5
        if (!is_object($kernel)) {
44
            throw new Exception("First parameter to BasketEvaluation should be kernel");
45
            return false;
0 ignored issues
show
Unused Code introduced by
return false; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
46
        }
47
48 5
        $this->error = new Intraface_Error;
49 5
        $this->id = (int)$id;
50 5
        $this->kernel = $kernel;
51
52 5
        $this->db = MDB2::singleton(DB_DSN);
53
54 5
        if (PEAR::isError($this->db)) {
55
            die($this->db->getMessage());
0 ignored issues
show
Coding Style Compatibility introduced by
The method __construct() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
56
        }
57
58 5
        $this->value['settings'] = array (
59
            'evaluate_target' => array(
60 5
                0 => 'price',
61 5
                1 => 'weight',
62 5
                2 => 'customer_coupon',
63 5
                3 => 'customer_country'),
64
65
            'evaluate_method' => array(
66 5
                0 => 'equals',
67 5
                1 => 'different_from',
68 5
                2 => 'at_least',
69 5
                3 => 'at_most'),
70
71
            'action_action' => array(
72 5
                0 => 'no_action',
73 5
                1 => 'add_product_id'),
74
75
            'action_unit' => array(
76 5
                0 => 'pieces',
77 5
                1 => 'percentage_of_price_including_vat',
78 5
                2 => 'percentage_of_price_exclusive_vat')
79 5
        );
80
81 5
        if ($this->id != 0) {
82 1
            $this->load();
83 1
        }
84 5
    }
85
86
    /**
87
     * Loads the evaluation
88
     *
89
     * @return boolean
90
     */
91 1
    private function load()
92
    {
93 1
        $result = $this->db->query("SELECT * FROM webshop_basket_evaluation WHERE active = 1 AND intranet_id = ".$this->db->quote($this->kernel->intranet->get('id'), 'integer')." AND id = ".$this->db->quote($this->id, 'integer'));
94
95 1
        if (PEAR::isError($result)) {
96
            throw new Exception($result->getMessage() . $result->getUserInfo());
97
        }
98
99 1
        if ($result->numRows() == 0) {
100
            throw new Exception('Invalid id in BasketEvaluation->load');
101
            return false;
0 ignored issues
show
Unused Code introduced by
return false; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
102
        }
103
104 1
        $this->value = array_merge($this->value, $result->fetchRow(MDB2_FETCHMODE_ASSOC));
105
106 1
        $this->value['evaluate_target'] = $this->value['settings']['evaluate_target'][$this->value['evaluate_target_key']];
107 1
        $this->value['evaluate_method'] = $this->value['settings']['evaluate_method'][$this->value['evaluate_method_key']];
108 1
        $this->value['action_action'] = $this->value['settings']['action_action'][$this->value['action_action_key']];
109 1
        $this->value['action_unit'] = $this->value['settings']['action_unit'][$this->value['action_unit_key']];
110
111 1
        return true;
112
    }
113
114 4 View Code Duplication
    function validate($input)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
115
    {
116 4
        $validator = new Intraface_Validator($this->error);
117
118 4
        $validator->isNumeric($input['running_index'], 'Index is not a valid number');
119 4
        $validator->isNumeric($input['evaluate_target_key'], 'Evaluation target is not valid');
120 4
        $validator->isNumeric($input['evaluate_method_key'], 'Evaluation method is not valid');
121 4
        $validator->isString($input['evaluate_value'], 'Evaluation value is not valid', '', 'allow_empty');
122 4
        $validator->isNumeric($input['go_to_index_after'], 'Go to index after is not a valid number');
123 4
        $validator->isNumeric($input['action_action_key'], 'Action is not valid');
124 4
        $validator->isString($input['action_value'], 'Target is not valid', '', 'allow_empty');
125 4
        $validator->isNumeric($input['action_quantity'], 'Action quantity is not a valid number', 'zero_or_greater');
126 4
        $validator->isNumeric($input['action_unit_key'], 'Action unit is not valid');
127
128 4
        if ($this->error->isError()) {
129
            return false;
130
        }
131
132 4
        return true;
133
    }
134
135
    /**
136
     * Saves and validates the evaluation
137
     *
138
     * @param struct $input Values to save
139
     *
140
     * @return boolean
141
     */
142 4
    public function save($input)
143
    {
144 4
        settype($input['evaluate_value'], 'string');
145 4
        settype($input['action_value'], 'string');
146 4
        settype($input['action_quantity'], 'integer');
147 4
        settype($input['evaluate_value_case_sensitive'], 'integer');
148
149 4
        if (!$this->validate($input)) {
150
            return false;
151
        }
152
153 4
        $sql = "running_index = ".$this->db->quote($input['running_index'], 'integer').", " .
154 4
                 "evaluate_target_key = ".$this->db->quote($input['evaluate_target_key'], 'integer').", " .
155 4
                 "evaluate_method_key = ".$this->db->quote($input['evaluate_method_key'], 'integer').", " .
156 4
                 "evaluate_value = ".$this->db->quote($input['evaluate_value'], 'text').", " .
157 4
                 "evaluate_value_case_sensitive = ".$this->db->quote($input['evaluate_value_case_sensitive'], 'integer').", " .
158 4
                 "go_to_index_after = ".$this->db->quote($input['go_to_index_after'], 'integer').", " .
159 4
                 "action_action_key = ".$this->db->quote($input['action_action_key'], 'integer').", " .
160 4
                 "action_value = ".$this->db->quote($input['action_value'], 'text').", " .
161 4
                 "action_quantity = ".$this->db->quote($input['action_quantity'], 'integer').", " .
162 4
                 "action_unit_key = ".$this->db->quote($input['action_unit_key'], 'integer');
163
164 4
        if ($this->id != 0) {
165
            $result = $this->db->exec("UPDATE webshop_basket_evaluation SET ".$sql." WHERE intranet_id = ".$this->kernel->intranet->get('id')." AND id = ".$this->id);
166
167
            if (PEAR::isError($result)) {
168
                throw new Exception($result->getMessage() . $result->getUserInfo());
169
                return false;
0 ignored issues
show
Unused Code introduced by
return false; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
170
            }
171
        } else {
172 4
            $result = $this->db->query("INSERT INTO webshop_basket_evaluation SET ".$sql.", intranet_id = ".$this->kernel->intranet->get('id').", id = ".$this->id);
173
174 4
            if (PEAR::isError($result)) {
175
                throw new Exception($result->getMessage() . $result->getUserInfo());
176
                return false;
0 ignored issues
show
Unused Code introduced by
return false; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
177
            }
178
179 4
            $this->id = $this->db->lastInsertID();
180 4
            if (PEAR::isError($this->id)) {
181
                throw new Exception($result->getMessage() . $result->getUserInfo());
182
            }
183
        }
184
185 4
        return true;
186
    }
187
188
    /**
189
     * Deletes the evaluation
190
     *
191
     * @return boolean
192
     */
193 1 View Code Duplication
    public function delete()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
194
    {
195 1
        $result = $this->db->exec("UPDATE webshop_basket_evaluation SET active = 0 WHERE intranet_id = ".$this->kernel->intranet->get('id')." AND id = ".$this->id);
196 1
        if (PEAR::isError($result)) {
197
            throw new Exception($result->getMessage() . $result->getUserInfo());
198
            return false;
0 ignored issues
show
Unused Code introduced by
return false; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
199
        }
200 1
        return true;
201
    }
202
203
    /**
204
     * Gets a list with evaluations
205
     *
206
     * @return boolean
207
     */
208 3
    public function getList()
209
    {
210 3
        $result = $this->db->query("SELECT * FROM webshop_basket_evaluation WHERE active = 1 AND intranet_id = ".$this->kernel->intranet->get('id').' ORDER BY running_index');
211
212 3
        if (PEAR::isError($this->id)) {
213
            throw new Exception($result->getMessage() . $result->getUserInfo());
214
        }
215
216 3
        $i = 0;
217 3
        $evaluation = array();
218
219 3 View Code Duplication
        while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
220 2
            $evaluation[$i] = $row;
221 2
            $evaluation[$i]['evaluate_target'] = $this->value['settings']['evaluate_target'][$row['evaluate_target_key']];
222 2
            $evaluation[$i]['evaluate_method'] = $this->value['settings']['evaluate_method'][$row['evaluate_method_key']];
223 2
            $evaluation[$i]['action_action'] = $this->value['settings']['action_action'][$row['action_action_key']];
224 2
            $evaluation[$i]['action_unit'] = $this->value['settings']['action_unit'][$row['action_unit_key']];
225
226 2
            $i++;
227 2
        }
228
229 3
        return $evaluation;
230
    }
231
232
    /**
233
     * Runs all evaluations
234
     *
235
     * @param object $basket   A basket object
236
     * @param array  $customer What is this for
237
     *
238
     * @return boolean
239
     */
240 1
    public function run($basket, $customer = array())
241
    {
242 1
        $evaluations = $this->getList();
243 1
        $go_to_index = 0;
244
245 1
        $basket->removeEvaluationProducts();
246
247 1
        foreach ($evaluations as $evaluation) {
248
            // If have been requested to move to a higher index, we make sure we do that
249 1
            if ($go_to_index > $evaluation['running_index']) {
250
                continue;
251
            }
252
253 1
            $evaluation_result = false;
254
255 1
            switch ($evaluation['evaluate_target']) {
256 1
                case 'price':
257 1
                    $evaluate = (double)$basket->getTotalPrice();
258 1
                    settype($evaluation['evaluate_value'], 'double');
259 1
                    break;
260
                case 'weight':
261
                    $evaluate = (int)$basket->getTotalWeight();
262
                    settype($evaluation['evaluate_value'], 'integer');
263
                    break;
264 View Code Duplication
                case 'customer_coupon':
265
                    settype($customer['customer_coupon'], 'string');
266
                    if ($evaluation['evaluate_value_case_sensitive'] != 1) {
267
                        $evaluate = strtolower(trim($customer['customer_coupon']));
268
                        $evaluation['evaluate_value'] = strtolower($evaluation['evaluate_value']);
269
                    } else {
270
                        $evaluate = trim($customer['customer_coupon']);
271
                    }
272
                    // coupons can only be evaluated as 'equals' or 'different from'
273
                    if ($evaluation['evaluate_method'] != 'equals' && $evaluation['evaluate_method'] != 'different_from') {
274
                        $evaluation['evaluate_method'] = 'different_from';
275
                    }
276
                    break;
277 View Code Duplication
                case 'customer_country':
278
                    settype($customer['country'], 'string');
279
                    if ($evaluation['evaluate_value_case_sensitive'] != 1) {
280
                        $evaluate = strtolower(trim($customer['country']));
281
                        $evaluation['evaluate_value'] = strtolower($evaluation['evaluate_value']);
282
                    } else {
283
                        $evaluate = trim($customer['country']);
284
                    }
285
                    // country can only be evaluated as 'equals' or 'different from'
286
                    if ($evaluation['evaluate_method'] != 'equals' && $evaluation['evaluate_method'] != 'different_from') {
287
                        $evaluation['evaluate_method'] = 'different_from';
288
                    }
289
                    break;
290
                default:
291
                    throw new Exception("Invalid evaluation_target in BasketEvaluation->run");
292
                    return false;
0 ignored issues
show
Unused Code introduced by
return false; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
293 1
            }
294
295 1 View Code Duplication
            switch ($evaluation['evaluate_method']) {
296 1
                case 'equals':
297
                    if ($evaluate == $evaluation['evaluate_value']) {
298
                        $evaluation_result = true;
299
                    }
300
                    break;
301 1
                case 'different_from':
302
                    if ($evaluate != $evaluation['evaluate_value']) {
303
                        $evaluation_result = true;
304
                    }
305
                    break;
306 1
                case 'at_least':
307 1
                    if ($evaluate >= $evaluation['evaluate_value']) {
308 1
                        $evaluation_result = true;
309 1
                    }
310 1
                    break;
311
                case 'at_most':
312
                    if ($evaluate <= $evaluation['evaluate_value']) {
313
                        $evaluation_result = true;
314
                    }
315
                    break;
316
                default:
317
                    throw new Exception("Invalid evaluation_method in BasketEvaluation->run");
318
                    return false;
0 ignored issues
show
Unused Code introduced by
return false; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
319 1
            }
320
321 1 View Code Duplication
            if ($evaluation_result) {
322 1
                $go_to_index = $evaluation['go_to_index_after'];
323
324 1
                switch ($evaluation['action_unit']) {
325 1
                    case 'pieces':
326 1
                        $quantity = $evaluation['action_quantity'];
327 1
                        break;
328
                    case 'percentage_of_price_including_vat':
329
                        $quantity = round(($evaluation['action_quantity']/100)*$basket->getTotalPrice());
330
                        break;
331
                    case 'percentage_of_price_exclusive_vat':
332
                        $quantity = round(($evaluation['action_quantity']/100)*$basket->getTotalPrice('exclusive_vat'));
333
                        break;
334
                    default:
335
                        throw new Exception("Invalid action_unit in BasketEvaluation->run");
336
                        return false;
0 ignored issues
show
Unused Code introduced by
return false; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
337 1
                }
338
339 1
                switch ($evaluation['action_action']) {
340 1
                    case 'no_action':
341
                        // fine nothing is done
342
                        break;
343 1
                    case 'add_product_id':
344 1
                        if (!$basket->change($evaluation['action_value'], $quantity, '', 0, 1)) { // 1: it is basketevaluation
345
                            $this->error->set('Could not add product - invalid id or out of stock');
346
                        }
347 1
                        break;
348
                    default:
349
                        throw new Exception("Invalid action_action in BasketEvaluation->run");
350
                        return false;
0 ignored issues
show
Unused Code introduced by
return false; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
351 1
                }
352 1
            }
353 1
        }
354 1
        return true;
355
    }
356
357 1
    function getId()
358
    {
359 1
        return $this->id;
360
    }
361
}
362