HelperFormElement.php 15.5 KB
Newer Older
Carsten  Rose's avatar
Carsten Rose committed
1
2
3
4
5
6
7
8
9
10
11
12
<?php
/**
 * Created by PhpStorm.
 * User: crose
 * Date: 1/26/16
 * Time: 11:25 AM
 */

namespace qfq;

use qfq;

13
14
15
16
require_once(__DIR__ . '/../../core/store/Store.php');
require_once(__DIR__ . '/../../core/Constants.php');
require_once(__DIR__ . '/../../core/helper/KeyValueStringParser.php');
require_once(__DIR__ . '/../../core/exceptions/UserFormException.php');
Carsten  Rose's avatar
Carsten Rose committed
17

18
19
20
21
/**
 * Class HelperFormElement
 * @package qfq
 */
22
class HelperFormElement {
Carsten  Rose's avatar
Carsten Rose committed
23

24
    /**
25
     * Expand column $keyName to row array as virtual columns.
26
     * E.g.: [ 'id' => '1', 'name' => 'John', 'parameter' => 'detail=xId:grId\nShowEmptyAtStart=1' ] becomes:
Carsten  Rose's avatar
Carsten Rose committed
27
28
29
     *  [ 'id' => '1', 'name' => 'John', 'parameter' => 'detail=xId:grId\nShowEmptyAtStart=1', 'detail' => 'xId:grId',
     *  'showEmptyAtStart'='1']
     *
30
     * @param array $elements
31
     * @param string $keyName Typically F_PARAMETER or FE_PARAMETER (both: 'parameter')
Carsten  Rose's avatar
Carsten Rose committed
32
     *
33
34
     * @throws CodeException
     * @throws UserFormException
35
     * @throws UserReportException
36
     */
37
    public static function explodeParameterInArrayElements(array &$elements, $keyName) {
38
        foreach ($elements AS $key => $element) {
39
            self::explodeParameter($element, $keyName);
40
41
42
43
            $elements[$key] = $element;
        }
    }

44
45
46

