Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
29.41% |
25 / 85 |
|
29.27% |
12 / 41 |
CRAP | |
0.00% |
0 / 1 |
tao_helpers_form_FormElement | |
29.41% |
25 / 85 |
|
29.27% |
12 / 41 |
1458.98 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getName | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getRawValue | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setValue | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
addClass | |
80.00% |
4 / 5 |
|
0.00% |
0 / 1 |
2.03 | |||
removeClass | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
addAttribute | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setAttribute | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setAttributes | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
disable | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isDisabled | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
renderAttributes | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
getWidget | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
getDescription | |
75.00% |
3 / 4 |
|
0.00% |
0 / 1 |
2.06 | |||
setDescription | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setUnit | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getLevel | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setLevel | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
addValidator | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
addValidators | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
getValidators | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setForcedValid | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
validate | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
30 | |||
preValidate | |
16.67% |
1 / 6 |
|
0.00% |
0 / 1 |
19.47 | |||
isValid | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getError | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getInvalidValues | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setInvalidValues | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setHelp | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getHelp | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
removeValidator | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
12 | |||
feed | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getEvaluatedValue | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getValue | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
isBreakOnFirstError | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setBreakOnFirstError | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getAttributes | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getInputValue | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
feedInputValue | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
render | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
getDecodedValue | |
66.67% |
2 / 3 |
|
0.00% |
0 / 1 |
4.59 |
1 | <?php |
2 | |
3 | /* |
4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License |
6 | * as published by the Free Software Foundation; under version 2 |
7 | * of the License (non-upgradable). |
8 | * |
9 | * This program is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write to the Free Software |
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | * |
18 | * Copyright (c) 2008-2010 (original work) Deutsche Institut für Internationale Pädagogische Forschung |
19 | * (under the project TAO-TRANSFER); |
20 | * 2009-2012 (update and modification) Public Research Centre Henri Tudor |
21 | * (under the project TAO-SUSTAIN & TAO-DEV); |
22 | * 2021 (original work) Open Assessment Technologies SA |
23 | */ |
24 | |
25 | declare(strict_types=1); |
26 | |
27 | use oat\oatbox\validator\ValidatorInterface; |
28 | use oat\tao\helpers\form\elements\xhtml\SearchTextBox; |
29 | use oat\tao\helpers\form\elements\xhtml\SearchDropdown; |
30 | use oat\tao\helpers\form\validators\PreliminaryValidationInterface; |
31 | |
32 | // Defining aliases for old style class names for backward compatibility |
33 | // phpcs:disable PSR1.Files.SideEffects |
34 | class_alias(SearchTextBox::class, \tao_helpers_form_elements_xhtml_Searchtextbox::class); |
35 | class_alias(SearchDropdown::class, \tao_helpers_form_elements_xhtml_Searchdropdown::class); |
36 | // phpcs:enable PSR1.Files.SideEffects |
37 | |
38 | /** |
39 | * Represents a form. It provides the default behavior for form management and |
40 | * be overridden for any rendering mode. |
41 | * A form is composed by a set of FormElements. |
42 | * |
43 | * The form data flow is: |
44 | * 1. add the elements to the form instance |
45 | * 2. run evaluate (initElements, update states (submited, valid, etc), update) |
46 | * 3. render form |
47 | * |
48 | * @author Joel Bout, <joel@taotesting.com> |
49 | * @package tao |
50 | */ |
51 | abstract class tao_helpers_form_FormElement |
52 | { |
53 | public const WIDGET_ID = ''; |
54 | |
55 | /** |
56 | * the name of the element |
57 | * |
58 | * @access protected |
59 | * @var string |
60 | */ |
61 | protected $name = ''; |
62 | |
63 | /** |
64 | * the value of the element |
65 | * |
66 | * @access protected |
67 | * @var mixed |
68 | */ |
69 | protected $value; |
70 | |
71 | /** |
72 | * the list of element attributes (key/value pairs) |
73 | * |
74 | * @access protected |
75 | * @var array |
76 | */ |
77 | protected $attributes = []; |
78 | |
79 | /** |
80 | * the widget links to the element |
81 | * |
82 | * @access protected |
83 | * @deprecated |
84 | * @see tao_helpers_form_FormElement::WIDGET_ID |
85 | */ |
86 | protected $widget = ''; |
87 | |
88 | /** |
89 | * the element description |
90 | * |
91 | * @access protected |
92 | * @var string |
93 | */ |
94 | protected $description = ''; |
95 | |
96 | /** |
97 | * used to display an element regarding the others |
98 | * |
99 | * @access protected |
100 | * @var int |
101 | */ |
102 | protected $level = 1; |
103 | |
104 | /** |
105 | * The list of validators links to the elements |
106 | * |
107 | * @access protected |
108 | * @var array |
109 | */ |
110 | protected $validators = []; |
111 | |
112 | /** |
113 | * the error message to display when the element validation has failed |
114 | * |
115 | * @access protected |
116 | * @var array |
117 | */ |
118 | protected $error = []; |
119 | |
120 | /** |
121 | * to force the validation of the element |
122 | * |
123 | * @access protected |
124 | * @var bool |
125 | */ |
126 | protected $forcedValid = false; |
127 | |
128 | /** |
129 | * Stop or not after first validation error occurred |
130 | * @var bool |
131 | */ |
132 | protected $breakOnFirstError = true; |
133 | |
134 | /** |
135 | * add a unit to the element (only for rendering purposes) |
136 | * |
137 | * @access protected |
138 | * @var string |
139 | */ |
140 | protected $unit = ''; |
141 | |
142 | /** |
143 | * Short description of attribute help |
144 | * |
145 | * @access protected |
146 | * @var string |
147 | */ |
148 | protected $help = ''; |
149 | |
150 | /** @var mixed */ |
151 | private $inputValue; |
152 | |
153 | /** @var array */ |
154 | private $invalidValues = []; |
155 | |
156 | /** @var bool */ |
157 | private $isValid = true; |
158 | |
159 | /** |
160 | * Short description of method __construct |
161 | * |
162 | * @author Joel Bout, <joel@taotesting.com> |
163 | * @param string $name |
164 | * @return void |
165 | */ |
166 | public function __construct($name = '') |
167 | { |
168 | $this->name = $name; |
169 | } |
170 | |
171 | /** |
172 | * Short description of method getName |
173 | * |
174 | * @author Joel Bout, <joel@taotesting.com> |
175 | * @return string |
176 | */ |
177 | public function getName() |
178 | { |
179 | return (string)$this->name; |
180 | } |
181 | |
182 | /** |
183 | * Short description of method setName |
184 | * |
185 | * @author Joel Bout, <joel@taotesting.com> |
186 | * @param string $name |
187 | * @return void |
188 | */ |
189 | public function setName($name) |
190 | { |
191 | $this->name = $name; |
192 | } |
193 | |
194 | /** |
195 | * Returns the raw data of the request, that was stored by the feed function |
196 | * the element. Mainly used by the Validators |
197 | * |
198 | * @author joel bout, joel@taotesting.com |
199 | * @return mixed |
200 | */ |
201 | public function getRawValue() |
202 | { |
203 | return $this->value; |
204 | } |
205 | |
206 | /** |
207 | * Short description of method setValue |
208 | * |
209 | * @author Joel Bout, <joel@taotesting.com> |
210 | * @param string $value |
211 | * @return void |
212 | */ |
213 | public function setValue($value) |
214 | { |
215 | $this->value = $value; |
216 | } |
217 | |
218 | /** |
219 | * Add a CSS class jQuery style |
220 | * |
221 | * @author Dieter Raber, <dieter@taotesting.com> |
222 | * @param string $className |
223 | */ |
224 | public function addClass($className) |
225 | { |
226 | $existingClasses = !empty($this->attributes['class']) |
227 | ? explode(' ', $this->attributes['class']) |
228 | : []; |
229 | $existingClasses[] = $className; |
230 | $this->attributes['class'] = implode(' ', array_unique($existingClasses)); |
231 | } |
232 | |
233 | |
234 | /** |
235 | * Remove a CSS class jQuery style |
236 | * |
237 | * @author Dieter Raber, <dieter@taotesting.com> |
238 | * @param string $className |
239 | */ |
240 | public function removeClass($className) |
241 | { |
242 | $existingClasses = !empty($this->attributes['class']) |
243 | ? explode(' ', $this->attributes['class']) |
244 | : []; |
245 | unset($existingClasses[array_search($className, $existingClasses, true)]); |
246 | $this->attributes['class'] = implode(' ', $existingClasses); |
247 | } |
248 | |
249 | |
250 | /** |
251 | * Short description of method addAttribute |
252 | * |
253 | * @author Joel Bout, <joel@taotesting.com> |
254 | * @param string $key |
255 | * @param string $value |
256 | * @return void |
257 | */ |
258 | public function addAttribute($key, $value) |
259 | { |
260 | $this->attributes[$key] = $value; |
261 | } |
262 | |
263 | |
264 | /** |
265 | * Short description of method setAttribute |
266 | * |
267 | * @author Joel Bout, <joel@taotesting.com> |
268 | * @param string $key |
269 | * @param string $value |
270 | * @return void |
271 | */ |
272 | public function setAttribute($key, $value) |
273 | { |
274 | $this->attributes[$key] = $value; |
275 | } |
276 | |
277 | /** |
278 | * Short description of method setAttributes |
279 | * |
280 | * @author Joel Bout, <joel@taotesting.com> |
281 | * @param array $attributes |
282 | * @return void |
283 | */ |
284 | public function setAttributes($attributes) |
285 | { |
286 | $this->attributes = $attributes; |
287 | } |
288 | |
289 | /** |
290 | * Disables a UI input |
291 | */ |
292 | public function disable() |
293 | { |
294 | $this->addAttribute('disabled', 'disabled'); |
295 | } |
296 | |
297 | public function isDisabled(): bool |
298 | { |
299 | return isset($this->attributes['disabled']) && $this->attributes['disabled'] === 'disabled'; |
300 | } |
301 | |
302 | /** |
303 | * Short description of method renderAttributes |
304 | * |
305 | * @author Joel Bout, <joel@taotesting.com> |
306 | * @return string |
307 | */ |
308 | protected function renderAttributes() |
309 | { |
310 | $returnValue = ''; |
311 | |
312 | foreach ($this->attributes as $key => $value) { |
313 | $returnValue .= " {$key}='{$value}' "; |
314 | } |
315 | |
316 | return $returnValue; |
317 | } |
318 | |
319 | /** |
320 | * Short description of method getWidget |
321 | * |
322 | * @author Joel Bout, <joel@taotesting.com> |
323 | * @return string |
324 | */ |
325 | public function getWidget(): string |
326 | { |
327 | return $this->widget ?: static::WIDGET_ID; |
328 | } |
329 | |
330 | /** |
331 | * Short description of method getDescription |
332 | * |
333 | * @author Joel Bout, <joel@taotesting.com> |
334 | * @return string |
335 | */ |
336 | public function getDescription() |
337 | { |
338 | |
339 | if (empty($this->description)) { |
340 | $returnValue = ucfirst(strtolower($this->name)); |
341 | } else { |
342 | $returnValue = __($this->description); |
343 | } |
344 | |
345 | return (string) $returnValue; |
346 | } |
347 | |
348 | /** |
349 | * Short description of method setDescription |
350 | * |
351 | * @author Joel Bout, <joel@taotesting.com> |
352 | * @param string $description |
353 | * @return void |
354 | */ |
355 | public function setDescription($description) |
356 | { |
357 | $this->description = $description; |
358 | } |
359 | |
360 | /** |
361 | * Short description of method setUnit |
362 | * |
363 | * @author Joel Bout, <joel@taotesting.com> |
364 | * @param string $unit |
365 | * @return void |
366 | */ |
367 | public function setUnit($unit) |
368 | { |
369 | $this->unit = $unit; |
370 | } |
371 | |
372 | /** |
373 | * Short description of method getLevel |
374 | * |
375 | * @author Joel Bout, <joel@taotesting.com> |
376 | * @return int |
377 | */ |
378 | public function getLevel() |
379 | { |
380 | return (int) $this->level; |
381 | } |
382 | |
383 | /** |
384 | * Short description of method setLevel |
385 | * |
386 | * @author Joel Bout, <joel@taotesting.com> |
387 | * @param int $level |
388 | * @return void |
389 | */ |
390 | public function setLevel($level) |
391 | { |
392 | $this->level = $level; |
393 | } |
394 | |
395 | /** |
396 | * Short description of method addValidator |
397 | * |
398 | * @author Joel Bout, <joel@taotesting.com> |
399 | * @param ValidatorInterface $validator |
400 | */ |
401 | public function addValidator(ValidatorInterface $validator) |
402 | { |
403 | if ($validator instanceof tao_helpers_form_validators_NotEmpty) { |
404 | $this->addAttribute('required', true); |
405 | } |
406 | $this->validators[] = $validator; |
407 | } |
408 | |
409 | /** |
410 | * Short description of method addValidators |
411 | * |
412 | * @author Joel Bout, <joel@taotesting.com> |
413 | * @param array $validators |
414 | * @return void |
415 | */ |
416 | public function addValidators($validators) |
417 | { |
418 | foreach ($validators as $validator) { |
419 | $this->addValidator($validator); |
420 | } |
421 | } |
422 | |
423 | /** |
424 | * @return ValidatorInterface[] |
425 | */ |
426 | public function getValidators(): array |
427 | { |
428 | return $this->validators; |
429 | } |
430 | |
431 | /** |
432 | * Short description of method setForcedValid |
433 | * |
434 | * @access public |
435 | * @author Joel Bout, <joel@taotesting.com> |
436 | */ |
437 | public function setForcedValid() |
438 | { |
439 | $this->forcedValid = true; |
440 | } |
441 | |
442 | /** |
443 | * Short description of method validate |
444 | * |
445 | * @author Joel Bout, <joel@taotesting.com> |
446 | * @return bool |
447 | */ |
448 | public function validate() |
449 | { |
450 | if ($this->forcedValid) { |
451 | return true; |
452 | } |
453 | |
454 | $returnValue = true; |
455 | |
456 | /** @var ValidatorInterface $validator */ |
457 | foreach ($this->validators as $validator) { |
458 | if ($validator->evaluate($this->getRawValue())) { |
459 | continue; |
460 | } |
461 | |
462 | $returnValue = false; |
463 | $this->error[] = $validator->getMessage(); |
464 | |
465 | if ($this->isBreakOnFirstError()) { |
466 | break; |
467 | } |
468 | } |
469 | |
470 | return $returnValue; |
471 | } |
472 | |
473 | public function preValidate(): void |
474 | { |
475 | /** @var ValidatorInterface $validator */ |
476 | foreach ($this->validators as $validator) { |
477 | if ( |
478 | $validator instanceof PreliminaryValidationInterface |
479 | && $validator->isPreValidationRequired() |
480 | && !$validator->evaluate($this->getRawValue()) |
481 | ) { |
482 | $this->isValid = false; |
483 | $this->error[] = $validator->getMessage(); |
484 | } |
485 | } |
486 | } |
487 | |
488 | public function isValid(): bool |
489 | { |
490 | return $this->isValid; |
491 | } |
492 | |
493 | /** |
494 | * Short description of method getError |
495 | * |
496 | * @author Joel Bout, <joel@taotesting.com> |
497 | * @return string |
498 | */ |
499 | public function getError() |
500 | { |
501 | return implode("\n", $this->error); |
502 | } |
503 | |
504 | public function getInvalidValues(): array |
505 | { |
506 | return $this->invalidValues; |
507 | } |
508 | |
509 | public function setInvalidValues(array $invalidValues): void |
510 | { |
511 | $this->invalidValues = $invalidValues; |
512 | } |
513 | |
514 | /** |
515 | * Short description of method setHelp |
516 | * |
517 | * @author Joel Bout, <joel@taotesting.com> |
518 | * @param string $help |
519 | * @return void |
520 | */ |
521 | public function setHelp($help) |
522 | { |
523 | $this->help = $help; |
524 | } |
525 | |
526 | /** |
527 | * Short description of method getHelp |
528 | * |
529 | * @author Joel Bout, <joel@taotesting.com> |
530 | * @return string |
531 | */ |
532 | public function getHelp() |
533 | { |
534 | return (string) $this->help; |
535 | } |
536 | |
537 | /** |
538 | * Short description of method removeValidator |
539 | * |
540 | * @author Joel Bout, <joel@taotesting.com> |
541 | * @param string $name |
542 | * @return bool |
543 | */ |
544 | public function removeValidator($name) |
545 | { |
546 | $returnValue = false; |
547 | |
548 | $name = (string) $name; |
549 | if (strpos($name, 'tao_helpers_form_validators_') === 0) { |
550 | $name = str_replace('tao_helpers_form_validators_', '', $name); |
551 | } |
552 | if (isset($this->validators[$name])) { |
553 | unset($this->validators[$name]); |
554 | $returnValue = true; |
555 | } |
556 | |
557 | return $returnValue; |
558 | } |
559 | |
560 | /** |
561 | * Reads the submitted data into the form element |
562 | * |
563 | * @author Joel Bout, <joel@taotesting.com> |
564 | */ |
565 | public function feed() |
566 | { |
567 | $value = $this->getDecodedValue($this->name); |
568 | |
569 | if ($value !== null) { |
570 | $this->setValue(tao_helpers_Uri::decode($_POST[$this->name])); |
571 | } |
572 | } |
573 | |
574 | /** |
575 | * Returns the evaluated data that is calculated from the raw data and might |
576 | * unchanged for simple form elements. Used for storage of the data. |
577 | * |
578 | * @author joel bout, joel@taotesting.com |
579 | * @return string |
580 | */ |
581 | public function getEvaluatedValue() |
582 | { |
583 | return tao_helpers_Uri::decode($this->getRawValue()); |
584 | } |
585 | |
586 | /** |
587 | * Legacy code compliance method. When the getRawValue and the |
588 | * methods were added, the fact that the getValue method was still invoked |
589 | * TAO was not taken into account. To solve the problem, the getValue method |
590 | * added to this class. Its implementation will call the getRawValue method |
591 | * it has the same behaviour as the old getValue. |
592 | * |
593 | * @author Jérôme Bogaerts |
594 | * @deprecated |
595 | * @return mixed |
596 | */ |
597 | public function getValue() |
598 | { |
599 | common_Logger::d('deprecated function getValue() called', [ 'TAO', 'DEPRECATED' ]); |
600 | |
601 | return $this->getRawValue(); |
602 | } |
603 | |
604 | /** |
605 | * @return bool |
606 | */ |
607 | public function isBreakOnFirstError() |
608 | { |
609 | return $this->breakOnFirstError; |
610 | } |
611 | |
612 | /** |
613 | * @param bool $breakOnFirstError |
614 | */ |
615 | public function setBreakOnFirstError($breakOnFirstError) |
616 | { |
617 | $this->breakOnFirstError = $breakOnFirstError; |
618 | } |
619 | |
620 | public function getAttributes(): array |
621 | { |
622 | return $this->attributes; |
623 | } |
624 | |
625 | /** |
626 | * @return mixed |
627 | */ |
628 | public function getInputValue() |
629 | { |
630 | return $this->inputValue; |
631 | } |
632 | |
633 | public function feedInputValue(): void |
634 | { |
635 | $this->inputValue = $this->getDecodedValue($this->name); |
636 | } |
637 | |
638 | /** |
639 | * Will render the Form Element. |
640 | * |
641 | */ |
642 | abstract public function render(); |
643 | |
644 | private function getDecodedValue(string $name): ?string |
645 | { |
646 | if (isset($_POST[$name]) && $name !== 'uri' && $name !== 'classUri') { |
647 | return tao_helpers_Uri::decode($_POST[$this->name]); |
648 | } |
649 | |
650 | return null; |
651 | } |
652 | } |