Passed
Branch main (6b0a6d)
by Thierry
03:16
created

QueryInputTrait::getEntryFunctions()   A

Complexity

Conditions 6
Paths 10

Size

Total Lines 21
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 14
c 0
b 0
f 0
nc 10
nop 4
dl 0
loc 21
rs 9.2222
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
    private function getMaxLength(TableFieldEntity $field)
134
    {
135
        $unsigned = $field->unsigned;
136
        // int(3) is only a display hint
137
        if (!preg_match('~int~', $field->type) &&
138
            preg_match('~^(\d+)(,(\d+))?$~', $field->length, $match)) {
139
            $length1 = preg_match("~binary~", $field->type) ? 2 : 1;
140
            $length2 = ($match[3] ?? false) ? 1 : 0;
141
            $length3 = ($match[2] ?? false) && !$unsigned ? 1 : 0;
142
            return $length1 * $match[1] + $length2 + $length3;
143
        }
144
        if ($this->driver->typeExists($field->type)) {
145
            return $this->driver->type($field->type) + ($unsigned ? 0 : 1);
146
        }
147
        return 0;
148
    }
149
150
    /**
151
     * @param TableFieldEntity $field
152
     * @param array $attrs
153
     * @param mixed $value
154
     * @param string|null $function
155
     * @param array $functions
156
     *
157
     * @return array
158
     */
159
    private function getDefaultInput(TableFieldEntity $field, array $attrs, $value, $function, array $functions): array
160
    {
161
        $maxlength = $this->getMaxLength($field);
162
        if ($this->driver->jush() == 'sql' && $this->driver->minVersion(5.6) && preg_match('~time~', $field->type)) {
163
            $maxlength += 7; // microtime
164
        }
165
        if ($maxlength > 0) {
166
            $attrs['data-maxlength'] = $maxlength;
167
        }
168
        // type='date' and type='time' display localized value which may be confusing,
169
        // type='datetime' uses 'T' as date and time separator
170
        $hasFunction = (in_array($function, $functions) || isset($functions[$function]));
171
        if ((!$hasFunction || $function === "") &&
172
            preg_match('~(?<!o)int(?!er)~', $field->type) &&
173
            !preg_match('~\[\]~', $field->fullType)) {
174
            $attrs['type'] = 'number';
175
        }
176
        if (preg_match('~char|binary~', $field->type) && $maxlength > 20) {
177
            $attrs['size'] = 40;
178
        }
179
        $attrs['value'] = $this->util->html($value);
180
        return ['type' => 'input', 'attrs' => $attrs];
181
    }
182
183
    /**
184
     * @param TableFieldEntity $field
185
     * @param string $name
186
     * @param mixed $value
187
     * @param string|null $function
188
     * @param array $functions
189
     * @param array $options
190
     *
191
     * @return array
192
     */
193
    private function getEntryInput(TableFieldEntity $field, string $name, $value, $function, array $functions, array $options): array
194
    {
195
        $attrs = ['name' => "fields[$name]"];
196
        if ($field->type == "enum") {
197
            return ['type' => 'radio', 'attrs' => $attrs,
198
                'values' => $this->getEnumValues($field, isset($options["select"]), $value)];
199
        }
200
        if (preg_match('~bool~', $field->type)) {
201
            $attrs['checked'] = preg_match('~^(1|t|true|y|yes|on)$~i', $value);
202
            return ['type' => 'bool', 'attrs' => $attrs];
203
        }
204
        if ($field->type == "set") {
205
            return $this->getSetInput($field, $attrs, $value);
206
        }
207
        if (preg_match('~blob|bytea|raw|file~', $field->type) && $this->util->iniBool("file_uploads")) {
208
            $attrs['name'] = "fields-$name";
209
            return ['type' => 'file', 'attrs' => $attrs];
210
        }
211
        if (preg_match('~text|lob|memo~i', $field->type) || preg_match("~\n~", $value)) {
212
            return $this->getBlobInput($field, $attrs, $value);
213
        }
214
        if ($function == "json" || preg_match('~^jsonb?$~', $field->type)) {
215
            $attrs['cols'] = 50;
216
            $attrs['rows'] = 12;
217
            return ['type' => 'textarea', 'attrs' => $attrs, 'value' => $this->util->html($value)];
218
        }
219
        return $this->getDefaultInput($field, $attrs, $value, $function, $functions);
220
    }
221
222
    /**
223
     * Get data for an input field
224
     *
225
     * @param TableFieldEntity $field
226
     * @param mixed $value
227
     * @param string|null $function
228
     * @param array $options
229
     *
230
     * @return array
231
     */
232
    protected function getFieldInput(TableFieldEntity $field, $value, $function, array $options): array
233
    {
234
        // From functions.inc.php (function input($field, $value, $function))
235
        $name = $this->util->html($this->util->bracketEscape($field->name));
236
        $save = $options["save"];
237
        $reset = ($this->driver->jush() == "mssql" && $field->autoIncrement);
238
        if (is_array($value) && !$function) {
239
            $value = json_encode($value, JSON_PRETTY_PRINT);
240
            $function = "json";
241
        }
242
        if ($reset && !$save) {
243
            $function = null;
244
        }
245
        $functions = [];
246
        if ($reset) {
247
            $functions["orig"] = $this->trans->lang('original');
248
        }
249
        $functions += $this->util->editFunctions($field);
250
        return [
251
            'type' => $this->util->html($field->fullType),
252
            'name' => $name,
253
            'field' => [
254
                'type' => $field->type,
255
            ],
256
            'functions' => $this->getEntryFunctions($field, $name, $function, $functions),
257
            'input' => $this->getEntryInput($field, $name, $value, $function, $functions, $options),
258
        ];
259
    }
260
}
261