Passed
Push — main ( 6d4942...fd6f94 )
by Stefan
11:16
created

FormGenerator::setReadOnly()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 7
rs 10
1
<?php
2
declare(strict_types=1);
3
4
namespace SKien\Formgenerator;
5
6
use SKien\Config\ConfigInterface;
7
use SKien\Config\NullConfig;
8
9
/**
10
 * An instance of this class is the starting point of each form.
11
 * Before doing the formdefinition, some minimum prerequisites have to be fulfilled:
12
 * - specify the configuration with FormGenerator::setConfig()
13
 * - specify the formaction with FormGenerator::setAction()
14
 *
15
 * @package Formgenerator
16
 * @author Stefanius <[email protected]>
17
 * @copyright MIT License - see the LICENSE file for details
18
 */
19
class FormGenerator extends FormCollection
20
{
21
    /** @var int last tab position in the form   */
22
    protected int $iLastTabindex = 0;
23
    /** @var bool set the whole form to readonly  */
24
    protected bool $bReadOnly = false;
25
    /** @var bool set debug mode to output more information  */
26
    protected bool $bDebugMode = false;
27
    /** @var bool set dialog mode (form runs in dynamic created iframe)  */
28
    protected bool $bIsDialog = false;
29
    /** @var int explicit width of the form in pixel  */
30
    protected int $iWidth = -1;
31
    /** @var FormFlags global flags for all form elements  */
32
    protected FormFlags $oGlobalFlags;
33
    /** @var string JS function for onsubmit  */
34
    protected string $strOnSubmit = '';
35
    /** @var string JS function for oncancel  */
36
    protected string $strOnCancel = '';
37
    /** @var array<mixed> config values to pass as object to JS */
38
    protected array $aConfigForJS = [];
39
    /** @var string path to the images  */
40
    protected string $strImgPath = '';
41
    /** @var string URL params for the form action  */
42
    protected string $strAction;
43
    /** @var string form target  */
44
    protected string $strFormTarget = '';
45
    /** @var FormDataInterface data provider     */
46
    protected FormDataInterface $oData;
47
    /** @var ConfigInterface configuration     */
48
    protected ConfigInterface $oConfig;
49
50
    /**
51
     * Create a FormGenerator.
52
     * Set some values to default.
53
     * @param FormDataInterface $oData
54
     * @param string $strID
55
     */
56
    public function __construct(?FormDataInterface $oData, string $strID = 'FormGenerator')
57
    {
58
        $this->oFG = $this;
59
        $this->oData = $oData ?? new NullFormData();
60
        $this->oConfig = new NullConfig();
61
        $this->oGlobalFlags = new FormFlags();
62
        $this->strID = $strID;
63
        $this->strOnSubmit = "validateForm();";
64
        $this->strOnCancel = "javascript:history.back();";
65
        $this->strAction = $_SERVER['PHP_SELF'];
66
        if (isset($_SERVER['QUERY_STRING'])) {
67
            $this->strAction .= '?' . $_SERVER['QUERY_STRING'];
68
        }
69
        $this->bDebugMode = (error_reporting() & (E_USER_ERROR | E_USER_WARNING)) != 0;
70
    }
71
72
    /**
73
     * <big><b>!!!  The FormGenerator itself can't be created direct through the fromXML() - method !!!</b></big>
74
     * However, this method must be implemented because it is declared as abstract in the higher-level class
75
     * @see \SKien\Formgenerator\FormElement::fromXML()
76
     * @ignore
77
     * @codeCoverageIgnore
78
     */
79
    static public function fromXML(\DOMElement $oXMLElement, FormCollection $oFormParent) : ?FormElement
80
    {
81
        return null;
82
    }
83
84
    /**
85
     * Get the form data.
86
     * @return \SKien\Formgenerator\FormDataInterface
87
     */
88
    public function getData() : FormDataInterface
89
    {
90
        return $this->oData;
91
    }
92
93
    /**
94
     * Get the configuration.
95
     * @return \SKien\Config\ConfigInterface
96
     */
97
    public function getConfig() : ConfigInterface
98
    {
99
        return $this->oConfig;
100
    }
101
102
    /**
103
     * Set the form data.
104
     * @param \SKien\Formgenerator\FormDataInterface $oData
105
     */
106
    public function setData(FormDataInterface $oData) : void
107
    {
108
        $this->oData = $oData;
109
    }
110
111
    /**
112
     * Set the configuration.
113
     * @param \SKien\Config\ConfigInterface $oConfig
114
     */
115
    public function setConfig(ConfigInterface $oConfig) : void
116
    {
117
        $this->oConfig = $oConfig;
118
    }
119
120
    /**
121
     * Set the action executed when submit the form.
122
     * If not changed here, <i><b>$_SERVER['QUERY_STRING']</b></i> is used.
123
     * @param string $strAction (default = '')
124
     */
125
    public function setAction(string $strAction) : void
126
    {
127
        $this->strAction = $strAction;
128
    }
129
130
    /**
131
     * Set the path to images.
132
     * @param string $strPath
133
     */
134
    public function setImagePath(string $strPath) : void
135
    {
136
        $this->strImgPath = $strPath;
137
    }
138
139
    /**
140
     * Get the path to the StdImages.
141
     * If no directory set, the subdirectory 'StdImages' of this sourcefile is used.
142
     * @return string current image path (withoutT trailing DIRECTORY_SEPARATOR!).
143
     * @internal
144
     */
145
    public function getImagePath() : string
146
    {
147
        if ($this->strImgPath == '') {
148
            $this->strImgPath = str_replace(rtrim($_SERVER['DOCUMENT_ROOT'], DIRECTORY_SEPARATOR), '', __DIR__);
149
            $this->strImgPath .= DIRECTORY_SEPARATOR . 'StdImages';
150
            $this->strImgPath = $this->getConfig()->getString('Images.Path', $this->strImgPath);
151
        }
152
        return rtrim($this->strImgPath, DIRECTORY_SEPARATOR);
153
    }
154
155
    /**
156
     * Get filename for predefined standard images
157
     * @param int $iImage
158
     * @return array<string>
159
     * @internal
160
     */
161
    public function getStdImage(int $iImage) : array
162
    {
163
        $aImageMap = [
164
            FormImage::IMG_DELETE      => ['Delete', 'delete.png', 'Delete content'],
165
            FormImage::IMG_SEARCH      => ['Search', 'search.png', 'Select'],
166
            FormImage::IMG_BROWSE      => ['Browse', 'browse.png', 'Browse on server'],
167
            FormImage::IMG_DATE_PICKER => ['DatePicker', 'datepicker.png', 'Select date'],
168
            FormImage::IMG_TIME_PICKER => ['TimePicker', 'timepicker.png', 'Select time'],
169
            FormImage::IMG_DTU         => ['InsertDTU', 'insert_dtu.png', 'insert current date, time and user'],
170
        ];
171
172
        $strImage = '';
173
        $strTitle = '';
174
        if (isset($aImageMap[$iImage])) {
175
            $aImage = $aImageMap[$iImage];
176
            $strImage = $this->getImagePath() . DIRECTORY_SEPARATOR;
177
            $strImage .= $this->getConfig()->getString('Images.StdImages.' . $aImage[0] . '.Image', $aImage[1]);
178
            $strTitle = $this->getConfig()->getString('Images.StdImages.' . $aImage[0] . '.Text', $aImage[2]);
179
        }
180
181
        return [$strImage, $strTitle];
182
    }
183
184
    /**
185
     * Get the global flags.
186
     * @return int
187
     * @internal
188
     */
189
    public function getGlobalFlags() : int
190
    {
191
        return $this->oGlobalFlags->getFlags();
192
    }
193
194
    /**
195
     * Set the target
196
     * @param string $strFormTarget
197
     */
198
    public function setTarget(string $strFormTarget) : void
199
    {
200
        $this->strFormTarget = $strFormTarget;
201
    }
202
203
    /**
204
     * @param string $strOnSubmit
205
     */
206
    public function setOnSubmit(string $strOnSubmit) : void
207
    {
208
        $this->strOnSubmit = $strOnSubmit;
209
    }
210
211
    /**
212
     * Set explicit width of the form.
213
     * @param int $iWidth    width (-1 for default)
214
     */
215
    public function setFormWidth(int $iWidth) : void
216
    {
217
        $this->iWidth = $iWidth;
218
    }
219
220
    /**
221
     * Sets the whole form to readonly.
222
     * All elements of the form set to disabled, Save/Cancel-Buttons are replaced
223
     * with Close-Button
224
     * @param bool $bReadOnly
225
     */
226
    public function setReadOnly(bool $bReadOnly) : void
227
    {
228
        $this->bReadOnly = $bReadOnly;
229
        if ($bReadOnly) {
230
            $this->oGlobalFlags->add(FormFlags::READ_ONLY);
231
        } else {
232
            $this->oGlobalFlags->remove(FormFlags::READ_ONLY);
233
        }
234
    }
235
236
    /**
237
     * Adjust the height of the two specified columns.
238
     * If we have two columns containing fieldset, the height pf both (... and the border)
239
     * usually differs dependent on the contents. To prettify the output, the height of the
240
     * smaller columns is set to the height of the bigger one.
241
     * @param string $strCol1
242
     * @param string $strCol2
243
     */
244
    public function adjustColHeight(string $strCol1, string $strCol2) : void
245
    {
246
        $strScript = "window.addEventListener('load', function () {";
247
        $strScript .= "adjustColumnHeight('" . $strCol1 . "', '" . $strCol2 . "');});";
248
        $this->add(new FormScript($strScript));
249
    }
250
251
    /**
252
     * Sets the debug mode to output more information.
253
     * Especialy for some elements, that need additional JS it can be helpfull to
254
     * turn on the debug mode.
255
     * @param bool $bDebugMode
256
     */
257
    public function setDebugMode(bool $bDebugMode) : void
258
    {
259
        // Even if we plan to integrate a logger, we keep the debug mode alive because the
260
        // logger do not cover the JS side (missing scripts, ...) and developers often
261
        // forget to take a look at the Browser console.
262
        $this->bDebugMode = $bDebugMode;
263
    }
264
265
    /**
266
     * Get state of the debug mode.
267
     * @return bool
268
     */
269
    public function getDebugMode() : bool
270
    {
271
        return $this->bDebugMode;
272
    }
273
274
    /**
275
     * Specify the form as an 'Dialog'.
276
     * Dialog means, the form runs inside of an dynamic iframe created in the
277
     * dialog - DIV of the parent. <br/>
278
     * The cancel can easy be done by clear the content of that dialog-DIV.
279
     * @param bool $bDialog
280
     * @internal
281
     */
282
    public function setDialog(bool $bDialog) : void
283
    {
284
        $this->bIsDialog = $bDialog;
285
    }
286
287
    /**
288
     * Check, if form runs in dialog (dynamic created iframe).
289
     * @return bool
290
     * @internal
291
     */
292
    public function isDialog() : bool
293
    {
294
        return $this->bIsDialog;
295
    }
296
297
    /**
298
     * Add any element to the form.
299
     * @param FormElementInterface $oElement
300
     * @internal
301
     */
302
    public function addElement(FormElementInterface $oElement) : void
303
    {
304
        $this->iLastTabindex += $oElement->setTabindex($this->iLastTabindex + 1);
305
    }
306
307
    /**
308
     * Add a key to the config passed to JS.
309
     * @param string $strKey
310
     * @param mixed $value
311
     * @internal
312
     */
313
    public function addConfigForJS(string $strKey, $value) : void
314
    {
315
        $this->aConfigForJS[$strKey] = $value;
316
    }
317
318
    /**
319
     * Create HTML for defined form.
320
     * @return string
321
     */
322
    public function getForm() : string
323
    {
324
        $strHTML = PHP_EOL;
325
326
        $strHTML .= '<form';
327
        if (!empty($this->strAction)) {
328
            $strHTML .= ' action="';
329
            $strHTML .= $this->strAction . '"';
330
        }
331
        if (!empty($this->strFormTarget)) {
332
            $strHTML .= ' target="' . $this->strFormTarget . '"';
333
        }
334
        if ($this->aAttrib != null) {
335
            foreach ($this->aAttrib as $strName => $strValue) {
336
                $strHTML .= ' ' . $strName . '="' . $strValue . '"';
337
            }
338
        }
339
        $strHTML .= $this->buildStyle();
340
        $strHTML .= ' method="post" id=' . $this->strID . ' onsubmit="return ' . $this->strOnSubmit . '">' . PHP_EOL;
341
        $strHTML .= '<div id=errorPopup onclick="this.style.display = \'none\';"></div>' . PHP_EOL;
342
        $iCnt = count($this->aChild);
343
        for ($i = 0; $i < $iCnt; $i++) {
344
            $strHTML .= $this->aChild[$i]->GetHTML();
345
        }
346
347
        $strHTML .= '</form>' . PHP_EOL;
348
        $strHTML .= PHP_EOL;
349
350
        return $strHTML;
351
    }
352
353
    /**
354
     * Build needed configuration for JS scripts.
355
     * - for validation
356
     * - scripts of all childs that have own script
357
     * @return string
358
     */
359
    public function getScript() : string
360
    {
361
        // set some general configurations
362
        $this->aConfigForJS['DebugMode'] = $this->getDebugMode();
363
        $this->aConfigForJS['FormDataValidation'] = $this->oConfig->getArray('FormDataValidation');
364
        $this->aConfigForJS['FormDataValidation']['formID'] = $this->strID;
365
        $this->aConfigForJS['JavaScript'] = $this->oConfig->getArray('JavaScript');
366
367
        $strScript = 'var g_oConfigFromPHP = ' . json_encode($this->aConfigForJS) . ';';
368
        return $strScript;
369
    }
370
371
    /**
372
     * Build needed CSS styles.
373
     * - body, if form width defined
374
     * - styles of all childs that have own styles
375
     * @return string
376
     */
377
    public function getStyle() : string
378
    {
379
        $strStyle = '';
380
        if ($this->iWidth > 0) {
381
            $strStyle = "body { width: " . $this->iWidth . "px;}" . PHP_EOL;
382
        }
383
        $iCnt = count($this->aChild);
384
        for ($i = 0; $i < $iCnt; $i++) {
385
            $strStyle .= $this->aChild[$i]->getStyle();
386
        }
387
        return $strStyle;
388
    }
389
}
390