    /**
     * @param array $elements
Carsten  Rose's avatar
Carsten Rose committed
47
     *
48
49
50
51
52
53
54
55
56
57
     * @return array
     */
    public static function formElementSetDefault(array $elements) {
        foreach ($elements AS $key => $element) {
            $elements[$key][FE_TG_INDEX] = 0;
        }

        return $elements;
    }

Carsten  Rose's avatar
Carsten Rose committed
58
    /**
59
     * Take all rows from field $element[$keyName] and merge them with $element itself. '$element' grows in size.
Carsten  Rose's avatar
Carsten Rose committed
60
     *
61
62
     * @param array $element
     * @param string $keyName Typically F_PARAMETER or FE_PARAMETER (both: 'parameter')
Carsten  Rose's avatar
Carsten Rose committed
63
     *
64
     * @param bool $flagAllowOverwrite
65
     * @throws CodeException
66
     * @throws UserFormException
67
     * @throws UserReportException
Carsten  Rose's avatar
Carsten Rose committed
68
     */
69
    public static function explodeParameter(array &$element, $keyName, $flagAllowOverwrite = false) {
70
        // Something to explode?
71
        if (isset($element[$keyName]) && $element[$keyName] !== '') {
72
            // Explode
73
            $arr = KeyValueStringParser::parse($element[$keyName], "=", "\n");
74
75
76
77
78
79
80
81
82
83
84

            if (!$flagAllowOverwrite) {
                // Check if some of the exploded keys conflict with existing keys
                $checkKeys = array_keys($arr);
                foreach ($checkKeys AS $checkKey) {
                    if (isset($element[$checkKey])) {
                        $store = Store::getInstance();
                        $store->setVar(SYSTEM_FORM_ELEMENT, Logger::formatFormElementName($element), STORE_SYSTEM);
                        $store->setVar(SYSTEM_FORM_ELEMENT_COLUMN, $keyName, STORE_SYSTEM);
                        throw new UserFormException("Found reserved keyname '$checkKey'", ERROR_RESERVED_KEY_NAME);
                    }
Carsten  Rose's avatar
Carsten Rose committed
85
86
                }
            }
87
            $element = array_merge($element, $arr);
88
            $element[$keyName] = ''; // to not expand it a second time
89
90
91
        }
    }

92
93
94
95
96
    /**
     * Take language specific definitions and overwrite the default values.
     *
     * @param array $formSpecFeSpecNative
     *
97
     * @param $parameterLanguageFieldName
98
     * @return array
99
     * @throws CodeException
100
     * @throws UserFormException
101
     * @throws UserReportException
102
103
104
105
106
107
108
109
110
     */
    public static function setLanguage(array $formSpecFeSpecNative, $parameterLanguageFieldName) {

        if (is_string($parameterLanguageFieldName) && isset($formSpecFeSpecNative[$parameterLanguageFieldName])) {
            self::explodeParameter($formSpecFeSpecNative, $parameterLanguageFieldName, true);
        }

        return $formSpecFeSpecNative;
    }
Carsten  Rose's avatar
Carsten Rose committed
111

112
    /**
113
     * Build the FE name: <field>-<record index)
Carsten  Rose's avatar
Carsten Rose committed
114
     *
Carsten  Rose's avatar
Carsten Rose committed
115
     * @param array $formElement
116
     * @param string $id
Carsten  Rose's avatar
Carsten Rose committed
117
     *
118
119
     * @return string
     */
120
121
122
    public static function buildFormElementName(array $formElement, $id) {
        $field = ($formElement[FE_NAME] == '') ? $formElement[FE_ID] : $formElement[FE_NAME];

123
        return "$field" . HTML_DELIMITER_NAME . "$id";
124
125
    }

126
127
128
129
130
131
132
133
134
135
136
137
    /**
     * Build the internal FE name for an imageCut element (used only in SIP): <field>-imageCut
     *
     * @param array $formElement
     * @return string
     */
    public static function AppendFormElementNameImageCut(array $formElement) {
        $field = ($formElement[FE_NAME] == '') ? $formElement[FE_ID] : $formElement[FE_NAME];

        return "$field" . HTML_DELIMITER_NAME . FE_TYPE_IMAGE_CUT;
    }

138
139
    /**
     * Build the FE id: <$formId>-<$formElementId>-<$formElementCopy>
Carsten  Rose's avatar
Carsten Rose committed
140
     * Attention: Radio's get's an additional index count as fourth parameter (not here).
141
142
143
144
145
     *
     * @param $formId
     * @param $formElementId
     * @param $recordId
     * @param $formElementCopy
Carsten  Rose's avatar
Carsten Rose committed
146
     *
147
148
149
     * @return string
     */
    public static function buildFormElementId($formId, $formElementId, $recordId, $formElementCopy) {
150
        return "$formId" . HTML_DELIMITER_ID . "$formElementId" . HTML_DELIMITER_ID . "$recordId" . HTML_DELIMITER_ID . "$formElementCopy";
151
152
    }

153

154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
    /**
     * In an array for $feSpecNative, set FE_HTML_ID for all fe.class=FE_CONTAINER Elements.
     *
     * @param array $feSpecNative
     * @param $formId
     * @param $recordId
     * @param int $formElementCopy
     * @return array
     */
    public static function setFeContainerFormElementId(array $feSpecNative, $formId, $recordId, $formElementCopy = 0) {

        foreach ($feSpecNative as $key => $fe) {

            switch ($fe[FE_CLASS]) {
                case FE_CLASS_CONTAINER:
                    $feSpecNative[$key][FE_HTML_ID] = self::buildFormElementId($formId, $fe[FE_ID], $recordId, $formElementCopy);
                    break;
                default:
                    break;
            }

        }

        return $feSpecNative;
    }

180
    /**
Carsten  Rose's avatar
Carsten Rose committed
181
182
     * Checkboxen, belonging to one element, grouped together by name: <fe>_<field>_<index>
     *
183
184
     * @param string $field
     * @param string $index
Carsten  Rose's avatar
Carsten Rose committed
185
     *
186
187
     * @return string
     */
188
189
    public static function prependFormElementNameCheckBoxMulti($field, $index) {
        return '_' . $index . '_' . $field;
190
191
    }

192
193
194
195
196
    /**
     * Check all FormElements if there are some with the attribute FE_RETYPE.
     * If yes: duplicate such elements and update FE_NAME, FE_LABEL, FE_NOTE.
     *
     * @param array $elements
Carsten  Rose's avatar
Carsten Rose committed
197
     *
198
199
200
201
202
203
204
     * @return array
     */
    public static function duplicateRetypeElements(array $elements) {
        $arr = array();

        foreach ($elements as $fe) {

205
            // adjust FE_RETYPE=1
206
207
208
209
210
211
212
213
            if (isset($fe[FE_RETYPE]) && ($fe[FE_RETYPE] == '' || $fe[FE_RETYPE] == '1')) {
                $fe[FE_RETYPE] = '1';
            }

            $arr[] = $fe;

            if (isset($fe[FE_RETYPE]) && $fe[FE_RETYPE] == '1') {

214
215
                // Reference to Source FormElement
                $fe[FE_RETYPE_SOURCE_NAME] = $fe[FE_NAME];
216
217
218
219
220
221
222
223
224
225
226
227
228
229

                // Create copy of FE, adjust name, label, note
                $fe[FE_NAME] .= RETYPE_FE_NAME_EXTENSION;

                if (isset($fe[FE_RETYPE_LABEL])) {
                    $fe[FE_LABEL] = $fe[FE_RETYPE_LABEL];
                    unset($fe[FE_RETYPE_LABEL]);
                }

                if (isset($fe[FE_RETYPE_NOTE])) {
                    $fe[FE_NOTE] = $fe[FE_RETYPE_NOTE];
                    unset($fe[FE_RETYPE_NOTE]);
                }

230
231
                $fe[FE_TG_INDEX] = 1; // Not sure if this is helpfull in case of dynamic update - but it will make the element uniqe.

232
233
234
235
236
237
238
239
                unset($fe[FE_RETYPE]);
                $arr[] = $fe;
            }
        }

        return $arr;
    }

240
241
242
243
244
    /**
     * Copy specific attributes defined on the form to all FormElements.
     *
     * @param array $formSpec
     * @param array $feSpecNative
Carsten  Rose's avatar
Carsten Rose committed
245
     *
246
247
248
     * @return mixed
     */
    public static function copyAttributesToFormElements(array $formSpec, array $feSpecNative) {
249
250

        // Iterate over all FormElement
251
252
253
254
255
        foreach ($feSpecNative as $key => $element) {
            Support::setIfNotSet($feSpecNative[$key], F_FE_DATA_PATTERN_ERROR, $formSpec[F_FE_DATA_PATTERN_ERROR]);
            Support::setIfNotSet($feSpecNative[$key], F_FE_DATA_REQUIRED_ERROR, $formSpec[F_FE_DATA_REQUIRED_ERROR]);
            Support::setIfNotSet($feSpecNative[$key], F_FE_DATA_MATCH_ERROR, $formSpec[F_FE_DATA_MATCH_ERROR]);
            Support::setIfNotSet($feSpecNative[$key], F_FE_DATA_ERROR, $formSpec[F_FE_DATA_ERROR]);
256
257
258
            if ($feSpecNative[$key][F_FE_LABEL_ALIGN] == F_FE_LABEL_ALIGN_DEFAULT) {
                $feSpecNative[$key][F_FE_LABEL_ALIGN] = $formSpec[F_FE_LABEL_ALIGN];
            }
259
260
261
262
263
        }

        return $feSpecNative;
    }

264
265
266
267
268

