d3utilities   F
last analyzed

Complexity

Total Complexity 63

Size/Duplication

Total Lines 377
Duplicated Lines 6.37 %

Coupling/Cohesion

Components 3
Dependencies 0

Importance

Changes 0
Metric Value
dl 24
loc 377
rs 3.36
c 0
b 0
f 0
wmc 63
lcom 3
cbo 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 26 3
A get_language_constant() 0 4 1
C get_set4sql() 6 27 12
B insert() 9 36 6
C update() 9 52 11
A delete() 0 32 5
A init_default_values() 0 30 5
C get_view_edit() 0 44 13
A get_control_form() 0 27 4
A get_select() 0 14 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like d3utilities often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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

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

1
<?php
2
3
/**
4
 * Class d3utilities
5
 */
6
class d3utilities
7
{
8
    public $dirname = ''; // directory name under xoops_trust_path
9
    public $mydirname = ''; // each directory name under xoops_root_path
10
    public $mid = 0; // id of each module instance
11
    public $table = ''; // table with prefix and dirname
12
    public $primary_key = ''; // column for primary_key
13
    public $cols = []; // settings of each columns
14
    public $form_mode = 'new'; // 'new','edit' are available
15
    public $page_name = ''; // controller's name  eg) page=(controller) in URI
16
    public $action_base_hiddens = [];
17
18
    //HACK by domifara
19
20
    //  public function D3Utilities( $mydirname , $table_body , $primary_key , $cols , $page_name , $action_base_hiddens )
21
22
    /**
23
     * d3utilities constructor.
24
     * @param $mydirname
25
     * @param $table_body
26
     * @param $primary_key
27
     * @param $cols
28
     * @param $page_name
29
     * @param $action_base_hiddens
30
     */
31
32
    public function __construct($mydirname, $table_body, $primary_key, $cols, $page_name, $action_base_hiddens)
33
    {
34
        $db = XoopsDatabaseFactory::getDatabaseConnection();
35
36
        $this->dirname = \basename(\dirname(__DIR__));
37
38
        $this->mydirname = $mydirname;
39
40
        $this->table = $db->prefix($mydirname ? $mydirname . '_' . $table_body : $table_body);
41
42
        $this->primary_key = $primary_key;
43
44
        $this->cols = $cols;
45
46
        $module_handler = xoops_getHandler('module');
47
48
        $module = $module_handler->getByDirname($this->mydirname);
49
50
        if (!empty($module)) {
51
            $this->mid = (int)$module->getVar('mid');
52
        }
53
54
        $this->page_name = $page_name;
55
56
        $this->action_base_hiddens = $action_base_hiddens;
57
    }
58
59
    /**
60
     * @param $name
61
     * @return mixed
62
     */
63
64
    public function get_language_constant($name)
65
    {
66
        return constant(mb_strtoupper('_MD_A_' . $this->dirname . '_' . $this->page_name . '_' . $name));
67
    }
68
69
    /**
70
     * @param $value
71
     * @param $col
72
     * @return string
73
     */
74
75
    public function get_set4sql($value, $col)
76
    {
77
        switch ($col['type']) {
78
            case 'text':
79 View Code Duplication
            case 'blob':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
80
                $length = empty($col['length']) ? 65535 : (int)$col['length'];
81
82
                return "`{$col['name']}`='" . addslashes(xoops_substr($value, 0, $length)) . "'";
83
            case 'char':
84
            case 'varchar':
85 View Code Duplication
            case 'string':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
86
                $length = empty($col['length']) ? 255 : (int)$col['length'];
87
88
                return "`{$col['name']}`='" . addslashes(xoops_substr($value, 0, $length)) . "'";
89
            case 'int':
90
            case 'integer':
91
                $value = (int)$value;
92
                if (!empty($col['max'])) {
93
                    $value = min($value, (int)$col['max']);
94
                }
95
                if (!empty($col['min'])) {
96
                    $value = max($value, (int)$col['min']);
97
                }
98
99
                return "`{$col['name']}`=$value";
100
        }
101
    }
102
103
    // single update or insert
104
105
    /**
106
     * @return array
107
     */
0 ignored issues
show
Documentation introduced by
Should the return type not be array<integer|string>|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...
108
109
    public function insert()
110
    {
111
        $db = XoopsDatabaseFactory::getDatabaseConnection();
112
113
        $id = $this->init_default_values();
114
115
        $set4sql = '';
116
117 View Code Duplication
        foreach ($this->cols as $col) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
118
            if (empty($col['edit_edit'])) {
119
                continue;
120
            }
121
122
            if ($col['name'] == $this->primary_key) {
123
                continue;
124
            }
125
126
            $set4sql .= $this->get_set4sql(@$_POST[$col['name']], $col) . ',';
127
        }
128
129
        if (!empty($set4sql)) {
130
            if ($id > 0) {
131
                // UPDATE
132
133
                $db->queryF("UPDATE $this->table SET " . mb_substr($set4sql, 0, -1) . " WHERE $this->primary_key='" . addslashes($id) . "'");
134
135
                return [$id, 'update'];
136
            }
137
138
            // INSERT
139
140
            $db->queryF("INSERT INTO $this->table SET " . mb_substr($set4sql, 0, -1));
141
142
            return [$db->getInsertId(), 'insert'];
143
        }
144
    }
