Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
90.36% |
75 / 83 |
|
86.05% |
37 / 43 |
CRAP | |
0.00% |
0 / 1 |
AbstractElement | |
90.36% |
75 / 83 |
|
86.05% |
37 / 43 |
67.67 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setName | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setValue | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
resetValue | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
setLabel | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setHint | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setPrepend | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
setAppend | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
setLabelAttribute | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setLabelAttributes | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
setHintAttribute | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setHintAttributes | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
setRequired | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setDisabled | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setReadonly | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setErrorPre | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
isErrorPre | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setValidators | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
clearErrors | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getName | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getType | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
getValue | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
getLabel | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
hasLabel | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getHint | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
hasHint | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getPrepend | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
hasPrepend | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getAppend | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
hasAppend | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getLabelAttributes | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
hasLabelAttributes | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getHintAttributes | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
hasHintAttributes | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getValidators | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
hasValidators | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isRequired | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isDisabled | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isReadonly | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isButton | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
4 | |||
getErrors | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
hasErrors | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
addValidator | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
addValidators | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
validateValue | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
7 | |||
validateCallable | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
8 | |||
validate | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
__toString | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | /** |
3 | * Pop PHP Framework (http://www.popphp.org/) |
4 | * |
5 | * @link https://github.com/popphp/popphp-framework |
6 | * @author Nick Sagona, III <dev@nolainteractive.com> |
7 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
8 | * @license http://www.popphp.org/license New BSD License |
9 | */ |
10 | |
11 | /** |
12 | * @namespace |
13 | */ |
14 | namespace Pop\Form\Element; |
15 | |
16 | use Pop\Dom\Child; |
17 | use Pop\Validator; |
18 | |
19 | /** |
20 | * Abstract form element class |
21 | * |
22 | * @category Pop |
23 | * @package Pop\Form |
24 | * @author Nick Sagona, III <dev@nolainteractive.com> |
25 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
26 | * @license http://www.popphp.org/license New BSD License |
27 | * @version 4.0.0 |
28 | */ |
29 | abstract class AbstractElement extends Child implements ElementInterface |
30 | { |
31 | |
32 | /** |
33 | * Element name |
34 | * @var ?string |
35 | */ |
36 | protected ?string $name = null; |
37 | |
38 | /** |
39 | * Form element label |
40 | * @var ?string |
41 | */ |
42 | protected ?string $label = null; |
43 | |
44 | /** |
45 | * Form element hint |
46 | * @var ?string |
47 | */ |
48 | protected ?string $hint = null; |
49 | |
50 | /** |
51 | * Form element label attributes |
52 | * @var array |
53 | */ |
54 | protected array $labelAttributes = []; |
55 | |
56 | /** |
57 | * Form element hint attributes |
58 | * @var array |
59 | */ |
60 | protected array $hintAttributes = []; |
61 | |
62 | /** |
63 | * Form element prepend contents |
64 | * @var ?string |
65 | */ |
66 | protected ?string $prepend = null; |
67 | |
68 | /** |
69 | * Form element append contents |
70 | * @var ?string |
71 | */ |
72 | protected ?string $append = null; |
73 | |
74 | /** |
75 | * Form element required property |
76 | * @var bool |
77 | */ |
78 | protected bool $required = false; |
79 | |
80 | /** |
81 | * Form element disabled property |
82 | * @var bool |
83 | */ |
84 | protected bool $disabled = false; |
85 | |
86 | /** |
87 | * Form element readonly property |
88 | * @var bool |
89 | */ |
90 | protected bool $readonly = false; |
91 | |
92 | /** |
93 | * Form element validators |
94 | * @var array |
95 | */ |
96 | protected array $validators = []; |
97 | |
98 | /** |
99 | * Form element error display position |
100 | * @var bool |
101 | */ |
102 | protected bool $errorPre = false; |
103 | |
104 | /** |
105 | * Form element errors |
106 | * @var array |
107 | */ |
108 | protected array $errors = []; |
109 | |
110 | /** |
111 | * Constructor |
112 | * |
113 | * Instantiate the form element object |
114 | * |
115 | * @param string $name |
116 | * @param ?string $value |
117 | * @param array $options |
118 | */ |
119 | public function __construct(string $name, ?string $value = null, array $options = []) |
120 | { |
121 | parent::__construct($name, $value, $options); |
122 | } |
123 | |
124 | /** |
125 | * Set the name of the form element object |
126 | * |
127 | * @param string $name |
128 | * @return AbstractElement |
129 | */ |
130 | public function setName(string $name): AbstractElement |
131 | { |
132 | $this->name = $name; |
133 | return $this; |
134 | } |
135 | |
136 | /** |
137 | * Set the value of the form element |
138 | * |
139 | * @param mixed $value |
140 | * @return AbstractElement |
141 | */ |
142 | abstract public function setValue(mixed $value): AbstractElement; |
143 | |
144 | /** |
145 | * Reset the value of the form element |
146 | * |
147 | * @return AbstractElement |
148 | */ |
149 | abstract public function resetValue(): AbstractElement; |
150 | |
151 | /** |
152 | * Set the label of the form element object |
153 | * |
154 | * @param string $label |
155 | * @return AbstractElement |
156 | */ |
157 | public function setLabel(string $label): AbstractElement |
158 | { |
159 | $this->label = $label; |
160 | return $this; |
161 | } |
162 | |
163 | /** |
164 | * Set the hint of the form element object |
165 | * |
166 | * @param string $hint |
167 | * @return AbstractElement |
168 | */ |
169 | public function setHint(string $hint): AbstractElement |
170 | { |
171 | $this->hint = $hint; |
172 | return $this; |
173 | } |
174 | |
175 | /** |
176 | * Set the prepend contents of the form element object |
177 | * |
178 | * @param string $prepend |
179 | * @return AbstractElement |
180 | */ |
181 | public function setPrepend(string $prepend): AbstractElement |
182 | { |
183 | $this->prepend = $prepend; |
184 | return $this; |
185 | } |
186 | |
187 | /** |
188 | * Set the append contents of the form element object |
189 | * |
190 | * @param string $append |
191 | * @return AbstractElement |
192 | */ |
193 | public function setAppend(string $append): AbstractElement |
194 | { |
195 | $this->append = $append; |
196 | return $this; |
197 | } |
198 | |
199 | /** |
200 | * Set an attribute of the label of the form element object |
201 | * |
202 | * @param string $a |
203 | * @param string $v |
204 | * @return AbstractElement |
205 | */ |
206 | public function setLabelAttribute(string $a, string $v): AbstractElement |
207 | { |
208 | $this->labelAttributes[$a] = $v; |
209 | return $this; |
210 | } |
211 | |
212 | /** |
213 | * Set the attributes of the label of the form element object |
214 | * |
215 | * @param array $attribs |
216 | * @return AbstractElement |
217 | */ |
218 | public function setLabelAttributes(array $attribs): AbstractElement |
219 | { |
220 | foreach ($attribs as $a => $v) { |
221 | $this->setLabelAttribute($a, $v); |
222 | } |
223 | return $this; |
224 | } |
225 | |
226 | /** |
227 | * Set an attribute of the hint of the form element object |
228 | * |
229 | * @param string $a |
230 | * @param string $v |
231 | * @return AbstractElement |
232 | */ |
233 | public function setHintAttribute(string $a, string $v): AbstractElement |
234 | { |
235 | $this->hintAttributes[$a] = $v; |
236 | return $this; |
237 | } |
238 | |
239 | /** |
240 | * Set the attributes of the hint of the form element object |
241 | * |
242 | * @param array $attribs |
243 | * @return AbstractElement |
244 | */ |
245 | public function setHintAttributes(array $attribs): AbstractElement |
246 | { |
247 | foreach ($attribs as $a => $v) { |
248 | $this->setHintAttribute($a, $v); |
249 | } |
250 | return $this; |
251 | } |
252 | |
253 | /** |
254 | * Set whether the form element is required |
255 | * |
256 | * @param bool $required |
257 | * @return AbstractElement |
258 | */ |
259 | public function setRequired(bool $required): AbstractElement |
260 | { |
261 | $this->required = $required; |
262 | return $this; |
263 | } |
264 | |
265 | /** |
266 | * Set whether the form element is disabled |
267 | * |
268 | * @param bool $disabled |
269 | * @return AbstractElement |
270 | */ |
271 | public function setDisabled(bool $disabled): AbstractElement |
272 | { |
273 | $this->disabled = $disabled; |
274 | return $this; |
275 | } |
276 | |
277 | /** |
278 | * Set whether the form element is readonly |
279 | * |
280 | * @param bool $readonly |
281 | * @return AbstractElement |
282 | */ |
283 | public function setReadonly(bool $readonly): AbstractElement |
284 | { |
285 | $this->readonly = $readonly; |
286 | return $this; |
287 | } |
288 | |
289 | /** |
290 | * Set error pre-display |
291 | * |
292 | * @param bool $pre |
293 | * @return AbstractElement |
294 | */ |
295 | public function setErrorPre(bool $pre): AbstractElement |
296 | { |
297 | $this->errorPre = $pre; |
298 | return $this; |
299 | } |
300 | |
301 | /** |
302 | * Determine if error to display before the element |
303 | * |
304 | * @return bool |
305 | */ |
306 | public function isErrorPre(): bool |
307 | { |
308 | return $this->errorPre; |
309 | } |
310 | |
311 | /** |
312 | * Set validators |
313 | * |
314 | * @param array $validators |
315 | * @return AbstractElement |
316 | */ |
317 | public function setValidators(array $validators = []): AbstractElement |
318 | { |
319 | $this->validators = $validators; |
320 | return $this; |
321 | } |
322 | |
323 | /** |
324 | * Clear errors |
325 | * |
326 | * @return AbstractElement |
327 | */ |
328 | public function clearErrors(): AbstractElement |
329 | { |
330 | $this->errors = []; |
331 | return $this; |
332 | } |
333 | |
334 | /** |
335 | * Get form element object name |
336 | * |
337 | * @return ?string |
338 | */ |
339 | public function getName(): ?string |
340 | { |
341 | return $this->name; |
342 | } |
343 | |
344 | /** |
345 | * Get form element object type |
346 | * |
347 | * @return ?string |
348 | */ |
349 | abstract public function getType() : ?string; |
350 | |
351 | /** |
352 | * Get form element value |
353 | * |
354 | * @return mixed |
355 | */ |
356 | abstract public function getValue(): mixed; |
357 | |
358 | /** |
359 | * Get form element object label |
360 | * |
361 | * @return ?string |
362 | */ |
363 | public function getLabel(): ?string |
364 | { |
365 | return $this->label; |
366 | } |
367 | |
368 | /** |
369 | * Determine if form element has a label |
370 | * |
371 | * @return bool |
372 | */ |
373 | public function hasLabel(): bool |
374 | { |
375 | return !empty($this->label); |
376 | } |
377 | |
378 | /** |
379 | * Get form element object hint |
380 | * |
381 | * @return ?string |
382 | */ |
383 | public function getHint(): ?string |
384 | { |
385 | return $this->hint; |
386 | } |
387 | |
388 | /** |
389 | * Determine if form element has a hint |
390 | * |
391 | * @return bool |
392 | */ |
393 | public function hasHint(): bool |
394 | { |
395 | return !empty($this->hint); |
396 | } |
397 | |
398 | /** |
399 | * Get form element object prepend contents |
400 | * |
401 | * @return ?string |
402 | */ |
403 | public function getPrepend(): ?string |
404 | { |
405 | return $this->prepend; |
406 | } |
407 | |
408 | /** |
409 | * Determine if form element has prepend content |
410 | * |
411 | * @return bool |
412 | */ |
413 | public function hasPrepend(): bool |
414 | { |
415 | return !empty($this->prepend); |
416 | } |
417 | |
418 | /** |
419 | * Get form element object append contents |
420 | * |
421 | * @return ?string |
422 | */ |
423 | public function getAppend(): ?string |
424 | { |
425 | return $this->append; |
426 | } |
427 | |
428 | /** |
429 | * Determine if form element has append content |
430 | * |
431 | * @return bool |
432 | */ |
433 | public function hasAppend(): bool |
434 | { |
435 | return !empty($this->append); |
436 | } |
437 | |
438 | /** |
439 | * Get the attributes of the form element object label |
440 | * |
441 | * @return array |
442 | */ |
443 | public function getLabelAttributes(): array |
444 | { |
445 | return $this->labelAttributes; |
446 | } |
447 | |
448 | /** |
449 | * Determine if form element has label attributes |
450 | * |
451 | * @return bool |
452 | */ |
453 | public function hasLabelAttributes(): bool |
454 | { |
455 | return !empty($this->labelAttributes); |
456 | } |
457 | |
458 | /** |
459 | * Get the attributes of the form element object hint |
460 | * |
461 | * @return array |
462 | */ |
463 | public function getHintAttributes(): array |
464 | { |
465 | return $this->hintAttributes; |
466 | } |
467 | |
468 | /** |
469 | * Determine if form element has hint attributes |
470 | * |
471 | * @return bool |
472 | */ |
473 | public function hasHintAttributes(): bool |
474 | { |
475 | return !empty($this->hintAttributes); |
476 | } |
477 | |
478 | /** |
479 | * Get validators |
480 | * |
481 | * @return array |
482 | */ |
483 | public function getValidators(): array |
484 | { |
485 | return $this->validators; |
486 | } |
487 | |
488 | /** |
489 | * Determine if form element has validators |
490 | * |
491 | * @return bool |
492 | */ |
493 | public function hasValidators(): bool |
494 | { |
495 | return !empty($this->validators); |
496 | } |
497 | |
498 | /** |
499 | * Get whether the form element object is required |
500 | * |
501 | * @return bool |
502 | */ |
503 | public function isRequired(): bool |
504 | { |
505 | return $this->required; |
506 | } |
507 | |
508 | /** |
509 | * Get whether the form element object is disabled |
510 | * |
511 | * @return bool |
512 | */ |
513 | public function isDisabled(): bool |
514 | { |
515 | return $this->disabled; |
516 | } |
517 | |
518 | /** |
519 | * Get whether the form element object is readonly |
520 | * |
521 | * @return bool |
522 | */ |
523 | public function isReadonly(): bool |
524 | { |
525 | return $this->readonly; |
526 | } |
527 | |
528 | /** |
529 | * Get whether the form element object is a button |
530 | * |
531 | * @return bool |
532 | */ |
533 | public function isButton(): bool |
534 | { |
535 | return (($this instanceof Button) || ($this instanceof Input\Button) || |
536 | ($this instanceof Input\Submit) || ($this instanceof Input\Reset)); |
537 | } |
538 | |
539 | /** |
540 | * Get form element object errors |
541 | * |
542 | * @return array |
543 | */ |
544 | public function getErrors(): array |
545 | { |
546 | return $this->errors; |
547 | } |
548 | |
549 | /** |
550 | * Get if form element object has errors |
551 | * |
552 | * @return bool |
553 | */ |
554 | public function hasErrors(): bool |
555 | { |
556 | return (count($this->errors) > 0); |
557 | } |
558 | |
559 | /** |
560 | * Add a validator the form element |
561 | * |
562 | * @param mixed $validator |
563 | * @throws Exception |
564 | * @return AbstractElement |
565 | */ |
566 | public function addValidator(mixed $validator): AbstractElement |
567 | { |
568 | if (!($validator instanceof \Pop\Validator\AbstractValidator) && !is_callable($validator)) { |
569 | throw new Exception('Error: The validator must be an instance of Pop\Validator\AbstractValidator or a callable object.'); |
570 | } |
571 | $this->validators[] = $validator; |
572 | return $this; |
573 | } |
574 | |
575 | /** |
576 | * Add multiple validators the form element |
577 | * |
578 | * @param array $validators |
579 | * @throws Exception |
580 | * @return AbstractElement |
581 | */ |
582 | public function addValidators(array $validators): AbstractElement |
583 | { |
584 | foreach ($validators as $validator) { |
585 | $this->addValidator($validator); |
586 | } |
587 | return $this; |
588 | } |
589 | |
590 | /** |
591 | * Validate the value |
592 | * |
593 | * @param mixed $value |
594 | * @param array $formValues |
595 | * @return void |
596 | */ |
597 | public function validateValue(mixed $value, array $formValues = []): void |
598 | { |
599 | // Check field validators |
600 | if (count($this->validators) > 0) { |
601 | foreach ($this->validators as $validator) { |
602 | if ($validator instanceof \Pop\Validator\ValidatorInterface) { |
603 | if (!$validator->evaluate($value)) { |
604 | if (!in_array($validator->getMessage(), $this->errors)) { |
605 | $this->errors[] = $validator->getMessage(); |
606 | } |
607 | } |
608 | } else if (is_callable($validator)) { |
609 | $this->validateCallable($validator, $value, $formValues); |
610 | } |
611 | } |
612 | } |
613 | } |
614 | |
615 | /** |
616 | * Validate the value by callable |
617 | * |
618 | * @param callable $validator |
619 | * @param mixed $value |
620 | * @param array $formValues |
621 | * @return void |
622 | */ |
623 | public function validateCallable(callable $validator, mixed $value, array $formValues = []): void |
624 | { |
625 | $result = call_user_func_array($validator, [$value, $formValues]); |
626 | if ($result instanceof \Pop\Validator\ValidatorInterface) { |
627 | if (!$result->evaluate($value)) { |
628 | $this->errors[] = $result->getMessage(); |
629 | } |
630 | } else if (is_array($result)) { |
631 | foreach ($result as $val) { |
632 | if ($val instanceof \Pop\Validator\ValidatorInterface) { |
633 | if (!$val->evaluate($value)) { |
634 | $this->errors[] = $val->getMessage(); |
635 | } |
636 | } |
637 | } |
638 | } else if ($result !== null) { |
639 | $this->errors[] = $result; |
640 | } |
641 | } |
642 | |
643 | /** |
644 | * Validate the form element object |
645 | * |
646 | * @param array $formValues |
647 | * @return bool |
648 | */ |
649 | abstract public function validate(array $formValues = []): bool; |
650 | |
651 | /** |
652 | * Print form element |
653 | * |
654 | * @return string |
655 | */ |
656 | public function __toString(): string |
657 | { |
658 | return $this->render(); |
659 | } |
660 | |
661 | } |