    /**
     * Set all necessary keys - subsequent 'isset()' are not necessary anymore.
     *
     * @param array $fe
Carsten  Rose's avatar
Carsten Rose committed
269
     *
270
271
272
273
274
275
276
     * @return array
     */
    public static function initActionFormElement(array $fe) {

        $list = [FE_TYPE, FE_SLAVE_ID, FE_SQL_VALIDATE, FE_SQL_BEFORE, FE_SQL_INSERT, FE_SQL_UPDATE, FE_SQL_DELETE,
            FE_SQL_AFTER, FE_EXPECT_RECORDS, FE_REQUIRED_LIST, FE_MESSAGE_FAIL, FE_SENDMAIL_TO, FE_SENDMAIL_CC,
            FE_SENDMAIL_BCC, FE_SENDMAIL_FROM, FE_SENDMAIL_SUBJECT, FE_SENDMAIL_REPLY_TO, FE_SENDMAIL_FLAG_AUTO_SUBMIT,
277
278
            FE_SENDMAIL_GR_ID, FE_SENDMAIL_X_ID, FE_SENDMAIL_X_ID2, FE_SENDMAIL_X_ID3, FE_SENDMAIL_BODY_MODE,
            FE_SENDMAIL_BODY_HTML_ENTITY, FE_SENDMAIL_SUBJECT_HTML_ENTITY];
279
280
281
282
283
284
285
286
287
288
289
290

        foreach ($list as $key) {
            Support::setIfNotSet($fe, $key);
        }

        return $fe;
    }

