Passed
Push — main ( 2edd53...9e1454 )
by Stefan
02:35
created

FormGenerator::fromXML()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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