Passed
Push — main ( 3c8d3b...bf9e72 )
by Thierry
01:52
created

QueryInputTrait   F

Complexity

Total Complexity 61

Size/Duplication

Total Lines 264
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 110
c 3
b 0
f 0
dl 0
loc 264
rs 3.52
wmc 61

10 Methods

Rating   Name   Duplication   Size   Complexity  
A getSetInput() 0 10 3
A getBlobInput() 0 14 4
B getEnumValues() 0 25 8
A getEntryFunctions() 0 21 6
B setDataLength() 0 11 7
B getFieldInput() 0 26 7
A setDataType() 0 6 3
B getMaxLength() 0 15 9
B getEntryInput() 0 27 10
A getDefaultInput() 0 9 4

How to fix   Complexity   

Complex Class

Complex classes like QueryInputTrait 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.

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

1
<?php
2
3
namespace Lagdo\DbAdmin\DbAdmin\Traits;
4
5
use Lagdo\DbAdmin\Driver\Entity\TableFieldEntity;
6
7
use function is_array;
8
use function in_array;
9
use function json_encode;
10
use function reset;
11
use function count;
12
use function preg_match;
13
use function preg_match_all;
14
use function stripcslashes;
15
use function str_replace;
16
use function is_int;
17
use function explode;
18
use function substr_count;
19
use function min;
20
21
trait QueryInputTrait
22
{
23
    /**
24
     * @param TableFieldEntity $field
25
     * @param string $name
26
     * @param string|null $function
27
     * @param array $functions
28
     *
29
     * @return array
30
     */
31
    private function getEntryFunctions(TableFieldEntity $field, string $name, $function, array $functions): array
32
    {
33
        // Input for functions
34
        if ($field->type == "enum") {
35
            return [
36
                'type' => 'name',
37
                'name' => $this->util->html($functions[""] ?? ''),
38
            ];
39
        }
40
        if (count($functions) > 1) {
41
            $hasFunction = (in_array($function, $functions) || isset($functions[$function]));
42
            return [
43
                'type' => 'select',
44
                'name' => "function[$name]",
45
                'options' => $functions,
46
                'selected' => $function === null || $hasFunction ? $function : "",
47
            ];
48
        }
49
        return [
50
            'type' => 'name',
51
            'name' => $this->util->html(reset($functions)),
52
        ];
53
    }
54
55
    /**
56
     * Get options to display edit field
57
     *
58
     * @param TableFieldEntity $field
59
     * @param bool $select
60
     * @param mixed $value
61
     *
62
     * @return array
63
     */
64
    private function getEnumValues(TableFieldEntity $field, bool $select, $value): array
65
    {
66
        $values = [];
67
        if (($select)) {
68
            $values[] = ['value' => '-1', 'checked' => true,
69
                'text' => '<i>' . $this->trans->lang('original') . '</i>'];
70
        }
71
        if ($field->null) {
72
            $values[] =  ['value' => '', 'checked' => $value === null && !$select, 'text' => '<i>NULL</i>'];
73
        }
74
75
        // From functions.inc.php (function enum_input())
76
        $empty = 0; // 0 - empty
77
        $values[] = ['value' => $empty, 'checked' => is_array($value) ? in_array($empty, $value) : $value === 0,
78
            'text' => '<i>' . $this->trans->lang('empty') . '</i>'];
79
80
        preg_match_all("~'((?:[^']|'')*)'~", $field->fullType, $matches);
81
        foreach ($matches[1] as $i => $val) {
82
            $val = stripcslashes(str_replace("''", "'", $val));
83
            $checked = (is_int($value) ? $value == $i + 1 :
84
                (is_array($value) ? in_array($i+1, $value) : $value === $val));
85
            $values[] = ['value' => $i + 1, 'checked' => $checked, 'text' => $this->util->html($val)];
86
        }
87
88
        return $values;
89
    }
90
91
    /**
92
     * @param TableFieldEntity $field
93
     * @param array $attrs
94
     * @param mixed $value
95
     *
96
     * @return array
97
     */
98
    private function getSetInput(TableFieldEntity $field, array $attrs, $value): array
99
    {
100
        $values = [];
101
        preg_match_all("~'((?:[^']|'')*)'~", $field->length, $matches);
102
        foreach ($matches[1] as $i => $val) {
103
            $val = stripcslashes(str_replace("''", "'", $val));
104
            $checked = (is_int($value) ? ($value >> $i) & 1 : in_array($val, explode(",", $value), true));
105
            $values[] = ['value=' => (1 << $i), 'checked' => $checked, 'text' => $this->util->html($val)];
106
        }
107
        return ['type' => 'checkbox', 'attrs' => $attrs, 'values' => $values];
108
    }
109
110
    /**
111
     * @param TableFieldEntity $field
112
     * @param array $attrs
113
     * @param mixed $value
114
     *
115
     * @return array
116
     */
117
    private function getBlobInput(TableFieldEntity $field, array $attrs, $value): array
118
    {
119
        if (preg_match('~text|lob|memo~i', $field->type) && $this->driver->jush() != "sqlite") {
120
            $attrs['cols'] = 50;
121
            $attrs['rows'] = 12;
122
        } else {
123
            $rows = min(12, substr_count($value, "\n") + 1);
124
            $attrs['cols'] = 30;
125
            $attrs['rows'] = $rows;
126
            if ($rows == 1) {
127
                $attrs['style'] = 'height: 1.2em;';
128
            }
129
        }
130
        return ['type' => 'textarea', 'attrs' => $attrs, 'value' => $this->util->html($value)];
131
    }
132
133
    /**
134
     * @param TableFieldEntity $field
135
     *
136
     * @return mixed
137
     */
138
    private function getMaxLength(TableFieldEntity $field)
139
    {
140
        $unsigned = $field->unsigned;
141
        // int(3) is only a display hint
142
        if (!preg_match('~int~', $field->type) &&
143
            preg_match('~^(\d+)(,(\d+))?$~', $field->length, $match)) {
144
            $length1 = preg_match("~binary~", $field->type) ? 2 : 1;
145
            $length2 = ($match[3] ?? false) ? 1 : 0;
146
            $length3 = ($match[2] ?? false) && !$unsigned ? 1 : 0;
147
            return $length1 * $match[1] + $length2 + $length3;
148
        }
149
        if ($this->driver->typeExists($field->type)) {
150
            return $this->driver->type($field->type) + ($unsigned ? 0 : 1);
151
        }
152
        return 0;
153
    }
154
155
    /**
156
     * @param TableFieldEntity $field
157
     * @param array $attrs
158
     *
159
     * @return void
160
     */
161
    private function setDataLength(TableFieldEntity $field, array &$attrs)
162
    {
163
        $maxlength = $this->getMaxLength($field);
164
        if ($this->driver->jush() == 'sql' && $this->driver->minVersion(5.6) && preg_match('~time~', $field->type)) {
165
            $maxlength += 7; // microtime
166
        }
167
        if ($maxlength > 0) {
168
            $attrs['data-maxlength'] = $maxlength;
169
        }
170
        if (preg_match('~char|binary~', $field->type) && $maxlength > 20) {
171
            $attrs['size'] = 40;
172
        }
173
    }
174
175
    /**
176
     * @param TableFieldEntity $field
177
     * @param array $attrs
178
     *
179
     * @return void
180
     */
181
    private function setDataType(TableFieldEntity $field, array &$attrs)
182
    {
183
        // type='date' and type='time' display localized value which may be confusing,
184
        // type='datetime' uses 'T' as date and time separator
185
        if (preg_match('~(?<!o)int(?!er)~', $field->type) && !preg_match('~\[\]~', $field->fullType)) {
186
            $attrs['type'] = 'number';
187
        }
188
    }
189
190
    /**
191
     * @param TableFieldEntity $field
192
     * @param array $attrs
193
     * @param mixed $value
194
     * @param string|null $function
195
     * @param array $functions
196
     *
197
     * @return array
198
     */
199
    private function getDefaultInput(TableFieldEntity $field, array $attrs, $value, $function, array $functions): array
200
    {
201
        $this->setDataLength($field, $attrs);
202
        $hasFunction = (in_array($function, $functions) || isset($functions[$function]));
203
        if (!$hasFunction || $function === "") {
204
            $this->setDataType($field, $attrs);
205
        }
206
        $attrs['value'] = $this->util->html($value);
207
        return ['type' => 'input', 'attrs' => $attrs];
208
    }
209
210
    /**
211
     * @param TableFieldEntity $field
212
     * @param string $name
213
     * @param mixed $value
214
     * @param string|null $function
215
     * @param array $functions
216
     * @param array $options
217
     *
218
     * @return array
219
     */
220
    private function getEntryInput(TableFieldEntity $field, string $name, $value, $function, array $functions, array $options): array
221
    {
222
        $attrs = ['name' => "fields[$name]"];
223
        if ($field->type == "enum") {
224
            return ['type' => 'radio', 'attrs' => $attrs,
225
                'values' => $this->getEnumValues($field, isset($options["select"]), $value)];
226
        }
227
        if (preg_match('~bool~', $field->type)) {
228
            $attrs['checked'] = preg_match('~^(1|t|true|y|yes|on)$~i', $value);
229
            return ['type' => 'bool', 'attrs' => $attrs];
230
        }
231
        if ($field->type == "set") {
232
            return $this->getSetInput($field, $attrs, $value);
233
        }
234
        if (preg_match('~blob|bytea|raw|file~', $field->type) && $this->util->iniBool("file_uploads")) {
235
            $attrs['name'] = "fields-$name";
236
            return ['type' => 'file', 'attrs' => $attrs];
237
        }
238
        if (preg_match('~text|lob|memo~i', $field->type) || preg_match("~\n~", $value)) {
239
            return $this->getBlobInput($field, $attrs, $value);
240
        }
241
        if ($function == "json" || preg_match('~^jsonb?$~', $field->type)) {
242
            $attrs['cols'] = 50;
243
            $attrs['rows'] = 12;
244
            return ['type' => 'textarea', 'attrs' => $attrs, 'value' => $this->util->html($value)];
245
        }
246
        return $this->getDefaultInput($field, $attrs, $value, $function, $functions);
247
    }
248
249
    /**
250
     * Get data for an input field
251
     *
252
     * @param TableFieldEntity $field
253
     * @param mixed $value
254
     * @param string|null $function
255
     * @param array $options
256
     *
257
     * @return array
258
     */
259
    protected function getFieldInput(TableFieldEntity $field, $value, $function, array $options): array
260
    {
261
        // From functions.inc.php (function input($field, $value, $function))
262
        $name = $this->util->html($this->util->bracketEscape($field->name));
263
        $save = $options["save"];
264
        $reset = ($this->driver->jush() == "mssql" && $field->autoIncrement);
265
        if (is_array($value) && !$function) {
266
            $value = json_encode($value, JSON_PRETTY_PRINT);
267
            $function = "json";
268
        }
269
        if ($reset && !$save) {
270
            $function = null;
271
        }
272
        $functions = [];
273
        if ($reset) {
274
            $functions["orig"] = $this->trans->lang('original');
275
        }
276
        $functions += $this->util->editFunctions($field);
277
        return [
278
            'type' => $this->util->html($field->fullType),
279
            'name' => $name,
280
            'field' => [
281
                'type' => $field->type,
282
            ],
283
            'functions' => $this->getEntryFunctions($field, $name, $function, $functions),
284
            'input' => $this->getEntryInput($field, $name, $value, $function, $functions, $options),
285
        ];
286
    }
287
}
288