Cfcm   F
last analyzed

Complexity

Total Complexity 63

Size/Duplication

Total Lines 378
Duplicated Lines 14.02 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
dl 53
loc 378
rs 3.36
c 0
b 0
f 0
wmc 63
lcom 1
cbo 2

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
A _set_forms_config() 0 6 1
B save_item_data() 0 34 7
C get_form() 13 83 14
B get_form_attributes() 6 38 11
A get_group_fields() 13 32 4
C connect_fields() 6 67 16
B update_fields_data() 0 32 6
A get_field() 15 15 2
A display_tpl() 0 5 1

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 Cfcm 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 Cfcm, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
if (!defined('BASEPATH')) {
4
    exit('No direct script access allowed');
5
}
6
7
/**
8
 * Image CMS
9
 *
10
 * CFCFM Module
11
 * @property Lib_category $lib_category
12
 * @property Forms $forms
13
 */
14
class Cfcm extends MY_Controller
15
{
16
17
    public function __construct() {
18
19
        parent::__construct();
20
        $obj = new MY_Lang();
21
        $obj->load('cfcm');
22
23
        $this->load->module('forms');
24
        $this->load->library('form_validation');
25
        $this->_set_forms_config();
26
    }
27
28
    public function _set_forms_config() {
29
30
        $this->load->config('cfcm');
31
32
        $this->forms->set_config($this->config->item('cfcm'));
33
    }
34
35
    /**
36
     * @param integer $item_id
37
     * @param string $type
38
     */
39
    public function save_item_data($item_id, $type = 'page') {
40
41
        $this->load->module('forms');
42
43
        $group = (int) $this->input->post('cfcm_use_group');
44
45
        if ($group != '0') {
46
            if (($fields = $this->get_group_fields($group))) {
47
                $form = $this->forms->add_fields($fields);
48
49
                if ($form->isValid()) {
50
                    if ($item_id > 0) {
51
                        // Save fields data
52
                        $data = $form->getData();
53
54
                        $this->update_fields_data($item_id, $data, $type);
55
56
                        // Delete empty fields
57
                        foreach (array_keys($fields) as $name) {
58
                            if (!array_key_exists($name, $data)) {
59
                                $this->db->where('item_id', $item_id);
60
                                $this->db->where('field_name', $name);
61
                                $this->db->where('item_type', $type);
62
                                $this->db->delete('content_fields_data');
63
                            }
64
                        }
65
                    }
66
                } else {
67
                    showMessage($form->_validation_errors(), false, 'r');
68
                    die();
69
                }
70
            }
71
        }
72
    }
73
74
    /**
75
     * @param bool|false|int $category_id
76
     * @param bool|false|int $item_id
77
     * @param bool|false|int $item_type
78
     * @param string $tpl
79
     */
80
    public function get_form($category_id = false, $item_id = false, $item_type = false, $tpl = '_onpage_form') {
81
82
        if ('page' === $category_id) {
83
            $item_type = 'page';
84
            $item_id = 0;
85
            $category_id = 0;
86
        }
87
88
        if ($item_id === 'page') {
89
            $item_type = 'page';
90
            $item_id = $category_id;
91
            $category_id = 0;
92
        }
93
94
        $category = (object) $this->lib_category->get_category($category_id);
95
        if ($item_type == 'category') {
96
            $category->field_group = $category->category_field_group;
97
        }
98
99
        if ($category_id == '0') {
100
            $category->field_group = -1;
101
        }
102
103
        if ($category->field_group != '0') {
104
            // Get group
105
            $group = $this->db->get_where('content_field_groups', ['id' => $category->field_group])->row();
106
107
            // Get all fields in group
108
            $query = $this->db->select('*')
109
                ->from('content_fields')
110
                ->join('content_fields_groups_relations', 'content_fields_groups_relations.field_name = content_fields.field_name')
111
                ->where("content_fields_groups_relations.group_id = $category->field_group")
112
                ->order_by('weight', 'ASC')
113
                ->get();
114
115
            if ($query) {
116
                $form_fields = [];
117
                $fields = $query->result_array();
118
119 View Code Duplication
                foreach ($fields as $field) {
120
                    $f_data = unserialize($field['data']);
121
                    if ($f_data == false) {
122
                        $f_data = [];
123
                    }
124
125
                    $form_fields[$field['field_name']] = [
126
                                                          'type'  => $field['type'],
127
                                                          'label' => encode($field['label']),
128
                                                         ];
129
130
                    $form_fields[$field['field_name']] = array_merge($form_fields[$field['field_name']], $f_data);
131
                }
132
133
                $form = $this->forms->add_fields($form_fields);
134
135
                // Set form attributes
136
                if ($item_id != false AND $item_type != false) {
137
138
                    $attributes = $this->get_form_attributes($fields, $item_id, $item_type);
139
140
                    if (count($attributes) > 0 AND is_array($attributes)) {
141
                        $form->setAttributes($attributes);
142
                    }
143
                }
144
                $form->title = $group->name;
145
146
                $gid = isset($group->id) ? $group->id : -1;
147
148
                $hiddenField = '<input type="hidden" name="cfcm_use_group" value="' . $gid . '" />';
149
            } else {
150
                $form = [];
151
            }
152
        }
153
154
        $this->template->add_array(
155
            [
156
             'form' => $form,
157
             'hf'   => $hiddenField,
158
            ]
159
        );
160
161
        $this->display_tpl($tpl);
162
    }
163
164
    /**
165
     * @param array $fields
166
     * @param integer $item_id
167
     * @param string|boolean $item_type
168
     * @return array|bool
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array|false.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
169
     */
170
    public function get_form_attributes(array $fields, $item_id, $item_type) {
171
172
        $this->db->where('item_id', $item_id);
173
        $this->db->where('item_type', $item_type);
174
        $query = $this->db->get('content_fields_data');
175
176
        $result = [];
177
        if ($query->num_rows() > 0) {
178
179
            $data = $query->result_array();
180
181
            foreach ($data as $row) {
182
183
                foreach ($fields as $key => $field) {
184
                    if ($field['field_name'] === $row['field_name']) {
185
                        unset($fields[$key]);
186
                    }
187
                }
188 View Code Duplication
                if (!isset($result[$row['field_name']])) {
189
                    $result[$row['field_name']] = $row['data'];
190
                } elseif (isset($result[$row['field_name']])) {
191
                    $result[$row['field_name']] = (array) $result[$row['field_name']];
192
                    $result[$row['field_name']][] = $row['data'];
193
                }
194
            }
195
196
        }
197
        //add unchecked checkboxes
198
        if (count($fields) > 0) {
199
            foreach ($fields as $field) {
200
                if ($field['type'] == 'checkbox') {
201
                    $result[$field['field_name']] = false;
202
                }
203
            }
204
        }
205
206
        return count($result) ? $result : false;
207
    }
208
209
    /**
210
     * @param int $group_id
211
     * @return array|bool
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array|false.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
212
     */
213
    public function get_group_fields($group_id = -1) {
214
215
        // Get all fields in group
216
        $query = $this->db
217
            ->where('group_id', $group_id)
218
            ->join('content_fields', 'content_fields_groups_relations.field_name = content_fields.field_name')
219
            ->order_by('weight', 'ASC')
220
            ->get('content_fields_groups_relations');
221
222
        if ($query->num_rows() > 0) {
223
            $form_fields = [];
224
            $fields = $query->result_array();
225
226 View Code Duplication
            foreach ($fields as $field) {
227
                $f_data = unserialize($field['data']);
228
                if ($f_data == false) {
229
                    $f_data = [];
230
                }
231
232
                $form_fields[$field['field_name']] = [
233
                                                      'type'  => $field['type'],
234
                                                      'label' => $field['label'],
235
                                                     ];
236
237
                $form_fields[$field['field_name']] = array_merge($form_fields[$field['field_name']], $f_data);
238
            }
239
240
            return $form_fields;
241
        } else {
242
            return false;
243
        }
244
    }
245
246
    /**
247
     * Merge item array with fields data
248
     * select/checkgroup/radiogroup always returned as array
249
     * @param array $item_data
250
     * @param string $item_type
251
     * @return array
252
     */
253
    public function connect_fields($item_data, $item_type) {
254
255
        if (($cache_result = $this->cache->fetch('cfcm_field_' . $item_data['id'] . $item_type)) !== false) {
256
            $item_data = array_merge($item_data, $cache_result);
257
            return $item_data;
258
        }
259
260
        $item_id = $item_data['id'];
261
262
        $this->db->where('item_id', $item_id);
263
        $this->db->where('item_type', $item_type);
264
        $query = $this->db->get('content_fields_data');
265
266
        if ($query->num_rows() == 0) {
267
            return $item_data;
268
        }
269
270
        $result = [];
271
        $data = $query->result_array();
272
273
        foreach ($data as $row) {
274 View Code Duplication
            if (!isset($result[$row['field_name']])) {
275
                $result[$row['field_name']] = $row['data'];
276
            } elseif (isset($result[$row['field_name']])) {
277
                $result[$row['field_name']] = (array) $result[$row['field_name']];
278
                $result[$row['field_name']][] = $row['data'];
279
            }
280
        }
281
282
        foreach ($result as $key => $val) {
283
            $field = $this->db->get_where('content_fields', ['field_name' => $key])->row();
284
285
            $weight[$field->field_name] = $field->weight;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$weight was never initialized. Although not strictly required by PHP, it is generally a good practice to add $weight = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
286
287
            if (is_array($val) OR in_array($field->type, ['select', 'checkgroup', 'radiogroup'])) {
288
                $field = unserialize($field->data);
289
290
                if (is_array($field) AND count($field) > 0 AND $field['initial'] != '') {
291
                    $values = explode("\n", $field['initial']);
292
293
                    $result[$key] = array_flip((array) $result[$key]);
294
                    foreach (array_keys($result[$key]) as $s_key) {
295
                        $result[$key][$s_key] = $values[$s_key];
296
                    }
297
298
                    ksort($result[$key]);
299
                }
300
            }
301
        }
302
303
        //Sort fields by weight
304
        array_multisort($weight, SORT_ASC, $result, SORT_DESC, $result);
305
306
        if (count($result) > 0) {
307
            // Display many many values
308
            foreach ($result as $key => $val) {
309
                if (is_array($val)) {
310
                    $result[$key] = implode(', ', $val);
311
                }
312
            }
313
314
            $this->cache->store('cfcm_field_' . $item_data['id'] . $item_type, $result);
315
            $item_data = array_merge($item_data, $result);
316
        }
317
318
        return $item_data;
319
    }
320
321
    /**
322
     * Save fields data in DB
323
     * @param integer $item_id
324
     * @param array $data
325
     * @param string $type
326
     */
327
    private function update_fields_data($item_id, $data, $type) {
328
329
        if (count($data) > 0) {
330
            foreach ($data as $key => $val) {
331
                $field_data = [
332
                               'item_id'    => $item_id,
333
                               'item_type'  => $type,
334
                               'field_name' => $key,
335
                              ];
336
337
                if (!is_array($val)) {
338
                    if ($this->db->get_where('content_fields_data', $field_data)->num_rows() > 0) {
339
                        $this->db->where($field_data);
340
                        $field_data['data'] = $val;
341
                        $this->db->update('content_fields_data', $field_data);
342
                    } else {
343
                        $field_data['data'] = $val;
344
                        $this->db->insert('content_fields_data', $field_data);
345
                    }
346
                } else {
347
                    // Clear
348
                    $this->db->where($field_data);
349
                    $this->db->delete('content_fields_data');
350
351
                    foreach ($val as $sub_val) {
352
                        $field_data['data'] = $sub_val;
353
                        $this->db->insert('content_fields_data', $field_data);
354
                    }
355
                }
356
            }
357
        }
358
    }
359
360
    /**
361
     * Get field info.
362
     * @param string $name
363
     * @return bool|array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array|false.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
364
     */
365 View Code Duplication
    public function get_field($name) {
366
367
        $this->db->limit(1);
368
        $this->db->where('field_name', $name);
369
        $query = $this->db->get('content_fields');
370
371
        if ($query->num_rows() == 1) {
372
            $data = $query->row_array();
373
            $data['data'] = unserialize($data['data']);
374
375
            return $data;
376
        } else {
377
            return false;
378
        }
379
    }
380
381
    /**
382
     * Display template file
383
     * @param string $file
384
     */
385
    private function display_tpl($file = '') {
386
387
        $file = realpath(__DIR__) . '/templates/public/' . $file . '.tpl';
388
        $this->template->display('file:' . $file);
389
    }
390
391
}