Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.36% covered (success)
90.36%
75 / 83
86.05% covered (success)
86.05%
37 / 43
CRAP
0.00% covered (danger)
0.00%
0 / 1
AbstractElement
90.36% covered (success)
90.36%
75 / 83
86.05% covered (success)
86.05%
37 / 43
67.67
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setName
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
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% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setHint
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setPrepend
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setAppend
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setLabelAttribute
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setLabelAttributes
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 setHintAttribute
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setHintAttributes
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 setRequired
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setDisabled
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setReadonly
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setErrorPre
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 isErrorPre
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setValidators
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 clearErrors
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
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% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasLabel
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getHint
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasHint
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPrepend
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 hasPrepend
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAppend
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 hasAppend
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getLabelAttributes
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasLabelAttributes
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getHintAttributes
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasHintAttributes
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getValidators
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasValidators
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isRequired
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isDisabled
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isReadonly
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isButton
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
4
 getErrors
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasErrors
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addValidator
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 addValidators
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 validateValue
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
7
 validateCallable
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
8
 validate
n/a
0 / 0
n/a
0 / 0
0
 __toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
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 */
14namespace Pop\Form\Element;
15
16use Pop\Dom\Child;
17use 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 */
29abstract 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}