145
146
    // multiple update
147
148
    /**
149
     * @return array
150
     */
151
152
    public function update()
153
    {
154
        $db = XoopsDatabaseFactory::getDatabaseConnection();
155
156
        // search appropriate column for getting primary_key
157
158
        foreach ($this->cols as $col) {
159
            if (in_array(@$col['list_edit'], ['text', 'textarea', 'hidden'], true)) {
160
                $column4key = $col['name'];
161
162
                break;
163
            }
164
        }
165
166
        if (empty($column4key)) {
167
            $column4key = $this->cols[0]['name'];
168
        }
169
170
        $ret = [];
171
172
        foreach (array_keys($_POST[$column4key]) as $id) {
173
            $id = (int)$id;    // primary_key should be 'integer'
174
175
            $set4sql = '';
176
177 View Code Duplication
            foreach ($this->cols as $col) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
178
                if (empty($col['list_edit'])) {
179
                    continue;
180
                }
181
182
                if ($col['name'] == $this->primary_key) {
183
                    continue;
184
                }
185
186
                $set4sql .= $this->get_set4sql(@$_POST[$col['name']][$id], $col) . ',';
187
            }
188
189
            if (!empty($set4sql)) {
190
                $result = $db->query("SELECT * FROM $this->table WHERE $this->primary_key=$id");
191
192
                if (1 == $db->getRowsNum($result)) {
193
                    $db->queryF("UPDATE $this->table SET " . mb_substr($set4sql, 0, -1) . " WHERE $this->primary_key=$id");
194
195
                    if (1 == $db->getAffectedRows()) {
196
                        $ret[$id] = $db->fetchArray($result);
197
                    }
198
                }
199
            }
200
        }
201
202
        return $ret;
203
    }
204
205
    /**
206
     * @param bool $delete_comments
207
     * @param bool $delete_notifications
208
     * @return array
209
     */
210
211
    public function delete($delete_comments = false, $delete_notifications = false)
212
    {
213
        $db = XoopsDatabaseFactory::getDatabaseConnection();
214
215
        $ret = [];
216
217
        foreach (array_keys($_POST['admin_main_checkboxes']) as $id) {
218
            $id = (int)$id;    // primary_key should be 'integer'
219
220
            $result = $db->query("SELECT * FROM $this->table WHERE $this->primary_key=$id");
221
222
            if (1 == $db->getRowsNum($result)) {
223
                $ret[$id] = $db->fetchArray($result);
224
225
                $db->queryF("DELETE FROM $this->table WHERE $this->primary_key=$id");
226
227
                if ($delete_comments) {
228
                    // remove comments
229
230
                    $db->queryF('DELETE FROM ' . $db->prefix('xoopscomments') . " WHERE com_modid=$this->mid AND com_itemid=$id");
231
                }
232
233
                if ($delete_notifications) {
234
                    // remove notifications
235
236
                    $db->queryF('DELETE FROM ' . $db->prefix('xoopsnotifications') . " WHERE not_modid=$this->mid AND not_itemid=$id");
237
                }
238
            }
239
        }
240
241
        return $ret;
242
    }
243
244
    /**
245
     * @return int
246
     */
247
248
    public function init_default_values()
