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