|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Lagdo\DbAdmin\Db\Page\Dml; |
|
4
|
|
|
|
|
5
|
|
|
use Lagdo\DbAdmin\Db\Page\AppPage; |
|
6
|
|
|
use Lagdo\DbAdmin\Driver\DriverInterface; |
|
7
|
|
|
use Lagdo\DbAdmin\Driver\Utils\Utils; |
|
8
|
|
|
|
|
9
|
|
|
use function count; |
|
10
|
|
|
use function explode; |
|
11
|
|
|
use function in_array; |
|
12
|
|
|
use function is_array; |
|
13
|
|
|
use function is_string; |
|
14
|
|
|
use function min; |
|
15
|
|
|
use function preg_match; |
|
16
|
|
|
use function preg_match_all; |
|
17
|
|
|
use function stripcslashes; |
|
18
|
|
|
use function str_replace; |
|
19
|
|
|
use function substr_count; |
|
20
|
|
|
|
|
21
|
|
|
/** |
|
22
|
|
|
* Make data for HTML elements in the user forms for data row insert and update. |
|
23
|
|
|
*/ |
|
24
|
|
|
class DataFieldInput |
|
25
|
|
|
{ |
|
26
|
|
|
/** |
|
27
|
|
|
* The constructor |
|
28
|
|
|
* |
|
29
|
|
|
* @param AppPage $page |
|
30
|
|
|
* @param DriverInterface $driver |
|
31
|
|
|
* @param Utils $utils |
|
32
|
|
|
* @param string $action |
|
33
|
|
|
* @param string $operation |
|
34
|
|
|
*/ |
|
35
|
|
|
public function __construct(private AppPage $page, private DriverInterface $driver, |
|
36
|
|
|
private Utils $utils, private string $action, private string $operation) |
|
37
|
|
|
{} |
|
38
|
|
|
|
|
39
|
|
|
/** |
|
40
|
|
|
* @param FieldEditEntity $editField |
|
41
|
|
|
* @param string $fieldName |
|
42
|
|
|
* @param string|null $enumValue |
|
43
|
|
|
* |
|
44
|
|
|
* @return array |
|
45
|
|
|
*/ |
|
46
|
|
|
private function getCheckedAttr(FieldEditEntity $editField, string $fieldName, string|null $enumValue): array |
|
47
|
|
|
{ |
|
48
|
|
|
$checked = is_array($editField->value) ? |
|
49
|
|
|
in_array($fieldName, $editField->value) : $editField->value === $enumValue; |
|
50
|
|
|
return $checked ? ['checked' => 'checked'] : []; |
|
51
|
|
|
} |
|
52
|
|
|
|
|
53
|
|
|
/** |
|
54
|
|
|
* Get data for enum or set input field |
|
55
|
|
|
* |
|
56
|
|
|
* @param FieldEditEntity $editField |
|
57
|
|
|
*/ |
|
58
|
|
|
private function itemList(FieldEditEntity $editField, array $attrs, string $default = ""): array|null |
|
59
|
|
|
{ |
|
60
|
|
|
if ($editField->type !== 'enum' && $editField->type !== 'set' ) { |
|
61
|
|
|
// Only for enums and sets |
|
62
|
|
|
return null; |
|
63
|
|
|
} |
|
64
|
|
|
|
|
65
|
|
|
// From html.inc.php: function enum_input(string $type, string $attrs, array $field, $value, string $empty = "") |
|
66
|
|
|
$prefix = $editField->type === 'enum' ? 'val-' : ''; |
|
67
|
|
|
$items = []; |
|
68
|
|
|
if ($editField->field->null && $prefix) { |
|
69
|
|
|
$checkedAttr = $this->getCheckedAttr($editField, 'null', null); |
|
70
|
|
|
$items[] = [ |
|
71
|
|
|
'attrs' => [ |
|
72
|
|
|
...$attrs, |
|
73
|
|
|
'id' => "{$attrs['id']}_null", // Overwrite the id value in the $attrs array. |
|
74
|
|
|
...$checkedAttr, |
|
75
|
|
|
], |
|
76
|
|
|
'label' => "<i>$default</i>", |
|
77
|
|
|
'value' => 'null', |
|
78
|
|
|
]; |
|
79
|
|
|
} |
|
80
|
|
|
|
|
81
|
|
|
preg_match_all("~'((?:[^']|'')*)'~", $editField->field->length, $matches); |
|
82
|
|
|
foreach (($matches[1] ?? []) as $enumValue) { |
|
83
|
|
|
$enumValue = stripcslashes(str_replace("''", "'", $enumValue)); |
|
84
|
|
|
$fieldName = "$prefix$enumValue"; |
|
85
|
|
|
$checkedAttr = $this->getCheckedAttr($editField, $fieldName, $enumValue); |
|
86
|
|
|
$items[] = [ |
|
87
|
|
|
'attrs' => [ |
|
88
|
|
|
...$attrs, |
|
89
|
|
|
'id' => "{$attrs['id']}_{$enumValue}", // Overwrite the id value in the $attrs array. |
|
90
|
|
|
...$checkedAttr, |
|
91
|
|
|
], |
|
92
|
|
|
'label' => $this->utils->html($enumValue), |
|
93
|
|
|
'value' => $this->utils->html($fieldName), |
|
94
|
|
|
]; |
|
95
|
|
|
} |
|
96
|
|
|
|
|
97
|
|
|
return $items; |
|
98
|
|
|
} |
|
99
|
|
|
|
|
100
|
|
|
/** |
|
101
|
|
|
* @param FieldEditEntity $editField |
|
102
|
|
|
* @param array $attrs |
|
103
|
|
|
* |
|
104
|
|
|
* @return array |
|
105
|
|
|
*/ |
|
106
|
|
|
private function getEnumFieldInput(FieldEditEntity $editField, array $attrs): array |
|
107
|
|
|
{ |
|
108
|
|
|
// From adminer.inc.php: function editInput(?string $table, array $field, string $attrs, $value): string |
|
109
|
|
|
$values = ['field' => 'enum']; |
|
110
|
|
|
if ($this->action === 'select') { |
|
111
|
|
|
$values['orig'] = [ |
|
112
|
|
|
'attrs' => [ |
|
113
|
|
|
...$attrs, |
|
114
|
|
|
'checked' => 'checked', |
|
115
|
|
|
], |
|
116
|
|
|
'label' => '<i>' . $this->utils->trans->lang('original') . '</i>', |
|
117
|
|
|
'value' => 'orig', |
|
118
|
|
|
]; |
|
119
|
|
|
} |
|
120
|
|
|
$values['items'] = $this->itemList($editField, $attrs, 'NULL'); |
|
121
|
|
|
|
|
122
|
|
|
return $values; |
|
123
|
|
|
} |
|
124
|
|
|
|
|
125
|
|
|
/** |
|
126
|
|
|
* @param FieldEditEntity $editField |
|
127
|
|
|
* @param array $attrs |
|
128
|
|
|
* |
|
129
|
|
|
* @return array |
|
130
|
|
|
*/ |
|
131
|
|
|
private function getSetFieldInput(FieldEditEntity $editField, array $attrs): array |
|
132
|
|
|
{ |
|
133
|
|
|
if (is_string($editField->value)) { |
|
134
|
|
|
$editField->value = explode(",", $editField->value); |
|
135
|
|
|
} |
|
136
|
|
|
|
|
137
|
|
|
return [ |
|
138
|
|
|
'field' => 'set', |
|
139
|
|
|
'items' => $this->itemList($editField, $attrs), |
|
140
|
|
|
]; |
|
141
|
|
|
} |
|
142
|
|
|
|
|
143
|
|
|
/** |
|
144
|
|
|
* @param FieldEditEntity $editField |
|
145
|
|
|
* @param array $attrs |
|
146
|
|
|
* |
|
147
|
|
|
* @return array |
|
148
|
|
|
*/ |
|
149
|
|
|
private function getBoolFieldInput(FieldEditEntity $editField, array $attrs): array |
|
150
|
|
|
{ |
|
151
|
|
|
$checkedAttr = $editField->isChecked() ? ['checked' => 'checked'] : []; |
|
152
|
|
|
return [ |
|
153
|
|
|
'field' => 'bool', |
|
154
|
|
|
'attrs' => [ |
|
155
|
|
|
'hidden' => [ |
|
156
|
|
|
...$attrs, |
|
157
|
|
|
'id' => '', // Unset the id value in the $attrs array |
|
158
|
|
|
'value' => '0', |
|
159
|
|
|
], |
|
160
|
|
|
'checkbox' => [ |
|
161
|
|
|
...$attrs, |
|
162
|
|
|
'value' => '1', |
|
163
|
|
|
...$checkedAttr, |
|
164
|
|
|
], |
|
165
|
|
|
], |
|
166
|
|
|
]; |
|
167
|
|
|
} |
|
168
|
|
|
|
|
169
|
|
|
/** |
|
170
|
|
|
* @param FieldEditEntity $editField |
|
171
|
|
|
* |
|
172
|
|
|
* @return bool |
|
173
|
|
|
*/ |
|
174
|
|
|
private function isBlob(FieldEditEntity $editField): bool |
|
175
|
|
|
{ |
|
176
|
|
|
return $this->utils->isBlob($editField->field) && $this->utils->iniBool("file_uploads"); |
|
177
|
|
|
} |
|
178
|
|
|
|
|
179
|
|
|
/** |
|
180
|
|
|
* @param FieldEditEntity $editField |
|
181
|
|
|
* @param array $attrs |
|
182
|
|
|
* |
|
183
|
|
|
* @return array |
|
184
|
|
|
*/ |
|
185
|
|
|
private function getFileFieldInput(FieldEditEntity $editField, array $attrs): array |
|
186
|
|
|
{ |
|
187
|
|
|
return [ |
|
188
|
|
|
'field' => 'file', |
|
189
|
|
|
'attrs' => [ |
|
190
|
|
|
'id' => $attrs['id'], |
|
191
|
|
|
'name' => "fields-{$editField->name}", |
|
192
|
|
|
], |
|
193
|
|
|
]; |
|
194
|
|
|
} |
|
195
|
|
|
|
|
196
|
|
|
/** |
|
197
|
|
|
* @param FieldEditEntity $editField |
|
198
|
|
|
* @param array $attrs |
|
199
|
|
|
* |
|
200
|
|
|
* @return array |
|
201
|
|
|
*/ |
|
202
|
|
|
private function getJsonFieldInput(FieldEditEntity $editField, array $attrs): array |
|
203
|
|
|
{ |
|
204
|
|
|
return [ |
|
205
|
|
|
'field' => 'json', |
|
206
|
|
|
'attrs' => [ |
|
207
|
|
|
...$attrs, |
|
208
|
|
|
'cols' => '50', |
|
209
|
|
|
'rows' => '5', |
|
210
|
|
|
'class' => 'jush-js', |
|
211
|
|
|
], |
|
212
|
|
|
'value' => $this->utils->str->html($editField->value ?? ''), |
|
213
|
|
|
]; |
|
214
|
|
|
} |
|
215
|
|
|
|
|
216
|
|
|
/** |
|
217
|
|
|
* @param FieldEditEntity $editField |
|
218
|
|
|
* |
|
219
|
|
|
* @return bool |
|
220
|
|
|
*/ |
|
221
|
|
|
private function textSizeIsFixed(FieldEditEntity $editField): bool |
|
222
|
|
|
{ |
|
223
|
|
|
return ($editField->isText() && $this->driver->jush() !== 'sqlite') || $editField->isSearch(); |
|
224
|
|
|
} |
|
225
|
|
|
|
|
226
|
|
|
/** |
|
227
|
|
|
* @param FieldEditEntity $editField |
|
228
|
|
|
* @param array $attrs |
|
229
|
|
|
* |
|
230
|
|
|
* @return array |
|
231
|
|
|
*/ |
|
232
|
|
|
private function getTextFieldInput(FieldEditEntity $editField, array $attrs): array |
|
233
|
|
|
{ |
|
234
|
|
|
$fieldAttrs = $this->textSizeIsFixed($editField) ? [ |
|
235
|
|
|
'cols' => '50', |
|
236
|
|
|
'rows' => '5', |
|
237
|
|
|
] : [ |
|
238
|
|
|
'cols' => '30', |
|
239
|
|
|
'rows' => min(5, substr_count($editField->value ?? '', "\n") + 1), |
|
240
|
|
|
]; |
|
241
|
|
|
return [ |
|
242
|
|
|
'field' => 'text', |
|
243
|
|
|
'attrs' => [ |
|
244
|
|
|
...$attrs, |
|
245
|
|
|
...$fieldAttrs, |
|
246
|
|
|
], |
|
247
|
|
|
'value' => $this->utils->html($editField->value ?? ''), |
|
248
|
|
|
]; |
|
249
|
|
|
} |
|
250
|
|
|
|
|
251
|
|
|
/** |
|
252
|
|
|
* @param FieldEditEntity $editField |
|
253
|
|
|
* |
|
254
|
|
|
* @return int |
|
255
|
|
|
*/ |
|
256
|
|
|
private function getInputFieldMaxLength(FieldEditEntity $editField): int |
|
257
|
|
|
{ |
|
258
|
|
|
$unsigned = $editField->field->unsigned; |
|
259
|
|
|
$length = $editField->field->length; |
|
260
|
|
|
$type = $editField->type; |
|
261
|
|
|
$types = $this->driver->types(); |
|
262
|
|
|
|
|
263
|
|
|
$maxlength = (!preg_match('~int~', $type) && |
|
264
|
|
|
preg_match('~^(\d+)(,(\d+))?$~', $length, $match) ? |
|
265
|
|
|
((preg_match("~binary~", $type) ? 2 : 1) * |
|
266
|
|
|
($match[1] ?? 0) + (($match[3] ?? false) ? 1 : 0) + |
|
267
|
|
|
(($match[2] ?? false) && !$unsigned ? 1 : 0)) : |
|
268
|
|
|
(isset($types[$type]) ? $types[$type] + ($unsigned ? 0 : 1) : 0) |
|
269
|
|
|
); |
|
270
|
|
|
|
|
271
|
|
|
return $this->driver->jush() === 'sql' && |
|
272
|
|
|
$this->driver->minVersion(5.6) && |
|
273
|
|
|
preg_match('~time~', $type) ? |
|
274
|
|
|
$maxlength += 7 : // microtime |
|
275
|
|
|
$maxlength; |
|
276
|
|
|
} |
|
277
|
|
|
|
|
278
|
|
|
/** |
|
279
|
|
|
* @param FieldEditEntity $editField |
|
280
|
|
|
* @param array $attrs |
|
281
|
|
|
* |
|
282
|
|
|
* @return array |
|
283
|
|
|
*/ |
|
284
|
|
|
private function getDefaultFieldInput(FieldEditEntity $editField, array $attrs): array |
|
285
|
|
|
{ |
|
286
|
|
|
$maxlength = $this->getInputFieldMaxLength($editField); |
|
287
|
|
|
// type='date' and type='time' display localized value which may be confusing, |
|
288
|
|
|
// type='datetime' uses 'T' as date and time separator |
|
289
|
|
|
|
|
290
|
|
|
if ($editField->isNumber()) { |
|
291
|
|
|
$attrs['type'] = 'number'; |
|
292
|
|
|
} |
|
293
|
|
|
if ($maxlength > 0) { |
|
294
|
|
|
$attrs['data-maxlength'] = $maxlength; |
|
295
|
|
|
} |
|
296
|
|
|
if ($editField->bigSize($maxlength)) { |
|
297
|
|
|
$attrs['size'] = $maxlength > 99 ? '60' : '40'; |
|
298
|
|
|
} |
|
299
|
|
|
|
|
300
|
|
|
return [ |
|
301
|
|
|
'field' => 'input', |
|
302
|
|
|
'attrs' => $attrs, |
|
303
|
|
|
'value' => $this->utils->html($editField->value ?? ''), |
|
304
|
|
|
]; |
|
305
|
|
|
} |
|
306
|
|
|
|
|
307
|
|
|
/** |
|
308
|
|
|
* Get the input field for value |
|
309
|
|
|
* |
|
310
|
|
|
* @param FieldEditEntity $editField |
|
311
|
|
|
* @param bool|null $autofocus |
|
312
|
|
|
* |
|
313
|
|
|
* @return array |
|
314
|
|
|
*/ |
|
315
|
|
|
private function getFieldValueInput(FieldEditEntity $editField, bool|null $autofocus): array |
|
316
|
|
|
{ |
|
317
|
|
|
// From input(array $field, $value, ?string $function, ?bool $autofocus = false) in html.inc.php |
|
318
|
|
|
$attrs = [ |
|
319
|
|
|
'id' => "fields_{$editField->name}", |
|
320
|
|
|
'name' => $editField->isEnum() || $editField->isSet() ? |
|
321
|
|
|
"fields[{$editField->name}][]" : "fields[{$editField->name}]", |
|
322
|
|
|
]; |
|
323
|
|
|
if ($editField->isDisabled()) { |
|
324
|
|
|
$attrs['disabled'] = 'disabled'; |
|
325
|
|
|
} |
|
326
|
|
|
if ($autofocus) { |
|
327
|
|
|
$attrs['autofocus'] = true; |
|
328
|
|
|
} |
|
329
|
|
|
|
|
330
|
|
|
// This function is implemented only for MySQL. |
|
331
|
|
|
// Todo: check what it actually does. |
|
332
|
|
|
// echo driver()->unconvertFunction($field) . " "; |
|
333
|
|
|
|
|
334
|
|
|
return match(true) { |
|
335
|
|
|
$editField->isEnum() => $this->getEnumFieldInput($editField, $attrs), |
|
336
|
|
|
$editField->isBool() => $this->getBoolFieldInput($editField, $attrs), |
|
337
|
|
|
$editField->isSet() => $this->getSetFieldInput($editField, $attrs), |
|
338
|
|
|
$this->isBlob($editField) => $this->getFileFieldInput($editField, $attrs), |
|
339
|
|
|
$editField->isJson() => $this->getJsonFieldInput($editField, $attrs), |
|
340
|
|
|
$editField->editText() => $this->getTextFieldInput($editField, $attrs), |
|
341
|
|
|
default => $this->getDefaultFieldInput($editField, $attrs), |
|
342
|
|
|
}; |
|
343
|
|
|
} |
|
344
|
|
|
|
|
345
|
|
|
/** |
|
346
|
|
|
* Get the input field for function |
|
347
|
|
|
* |
|
348
|
|
|
* @param FieldEditEntity $editField |
|
349
|
|
|
* |
|
350
|
|
|
* @return array|null |
|
351
|
|
|
*/ |
|
352
|
|
|
private function getFieldFunctionInput(FieldEditEntity $editField): array|null |
|
353
|
|
|
{ |
|
354
|
|
|
// From html.inc.php: function input(array $field, $value, ?string $function, ?bool $autofocus = false) |
|
355
|
|
|
if ($editField->type === 'enum' || $editField->function === null) { |
|
356
|
|
|
return null; // No function for enum values |
|
357
|
|
|
} |
|
358
|
|
|
|
|
359
|
|
|
if (count($editField->functions) < 2) { |
|
360
|
|
|
return [ |
|
361
|
|
|
'label' => $this->utils->str->html($editField->functions[0] ?? ''), |
|
362
|
|
|
]; |
|
363
|
|
|
} |
|
364
|
|
|
|
|
365
|
|
|
$disabledAttr = $editField->isDisabled() ? ['disabled' => 'disabled'] : []; |
|
366
|
|
|
return [ |
|
367
|
|
|
'select' => [ |
|
368
|
|
|
'attrs' => [ |
|
369
|
|
|
'name' => "function[{$editField->name}]", |
|
370
|
|
|
...$disabledAttr, |
|
371
|
|
|
], |
|
372
|
|
|
'options' => $editField->functions, |
|
373
|
|
|
'value' => $editField->functionValue(), |
|
374
|
|
|
], |
|
375
|
|
|
]; |
|
376
|
|
|
} |
|
377
|
|
|
|
|
378
|
|
|
/** |
|
379
|
|
|
* @param FieldEditEntity $editField |
|
380
|
|
|
* @param bool|null $autofocus |
|
381
|
|
|
* |
|
382
|
|
|
* @return void |
|
383
|
|
|
*/ |
|
384
|
|
|
public function setFieldInputValues(FieldEditEntity $editField, bool|null $autofocus): void |
|
385
|
|
|
{ |
|
386
|
|
|
$editField->functionInput = $this->getFieldFunctionInput($editField); |
|
387
|
|
|
$editField->valueInput = $this->getFieldValueInput($editField, $autofocus); |
|
388
|
|
|
} |
|
389
|
|
|
} |
|
390
|
|
|
|