    /**
     * Set all necessary keys - subsequent 'isset()' are not necessary anymore.
     *
     * @param array $fe
Carsten  Rose's avatar
Carsten Rose committed
291
     *
292
293
294
295
296
297
298
299
300
301
302
303
304
     * @return array
     */
    public static function initUploadFormElement(array $fe) {

        $list = [FE_SQL_BEFORE, FE_SQL_INSERT, FE_SQL_UPDATE, FE_SQL_DELETE, FE_SQL_AFTER];

        foreach ($list as $key) {
            Support::setIfNotSet($fe, $key);
        }

        return $fe;
    }

305
306
307
308
309
310
311
312
313
314
315
316
317
318
    /**
     * Prepare code of 'lock', 'password', 'info' to extend a FormElement.
     * The 'info' will always be added, 'lock' and 'password' only on FE with mode=show|required
     * Depending on $showInside:
     *    * true: a button is shown inside the 'input' or 'select' element.
     *    * false: an icon is shown below the FormElement.
     *
     * 'Add' means:
     *    * $rcButton contains all HTML button code. The calling function is responsible to build the correct code.
     *    * $formElement[FE_INPUT_EXTRA_BUTTON_INFO] has been wrapped with HTML-tag and HTML-id.
     *    * $formElement[FE_MODE] - for 'lock' it will be faked to 'readonly'
     *    * $formElement[FE_TYPE] - for 'password' it will be faked to 'password'
     *
     * @param array $formElement
Carsten  Rose's avatar
Carsten Rose committed
319
     * @param bool $showInline
Carsten  Rose's avatar
Carsten Rose committed
320
     *
321
     * @return array
322
323
     * @throws CodeException
     * @throws UserFormException
324
     * @throws UserReportException
325
     */
326
    public static function prepareExtraButton(array $formElement, $showInline) {
327

328
        $store = Store::getInstance();
329

330
331
        $infoSymbolInside = $store->getVar(SYSTEM_EXTRA_BUTTON_INFO_INLINE, STORE_SYSTEM);
        $infoSymbolOutside = $store->getVar(SYSTEM_EXTRA_BUTTON_INFO_BELOW, STORE_SYSTEM);
332

333
334
335
336
        if (SYSTEM_EXTRA_BUTTON_INFO_POSITION_BELOW == $store->getVar(SYSTEM_EXTRA_BUTTON_INFO_POSITION, STORE_SYSTEM)) {
            $showInline = false;
        }

337
        $extraButton = '';
338
        $id = $formElement[FE_HTML_ID];
339
340
341
342
343

        if (false !== strpos($formElement[FE_NAME], FE_TEMPLATE_GROUP_NAME_PATTERN)) {
            $id .= '-' . FE_TEMPLATE_GROUP_NAME_PATTERN;
        }

344
        $formElement[FE_TMP_EXTRA_BUTTON_HTML] = '';
345
346
347

        // INFO: $showinline =- TRUE ('input' elemente)
        if (isset($formElement[FE_INPUT_EXTRA_BUTTON_INFO]) && $showInline) {
348
            $extraButton .= <<<EOF
349
350
351
            <button class="btn btn-info" onclick="$('#$id-extra-info').slideToggle('swing')">
                $infoSymbolInside
            </button>
352
353
354
355
356
357
358
359
360
361
EOF;

            $value = $formElement[FE_INPUT_EXTRA_BUTTON_INFO];
            $formElement[FE_INPUT_EXTRA_BUTTON_INFO] = <<<EOF
            <div class="alert alert-info" id="$id-extra-info" style="display: none;">
                <p>$value</p>
            </div>
EOF;
        }

362
363
364
365
366
//        <span class="glyphicon glyphicon-info-sign text-info" aria-hidden="true" onclick="$('#$id-extra-info').slideToggle('swing')"></span>

        $js = " onclick=\"$('#$id-extra-info').slideToggle('swing')\" ";
        $arr = explode(' ', $infoSymbolOutside, 2);
        $infoSymbolOutside = $arr[0] . $js . $arr[1];
367

368
        // INFO: $showinline == FALSE (e.g. 'textarea' elemente)
369
        if (isset($formElement[FE_INPUT_EXTRA_BUTTON_INFO]) && !$showInline) {
370
            $class = $formElement[FE_INPUT_EXTRA_BUTTON_INFO_CLASS];
371
            $extraButton .= <<<EOF
372
            <span class="$class">$infoSymbolOutside</span>
373
374
375
376
377
378
379
380
381
382
EOF;

            $value = $formElement[FE_INPUT_EXTRA_BUTTON_INFO];
            $formElement[FE_INPUT_EXTRA_BUTTON_INFO] = <<<EOF
            <div class="alert alert-info" id="$id-extra-info" style="display: none;">
                <p>$value</p>
            </div>
EOF;
        }

383
        $skip = (!($formElement[FE_MODE] == FE_MODE_SHOW || $formElement[FE_MODE] == FE_MODE_REQUIRED));
384
385

        // LOCK
386
        if (!$skip && isset($formElement[FE_INPUT_EXTRA_BUTTON_LOCK])) {
387
388
389

            $formElement[FE_MODE] = FE_MODE_READONLY;

390
            $extraButton .= <<<EOF
391
392
393
394
            <button class="btn btn-info"
                    onclick="$('#$id').prop('readonly',!$('#$id').prop('readonly'))">
                <span class="glyphicon glyphicon-lock" aria-hidden="true"></span>
            </button>
395
396
397
398
EOF;
        }

        // PASSWORD
399
        if (!$skip && isset($formElement[FE_INPUT_EXTRA_BUTTON_PASSWORD])) {
400
401
402

            $formElement[FE_TYPE] = 'password';

403
            $extraButton .= <<<EOF
404
405
406
407
            <button class="btn btn-info"
                    onclick="$('#$id').attr('type',$('#$id').attr('type')==='password' ? 'text': 'password')">
                <span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span>
            </button>
408
409
410
EOF;
        }

411
        $formElement[FE_TMP_EXTRA_BUTTON_HTML] = Support::wrapTag('<div class="input-group-btn" style="font-size: 1em;">', $extraButton, true);
412
413
        Support::setIfNotSet($formElement, FE_INPUT_EXTRA_BUTTON_INFO);

414
415
416
        return $formElement;
    }

417
    /**
418
     * Returns $maxLength if greater than 0, else FE_TEMPLATE_GROUP_DEFAULT_MAX_LENGTH
419
420
     *
     * @param $maxLength
Carsten  Rose's avatar
Carsten Rose committed
421
     *
422
423
424
425
426
     * @return int
     */
    public static function tgGetMaxLength($maxLength) {
        return (empty($maxLength)) ? FE_TEMPLATE_GROUP_DEFAULT_MAX_LENGTH : $maxLength;
    }
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451

