1 | <?php |
||
2 | |||
3 | namespace Common\Core; |
||
4 | |||
5 | use Backend\Core\Engine\Header as BackendHeader; |
||
6 | use Exception; |
||
7 | use Frontend\Core\Header\Header as FrontendHeader; |
||
8 | use Backend\Core\Engine\Url as BackendUrl; |
||
9 | use Frontend\Core\Engine\Url as FrontendUrl; |
||
10 | use SpoonFilter; |
||
11 | use SpoonFormButton; |
||
12 | use SpoonFormDropdown; |
||
13 | use SpoonFormPassword; |
||
14 | use SpoonFormRadiobutton; |
||
15 | use SpoonFormText; |
||
16 | use SpoonFormTextarea; |
||
17 | use SpoonFormTime; |
||
18 | |||
19 | /** |
||
20 | * This class will initiate the frontend-application |
||
21 | */ |
||
22 | class Form extends \SpoonForm |
||
23 | { |
||
24 | /** |
||
25 | * The header instance |
||
26 | * |
||
27 | * @var BackendHeader|FrontendHeader |
||
28 | */ |
||
29 | protected $header; |
||
30 | |||
31 | /** |
||
32 | * The URL instance |
||
33 | * |
||
34 | * @var BackendUrl|FrontendUrl |
||
35 | */ |
||
36 | protected $url; |
||
37 | |||
38 | /** |
||
39 | * @param string $name Name of the form |
||
40 | * @param string|null $action The action (URL) whereto the form will be submitted, if not provided it |
||
41 | * will be auto generated. |
||
42 | * @param string|null $method The method to use when submitting the form, default is POST. |
||
43 | * @param string $hash The id of the anchor to append to the action-URL. |
||
44 | * @param bool $useToken Should we automatically add a formtoken? |
||
45 | */ |
||
46 | 90 | public function __construct( |
|
47 | string $name, |
||
48 | string $action = null, |
||
49 | ?string $method = 'post', |
||
50 | string $hash = null, |
||
51 | bool $useToken = true |
||
52 | ) { |
||
53 | 90 | $this->url = Model::getContainer()->get('url'); |
|
54 | 90 | if (Model::getContainer()->has('header')) { |
|
55 | 90 | $this->header = Model::getContainer()->get('header'); |
|
56 | } |
||
57 | |||
58 | 90 | $action = ($action === null) ? rtrim(Model::getRequest()->getRequestUri(), '/') : (string) $action; |
|
59 | |||
60 | 90 | if ($hash !== null && mb_strlen($hash) > 0) { |
|
61 | // check if the # is present |
||
62 | if ($hash[0] !== '#') { |
||
63 | $hash = '#' . $hash; |
||
64 | } |
||
65 | |||
66 | $action .= $hash; |
||
67 | } |
||
68 | |||
69 | 90 | parent::__construct($name, $action, $method ?? 'post', $useToken); |
|
70 | |||
71 | 90 | $this->setParameter('id', $name); |
|
72 | 90 | $this->setParameter('class', 'fork-form submitWithLink'); |
|
73 | 90 | } |
|
74 | |||
75 | /** |
||
76 | * Adds a button to the form |
||
77 | * |
||
78 | * @param string $name Name of the button. |
||
79 | * @param string $value The value (or label) that will be printed. |
||
80 | * @param string $type The type of the button (submit is default). |
||
81 | * @param string $class Class(es) that will be applied on the button. |
||
82 | * |
||
83 | * @throws Exception |
||
84 | * |
||
85 | * @return SpoonFormButton |
||
86 | */ |
||
87 | public function addButton($name, $value, $type = 'submit', $class = null): SpoonFormButton |
||
88 | { |
||
89 | $name = (string) $name; |
||
90 | $value = (string) $value; |
||
91 | $type = (string) $type; |
||
92 | $class = (string) ($class ?? 'btn btn-primary'); |
||
93 | |||
94 | // do a check |
||
95 | if ($type === 'submit' && $name === 'submit') { |
||
96 | throw new Exception( |
||
97 | 'You can\'t add buttons with the name submit. JS freaks out when we |
||
98 | replace the buttons with a link and use that link to submit the form.' |
||
99 | ); |
||
100 | } |
||
101 | |||
102 | // create and return a button |
||
103 | return parent::addButton($name, $value, $type, $class); |
||
104 | } |
||
105 | |||
106 | /** |
||
107 | * Adds a date field to the form |
||
108 | * |
||
109 | * @param string $name Name of the element. |
||
110 | * @param mixed $value The value for the element. |
||
111 | * @param string $type The type (from, till, range) of the datepicker. |
||
112 | * @param int $date The date to use. |
||
113 | * @param int $date2 The second date for a rangepicker. |
||
114 | * @param string $class Class(es) that have to be applied on the element. |
||
115 | * @param string $classError Class(es) that have to be applied when an error occurs on the element. |
||
116 | * |
||
117 | * @throws Exception |
||
118 | * |
||
119 | * @return FormDate |
||
120 | */ |
||
121 | 7 | public function addDate( |
|
122 | $name, |
||
123 | $value = null, |
||
124 | $type = null, |
||
125 | $date = null, |
||
126 | $date2 = null, |
||
127 | $class = null, |
||
128 | $classError = null |
||
129 | ): FormDate { |
||
130 | 7 | $name = (string) $name; |
|
131 | 7 | $value = ($value === null || $value === '') ? null : (int) $value; |
|
132 | 7 | $type = SpoonFilter::getValue($type, ['from', 'till', 'range'], 'none'); |
|
133 | 7 | $date = ($date !== null) ? (int) $date : null; |
|
134 | 7 | $date2 = ($date2 !== null) ? (int) $date2 : null; |
|
135 | 7 | $class = (string) ($class ?? 'form-control fork-form-date inputDate'); |
|
136 | 7 | $classError = (string) ($classError ?? 'error form-control-danger is-invalid'); |
|
137 | |||
138 | // validate |
||
139 | 7 | if ($type === 'from' && ($date === 0 || $date === null)) { |
|
140 | throw new Exception('A date field with type "from" should have a valid date-parameter.'); |
||
141 | } |
||
142 | 7 | if ($type === 'till' && ($date === 0 || $date === null)) { |
|
143 | throw new Exception('A date field with type "till" should have a valid date-parameter.'); |
||
144 | } |
||
145 | 7 | if ($type === 'range' && ($date === 0 || $date2 === 0 || $date === null || $date2 === null)) { |
|
146 | throw new Exception('A date field with type "range" should have 2 valid date-parameters.'); |
||
147 | } |
||
148 | |||
149 | // set mask and firstday |
||
150 | 7 | $mask = 'd/m/Y'; |
|
151 | 7 | $firstDay = 1; |
|
152 | |||
153 | // build attributes |
||
154 | 7 | $attributes = []; |
|
155 | 7 | $attributes['data-mask'] = str_replace( |
|
156 | 7 | ['d', 'm', 'Y', 'j', 'n'], |
|
157 | 7 | ['dd', 'mm', 'yy', 'd', 'm'], |
|
158 | 7 | $mask |
|
159 | ); |
||
160 | 7 | $attributes['data-firstday'] = $firstDay; |
|
161 | 7 | $attributes['data-year'] = date('Y', $value); |
|
162 | // -1 because javascript starts at 0 |
||
163 | 7 | $attributes['data-month'] = date('n', $value) - 1; |
|
164 | 7 | $attributes['data-day'] = date('j', $value); |
|
165 | |||
166 | // add extra classes based on type |
||
167 | switch ($type) { |
||
168 | 7 | case 'from': |
|
169 | $class .= ' fork-form-date-from inputDatefieldFrom form-control'; |
||
170 | $classError .= ' inputDatefieldFrom'; |
||
171 | $attributes['data-startdate'] = date('Y-m-d', $date); |
||
172 | break; |
||
173 | |||
174 | 7 | case 'till': |
|
175 | $class .= ' fork-form-date-till inputDatefieldTill form-control'; |
||
176 | $classError .= ' inputDatefieldTill'; |
||
177 | $attributes['data-enddate'] = date('Y-m-d', $date); |
||
178 | break; |
||
179 | |||
180 | 7 | case 'range': |
|
181 | 2 | $class .= ' fork-form-date-range inputDatefieldRange form-control'; |
|
182 | 2 | $classError .= ' inputDatefieldRange'; |
|
183 | 2 | $attributes['data-startdate'] = date('Y-m-d', $date); |
|
184 | 2 | $attributes['data-enddate'] = date('Y-m-d', $date2); |
|
185 | 2 | break; |
|
186 | |||
187 | default: |
||
188 | 5 | $class .= ' inputDatefieldNormal form-control'; |
|
189 | 5 | $classError .= ' inputDatefieldNormal'; |
|
190 | 5 | break; |
|
191 | } |
||
192 | |||
193 | 7 | $this->add(new FormDate($name, $value, $mask, $class, $classError)); |
|
194 | |||
195 | 7 | parent::getField($name)->setAttributes($attributes); |
|
196 | |||
197 | 7 | return parent::getField($name); |
|
198 | } |
||
199 | |||
200 | /** |
||
201 | * Adds a single checkbox. |
||
202 | * |
||
203 | * @param string $name The name of the element. |
||
204 | * @param bool $checked Should the checkbox be checked? |
||
205 | * @param string $class Class(es) that will be applied on the element. |
||
206 | * @param string $classError Class(es) that will be applied on the element when an error occurs. |
||
207 | * |
||
208 | * @return CommonFormCheckbox |
||
209 | */ |
||
210 | 8 | public function addCheckbox($name, $checked = false, $class = null, $classError = null) |
|
211 | { |
||
212 | 8 | $name = (string) $name; |
|
213 | 8 | $checked = (bool) $checked; |
|
214 | 8 | $class = (string) ($class ?? 'fork-form-checkbox'); |
|
215 | 8 | $classError = (string) ($classError ?? 'error form-control-danger is-invalid'); |
|
216 | |||
217 | // create and return a checkbox |
||
218 | 8 | $this->add(new CommonFormCheckbox($name, $checked, $class, $classError)); |
|
219 | |||
220 | // return element |
||
221 | 8 | return $this->getField($name); |
|
222 | } |
||
223 | |||
224 | /** |
||
225 | * Adds a single dropdown. |
||
226 | * |
||
227 | * @param string $name Name of the element. |
||
228 | * @param array $values Values for the dropdown. |
||
229 | * @param string $selected The selected elements. |
||
230 | * @param bool $multipleSelection Is it possible to select multiple items? |
||
231 | * @param string $class Class(es) that will be applied on the element. |
||
232 | * @param string $classError Class(es) that will be applied on the element when an error occurs. |
||
233 | * |
||
234 | * @return SpoonFormDropdown |
||
235 | */ |
||
236 | 11 | public function addDropdown( |
|
237 | $name, |
||
238 | array $values = null, |
||
239 | $selected = null, |
||
240 | $multipleSelection = false, |
||
241 | $class = null, |
||
242 | $classError = null |
||
243 | ): SpoonFormDropdown { |
||
244 | 11 | $name = (string) $name; |
|
245 | 11 | $multipleSelection = (bool) $multipleSelection; |
|
246 | 11 | $class = (string) ($class ?? 'form-control fork-form-select'); |
|
247 | 11 | $classError = (string) ($classError ?? 'error form-control-danger is-invalid'); |
|
248 | |||
249 | // special classes for multiple |
||
250 | 11 | if ($multipleSelection) { |
|
251 | $class .= ' fork-form-select-multiple'; |
||
252 | } |
||
253 | |||
254 | // create and return a dropdown |
||
255 | 11 | return parent::addDropdown($name, Model::recursiveHtmlspecialchars($values), $selected, $multipleSelection, $class, $classError); |
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
256 | } |
||
257 | |||
258 | /** |
||
259 | * Adds a multiple checkbox. |
||
260 | * |
||
261 | * @param string $name The name of the element. |
||
262 | * @param array $values The values for the checkboxes. |
||
263 | * @param mixed $checked Should the checkboxes be checked? |
||
264 | * @param string $class Class(es) that will be applied on the element. |
||
265 | * |
||
266 | * @return \SpoonFormMultiCheckbox |
||
267 | */ |
||
268 | public function addMultiCheckbox($name, array $values, $checked = null, $class = null) |
||
269 | { |
||
270 | $name = (string) $name; |
||
271 | $checked = ($checked !== null) ? (array) $checked : null; |
||
272 | $class = (string) ($class ?? 'fork-form-multi-checkbox'); |
||
273 | |||
274 | // create and return a multi checkbox |
||
275 | return parent::addMultiCheckbox($name, $values, $checked, $class); |
||
276 | } |
||
277 | |||
278 | /** |
||
279 | * Adds a single password field. |
||
280 | * |
||
281 | * @param string $name The name of the field. |
||
282 | * @param string $value The value for the field. |
||
283 | * @param int $maxLength The maximum length for the field. |
||
284 | * @param string $class Class(es) that will be applied on the element. |
||
285 | * @param string $classError Class(es) that will be applied on the element when an error occurs. |
||
286 | * @param bool $HTML Will the field contain HTML? |
||
287 | * |
||
288 | * @return SpoonFormPassword |
||
289 | */ |
||
290 | 67 | public function addPassword( |
|
291 | $name, |
||
292 | $value = null, |
||
293 | $maxLength = null, |
||
294 | $class = null, |
||
295 | $classError = null, |
||
296 | $HTML = false |
||
297 | ): SpoonFormPassword { |
||
298 | 67 | $name = (string) $name; |
|
299 | 67 | $value = ($value !== null) ? (string) $value : null; |
|
300 | 67 | $maxLength = ($maxLength !== null) ? (int) $maxLength : null; |
|
301 | 67 | $class = (string) ($class ?? 'form-control fork-form-password inputPassword'); |
|
302 | 67 | $classError = (string) ($classError ?? 'error form-control-danger is-invalid'); |
|
303 | 67 | $HTML = (bool) $HTML; |
|
304 | |||
305 | // create and return a password field |
||
306 | 67 | return parent::addPassword($name, $value, $maxLength, $class, $classError, $HTML); |
|
307 | } |
||
308 | |||
309 | /** |
||
310 | * Adds a single radio button. |
||
311 | * |
||
312 | * @param string $name The name of the element. |
||
313 | * @param array $values The possible values for the radio button. |
||
314 | * @param string $checked Should the element be checked? |
||
315 | * @param string $class Class(es) that will be applied on the element. |
||
316 | * |
||
317 | * @return SpoonFormRadiobutton |
||
318 | */ |
||
319 | 10 | public function addRadiobutton($name, array $values, $checked = null, $class = null): SpoonFormRadiobutton |
|
320 | { |
||
321 | 10 | $name = (string) $name; |
|
322 | 10 | $checked = ($checked !== null) ? (string) $checked : null; |
|
323 | 10 | $class = (string) ($class ?? 'fork-form-radio'); |
|
324 | |||
325 | // create and return a radio button |
||
326 | 10 | return parent::addRadiobutton($name, $values, $checked, $class); |
|
327 | } |
||
328 | |||
329 | /** |
||
330 | * Adds a single textfield. |
||
331 | * |
||
332 | * @param string $name The name of the element. |
||
333 | * @param string $value The value inside the element. |
||
334 | * @param int $maxLength The maximum length for the value. |
||
335 | * @param string $class Class(es) that will be applied on the element. |
||
336 | * @param string $classError Class(es) that will be applied on the element when an error occurs. |
||
337 | * @param bool $HTML Will this element contain HTML? |
||
338 | * |
||
339 | * @return SpoonFormText |
||
340 | */ |
||
341 | 88 | public function addText( |
|
342 | $name, |
||
343 | $value = null, |
||
344 | $maxLength = 255, |
||
345 | $class = null, |
||
346 | $classError = null, |
||
347 | $HTML = true |
||
348 | ): SpoonFormText { |
||
349 | 88 | $name = (string) $name; |
|
350 | 88 | $value = ($value !== null) ? (string) $value : null; |
|
351 | 88 | $maxLength = (int) ($maxLength ?? 255); |
|
352 | 88 | $class = (string) ($class ?? 'form-control fork-form-text'); |
|
353 | 88 | $classError = (string) ($classError ?? 'error form-control-danger is-invalid'); |
|
354 | 88 | $HTML = (bool) $HTML; |
|
355 | |||
356 | // create and return a textfield |
||
357 | 88 | return parent::addText($name, $value, $maxLength, $class, $classError, $HTML); |
|
358 | } |
||
359 | |||
360 | /** |
||
361 | * Adds a single textarea. |
||
362 | * |
||
363 | * @param string $name The name of the element. |
||
364 | * @param string $value The value inside the element. |
||
365 | * @param string $class Class(es) that will be applied on the element. |
||
366 | * @param string $classError Class(es) that will be applied on the element when an error occurs. |
||
367 | * @param bool $HTML Will the element contain HTML? |
||
368 | * |
||
369 | * @return SpoonFormTextarea |
||
370 | */ |
||
371 | 11 | public function addTextarea( |
|
372 | $name, |
||
373 | $value = null, |
||
374 | $class = null, |
||
375 | $classError = null, |
||
376 | $HTML = true |
||
377 | ): SpoonFormTextarea { |
||
378 | 11 | $name = (string) $name; |
|
379 | 11 | $value = ($value !== null) ? (string) $value : null; |
|
380 | 11 | $class = (string) ($class ?? 'form-control fork-form-textarea'); |
|
381 | 11 | $classError = (string) ($classError ?? 'error form-control-danger is-invalid'); |
|
382 | 11 | $HTML = (bool) $HTML; |
|
383 | |||
384 | // create and return a textarea |
||
385 | 11 | return parent::addTextarea($name, $value, $class, $classError, $HTML); |
|
386 | } |
||
387 | |||
388 | /** |
||
389 | * Adds a single time field. |
||
390 | * |
||
391 | * @param string $name The name of the element. |
||
392 | * @param string $value The value inside the element. |
||
393 | * @param string $class Class(es) that will be applied on the element. |
||
394 | * @param string $classError Class(es) that will be applied on the element when an error occurs. |
||
395 | * |
||
396 | * @return SpoonFormTime |
||
397 | */ |
||
398 | 5 | public function addTime($name, $value = null, $class = null, $classError = null): SpoonFormTime |
|
399 | { |
||
400 | 5 | $name = (string) $name; |
|
401 | 5 | $value = ($value !== null) ? (string) $value : null; |
|
402 | 5 | $class = (string) ($class ?? 'form-control fork-form-time inputTime'); |
|
403 | 5 | $classError = (string) ($classError ?? 'error form-control-danger is-invalid'); |
|
404 | |||
405 | // create and return a time field |
||
406 | 5 | return parent::addTime($name, $value, $class, $classError); |
|
407 | } |
||
408 | |||
409 | /** |
||
410 | * @return string|null |
||
411 | */ |
||
412 | 14 | public static function getUploadMaxFileSize(): ?string |
|
413 | { |
||
414 | 14 | $uploadMaxFileSize = ini_get('upload_max_filesize'); |
|
415 | 14 | if ($uploadMaxFileSize === false) { |
|
416 | return null; |
||
417 | } |
||
418 | |||
419 | // reformat if defined as an integer |
||
420 | 14 | if (is_numeric($uploadMaxFileSize)) { |
|
421 | return $uploadMaxFileSize / 1024 . 'MB'; |
||
422 | } |
||
423 | |||
424 | // reformat if specified in kB |
||
425 | 14 | if (mb_strtoupper(mb_substr($uploadMaxFileSize, -1, 1)) === 'K') { |
|
426 | return mb_substr($uploadMaxFileSize, 0, -1) . 'kB'; |
||
427 | } |
||
428 | |||
429 | // reformat if specified in MB |
||
430 | 14 | if (mb_strtoupper(mb_substr($uploadMaxFileSize, -1, 1)) === 'M') { |
|
431 | 14 | return $uploadMaxFileSize . 'B'; |
|
432 | } |
||
433 | |||
434 | // reformat if specified in GB |
||
435 | if (mb_strtoupper(mb_substr($uploadMaxFileSize, -1, 1)) === 'G') { |
||
436 | return $uploadMaxFileSize . 'B'; |
||
437 | } |
||
438 | |||
439 | return $uploadMaxFileSize; |
||
440 | } |
||
441 | |||
442 | 71 | protected function sessionHasFormToken(): bool |
|
443 | { |
||
444 | 71 | return Model::getSession()->has('form_token'); |
|
445 | } |
||
446 | |||
447 | 71 | protected function saveTokenToSession($token): void |
|
448 | { |
||
449 | 71 | Model::getSession()->set('form_token', $token); |
|
450 | 71 | } |
|
451 | |||
452 | 71 | protected function getSessionId(): string |
|
453 | { |
||
454 | 71 | return Model::getSession()->getId(); |
|
455 | } |
||
456 | |||
457 | 71 | protected function getTokenFromSession(): ?string |
|
458 | { |
||
459 | 71 | return Model::getSession()->get('form_token'); |
|
460 | } |
||
461 | } |
||
462 |