249
    {
250
        $db = XoopsDatabaseFactory::getDatabaseConnection();
251
252
        if (@$_GET['id']) {
253
            $id = \Xmf\Request::getInt('id', 0, 'GET');
254
255
            $rs = $db->query("SELECT * FROM $this->table WHERE $this->primary_key=$id");
256
257
            if (1 == $db->getRowsNum($rs)) {
258
                $row = $db->fetchArray($rs);
259
260
                foreach (array_keys($this->cols) as $key) {
261
                    if (empty($this->cols[$key]['edit_show'])) {
262
                        continue;
263
                    }
264
265
                    $this->cols[$key]['default_value'] = $row[$this->cols[$key]['name']];
266
                }
267
268
                $this->form_mode = 'edit';
269
270
                return $id;
271
            }
272
        }
273
274
        $this->form_mode = 'new';
275
276
        return 0;
277
    }
278
279
    /**
280
     * @return array
281
     */
282
283
    public function get_view_edit()
284
    {
285
        $id = $this->init_default_values();
286
287
        $lines = [];
288
289
        foreach ($this->cols as $col) {
290
            if (empty($col['edit_show'])) {
291
                continue;
292
            }
293
294
            if (!isset($col['default_value'])) {
295
                switch ($col['type']) {
296
                    case 'int':
297
                    case 'integer':
298
                        $col['default_value'] = 0;
299
                        break;
300
                    default:
301
                        $col['default_value'] = '';
302
                        break;
303
                }
304
            }
305
306
            switch ($col['edit_edit']) {
307
                case 'checkbox':
308
                    $checked = empty($col['default_value']) ? '' : "checked='checked'";
309
                    $value = empty($col['checkbox_value']) ? 1 : htmlspecialchars($col['checkbox_value'], ENT_QUOTES);
310
311
                    $lines[$col['name']] = "<input type='checkbox' name='{$col['name']}' value='$value' $checked />";
312
                    break;
313
                case 'text':
314
                default:
315
                    $size = empty($col['edit_size']) ? 32 : (int)$col['edit_size'];
316
                    $length = empty($col['length']) ? 255 : (int)$col['length'];
317
                    $lines[$col['name']] = "<input type='text' name='{$col['name']}' size='$size' maxlength='$length' value='" . htmlspecialchars($col['default_value'], ENT_QUOTES) . "' />";
318
                    break;
319
                case false:
0 ignored issues
show
Unused Code introduced by
case false: $lines[$...ENT_QUOTES); break; 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...
320
                    $lines[$col['name']] = htmlspecialchars($col['default_value'], ENT_QUOTES);
321
                    break;
322
            }
323
        }
324
325
        return [$id, $lines];
326
    }
327
328
    /**
329
     * @param $controllers
330
     * @return string
331
     */
332
333
    public function get_control_form($controllers)
334
    {
335
        $hiddens = '';
336
337
        foreach ($this->action_base_hiddens as $key => $val) {
338
            $key4disp = htmlspecialchars($key, ENT_QUOTES);
339
340
            $val4disp = htmlspecialchars($val, ENT_QUOTES);
341
342
            $hiddens .= "<input type='hidden' name='$key4disp' value='$val4disp' />\n";
343
        }
344
345
        $controllers_html = '';
346
347
        foreach ($controllers as $type => $body) {
348
            if ('num' == $type) {
349
                $controllers_html .= $this->get_select('num', $body, $GLOBALS['num']);
350
            }
351
        }
352
353
        return "
354
            <form action='' method='get' name='admin_control' id='admin_control'>
355
                $hiddens
356
                $controllers_html
357
                <input type='submit' value='" . _SUBMIT . "' />
358
            </form>\n";
359
    }
360
361
    /**
362
     * @param $name
363
     * @param $options
364
     * @param $current_value
365
     * @return string
366
     */
367
368
    public function get_select($name, $options, $current_value)
369
    {
370
        $ret = "<select name='" . htmlspecialchars($name, ENT_QUOTES) . "'>\n";
371
372
        foreach ($options as $key => $val) {
373
            $selected = $val == $current_value ? "selected='selected'" : '';
374
375
            $ret .= "<option value='" . htmlspecialchars($key, ENT_QUOTES) . "' $selected>" . htmlspecialchars($val, ENT_QUOTES) . "</option>\n";
376
        }
377
378
        $ret .= "</select>\n";
379
380
        return $ret;
381
    }
382
}
383