    /**
     * Converts a string of '00ff00' and returns a string of '{"red": 0, "green": 255, "blue": 0}'.
     *
     * @param array $formElement
     * @return string
     * @throws UserFormException
     */
    public static function penColorToHex(array $formElement) {

        if (empty($formElement[FE_DEFAULT_PEN_COLOR])) {
            return '';
        }

        if (strlen($formElement[FE_DEFAULT_PEN_COLOR]) != LENGTH_HEX_COLOR) {
            throw new UserFormException("Invalid Format for " . FE_DEFAULT_PEN_COLOR .
                ". Expect like '#ffdd00', got: '" . $formElement[FE_DEFAULT_PEN_COLOR] . "'", ERROR_INVALID_OR_MISSING_PARAMETER);
        }

        $rgb['red'] = hexdec($formElement[FE_DEFAULT_PEN_COLOR][0] . $formElement[FE_DEFAULT_PEN_COLOR][1]);
        $rgb['green'] = hexdec($formElement[FE_DEFAULT_PEN_COLOR][2] . $formElement[FE_DEFAULT_PEN_COLOR][3]);
        $rgb['blue'] = hexdec($formElement[FE_DEFAULT_PEN_COLOR][4] . $formElement[FE_DEFAULT_PEN_COLOR][5]);

        return json_encode($rgb);
    }
Carsten  Rose's avatar
Carsten Rose committed
452
}