Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
87.01% covered (success)
87.01%
201 / 231
89.19% covered (success)
89.19%
33 / 37
CRAP
0.00% covered (danger)
0.00%
0 / 1
Fieldset
87.01% covered (success)
87.01%
201 / 231
89.19% covered (success)
89.19%
33 / 37
151.54
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 createFromConfig
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 setContainer
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setCurrent
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 createGroup
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 addField
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 addFields
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 insertFieldBefore
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
 insertFieldAfter
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
 count
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 toArray
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getLegend
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getContainer
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getCurrent
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasField
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 getField
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getFields
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 getFieldGroups
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAllFields
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getFieldValue
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 setLegend
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setFieldValue
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 setFieldValues
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getIterator
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 prepare
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
5
 prepareForView
73.91% covered (success)
73.91%
17 / 23
0.00% covered (danger)
0.00%
0 / 1
13.15
 prepareTable
78.38% covered (success)
78.38%
29 / 37
0.00% covered (danger)
0.00%
0 / 1
17.27
 prepareElement
72.41% covered (success)
72.41%
21 / 29
0.00% covered (danger)
0.00%
0 / 1
18.11
 prepareDl
75.76% covered (success)
75.76%
25 / 33
0.00% covered (danger)
0.00%
0 / 1
16.79
 __set
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __get
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __isset
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __unset
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
4
 offsetExists
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 offsetGet
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 offsetSet
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 offsetUnset
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-2023 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;
15
16use Pop\Dom\Child;
17use Pop\Form\Element;
18use ReturnTypeWillChange;
19
20/**
21 * Form fieldset class
22 *
23 * @category   Pop
24 * @package    Pop\Form
25 * @author     Nick Sagona, III <dev@nolainteractive.com>
26 * @copyright  Copyright (c) 2009-2023 NOLA Interactive, LLC. (http://www.nolainteractive.com)
27 * @license    http://www.popphp.org/license     New BSD License
28 * @version    3.6.0
29 */
30
31class Fieldset extends Child implements \ArrayAccess, \Countable, \IteratorAggregate
32{
33
34    /**
35     * Form field elements
36     * @var array
37     */
38    protected $fields = [];
39
40    /**
41     * Current field group
42     * @var int
43     */
44    protected $current = 0;
45
46    /**
47     * Fieldset legend
48     * @var string
49     */
50    protected $legend = null;
51
52    /**
53     * Fieldset container (dl, table, div or p)
54     * @var string
55     */
56    protected $container = 'dl';
57
58    /**
59     * Constructor
60     *
61     * Instantiate the form fieldset object
62     *
63     * @param  array  $fields
64     * @param  string $container
65     */
66    public function __construct(array $fields = null, $container = 'dl')
67    {
68        parent::__construct('fieldset');
69        $this->setContainer($container);
70        if (null !== $fields) {
71            $this->addFields($fields);
72        }
73    }
74
75    /**
76     * Method to create form fieldset object and fields from config
77     *
78     * @param  array  $config
79     * @return Fieldset
80     */
81    public static function createFromConfig(array $config)
82    {
83        $fields = [];
84
85        foreach ($config as $name => $field) {
86            $fields[$name] = Fields::create($name, $field);
87        }
88
89        return new static($fields);
90    }
91
92    /**
93     * Method to set container
94     *
95     * @param  string $container
96     * @return Fieldset
97     */
98    public function setContainer($container)
99    {
100        $this->container = strtolower($container);
101        return $this;
102    }
103
104    /**
105     * Method to get current group index
106     *
107     * @param  int $i
108     * @return Fieldset
109     */
110    public function setCurrent($i)
111    {
112        $this->current = (int)$i;
113        if (!isset($this->fields[$this->current])) {
114            $this->fields[$this->current] = [];
115        }
116        return $this;
117    }
118
119    /**
120     * Method to create new group
121     *
122     * @return Fieldset
123     */
124    public function createGroup()
125    {
126        $this->current++;
127        $this->fields[$this->current] = [];
128        return $this;
129    }
130
131    /**
132     * Method to add a form field
133     *
134     * @param  Element\AbstractElement $field
135     * @return Fieldset
136     */
137    public function addField(Element\AbstractElement $field)
138    {
139        if (!isset($this->fields[$this->current])) {
140            $this->fields[$this->current] = [];
141        }
142        $this->fields[$this->current][$field->getName()] = $field;
143        return $this;
144    }
145
146    /**
147     * Method to add form fields
148     *
149     * @param  array $fields
150     * @return Fieldset
151     */
152    public function addFields(array $fields)
153    {
154        foreach ($fields as $field) {
155            $this->addField($field);
156        }
157        return $this;
158    }
159
160    /**
161     * Method to insert a field before another one
162     *
163     * @param  string                  $name
164     * @param  Element\AbstractElement $field
165     * @return Fieldset
166     */
167    public function insertFieldBefore($name, Element\AbstractElement $field)
168    {
169        foreach ($this->fields as $i => $group) {
170            $fields = [];
171            foreach ($group as $key => $value) {
172                if ($key == $name) {
173                    $fields[$field->getName()] = $field;
174                    $fields[$key] = $value;
175                } else {
176                    $fields[$key] = $value;
177                }
178            }
179            $this->fields[$i] = $fields;
180        }
181
182        return $this;
183    }
184
185    /**
186     * Method to insert a field after another one
187     *
188     * @param  string                  $name
189     * @param  Element\AbstractElement $field
190     * @return Fieldset
191     */
192    public function insertFieldAfter($name, Element\AbstractElement $field)
193    {
194        foreach ($this->fields as $i => $group) {
195            $fields = [];
196            foreach ($group as $key => $value) {
197                if ($key == $name) {
198                    $fields[$key] = $value;
199                    $fields[$field->getName()] = $field;
200                } else {
201                    $fields[$key] = $value;
202                }
203            }
204            $this->fields[$i] = $fields;
205        }
206
207        return $this;
208    }
209
210    /**
211     * Method to get the count of elements in the form fieldset
212     *
213     * @return int
214     */
215    public function count(): int
216    {
217        $count = 0;
218        foreach ($this->fields as $group) {
219            $count += count($group);
220        }
221        return $count;
222    }
223
224    /**
225     * Method to get the field values as an array
226     *
227     * @return array
228     */
229    public function toArray(): array
230    {
231        $fieldValues = [];
232
233        foreach ($this->fields as $group) {
234            foreach ($group as $name => $field) {
235                $fieldValues[$name] = $field->getValue();
236            }
237        }
238
239        return $fieldValues;
240    }
241
242    /**
243     * Method to get fieldset legend
244     *
245     * @return string
246     */
247    public function getLegend()
248    {
249        return $this->legend;
250    }
251
252    /**
253     * Method to get container
254     *
255     * @return string
256     */
257    public function getContainer()
258    {
259        return $this->container;
260    }
261
262    /**
263     * Method to get current group index
264     *
265     * @return int
266     */
267    public function getCurrent()
268    {
269        return $this->current;
270    }
271
272    /**
273     * Method to determine if the fieldset has a field
274     *
275     * @param  string $name
276     * @return boolean
277     */
278    public function hasField($name)
279    {
280        $result = false;
281        foreach ($this->fields as $key => $fields) {
282            if (isset($fields[$name])) {
283                $result = true;
284                break;
285            }
286        }
287        return $result;
288    }
289
290    /**
291     * Method to get a field element object
292     *
293     * @param  string $name
294     * @return Element\AbstractElement
295     */
296    public function getField($name)
297    {
298        $result = null;
299        foreach ($this->fields as $key => $fields) {
300            if (isset($fields[$name])) {
301                $result = $fields[$name];
302            }
303        }
304        return $result;
305    }
306
307    /**
308     * Method to get field element objects in a group
309     *
310     * @param  int  $i
311     * @return array
312     */
313    public function getFields($i)
314    {
315        return (isset($this->fields[$i])) ? $this->fields[$i] : null;
316    }
317
318    /**
319     * Method to get all field element groups
320     *
321     * @return array
322     */
323    public function getFieldGroups()
324    {
325        return $this->fields;
326    }
327
328    /**
329     * Method to get all field elements
330     *
331     * @return array
332     */
333    public function getAllFields()
334    {
335        $fields = [];
336        foreach ($this->fields as $group) {
337            foreach ($group as $field) {
338                $fields[$field->getName()] = $field;
339            }
340        }
341        return $fields;
342    }
343
344    /**
345     * Method to get a field element value
346     *
347     * @param  string $name
348     * @return mixed
349     */
350    public function getFieldValue($name)
351    {
352        $result = null;
353        foreach ($this->fields as $key => $fields) {
354            if (isset($fields[$name])) {
355                $result = $this->fields[$key][$name]->getValue();
356            }
357        }
358        return $result;
359    }
360
361    /**
362     * Method to set fieldset legend
363     *
364     * @param  string $legend
365     * @return Fieldset
366     */
367    public function setLegend($legend)
368    {
369        $this->legend = $legend;
370        return $this;
371    }
372
373    /**
374     * Method to set a field element value
375     *
376     * @param  string $name
377     * @param  mixed  $value
378     * @return Fieldset
379     */
380    public function setFieldValue($name, $value)
381    {
382        foreach ($this->fields as $key => $fields) {
383            if (isset($fields[$name])) {
384                $this->fields[$key][$name]->setValue($value);
385            }
386        }
387        return $this;
388    }
389
390    /**
391     * Method to set field element values
392     *
393     * @param  array $values
394     * @return Fieldset
395     */
396    public function setFieldValues(array $values)
397    {
398        foreach ($values as $name => $value) {
399            $this->setFieldValue($name, $value);
400        }
401        return $this;
402    }
403
404    /**
405     * Method to iterate over the form elements
406     *
407     * @return \ArrayIterator
408     */
409    public function getIterator(): \ArrayIterator
410    {
411        return new \ArrayIterator($this->toArray());
412    }
413
414    /**
415     * Prepare fieldset object for rendering
416     *
417     * @return Fieldset
418     */
419    public function prepare()
420    {
421        if (!empty($this->legend)) {
422            $this->addChild(new Child('legend', $this->legend));
423        }
424
425        switch ($this->container) {
426            case 'table':
427                $this->prepareTable();
428                break;
429            case 'dl':
430                $this->prepareDl();
431                break;
432            default:
433                $this->prepareElement($this->container);
434        }
435
436        return $this;
437    }
438
439    /**
440     * Prepare fieldset elements for rendering with a view
441     *
442     * @return array
443     */
444    public function prepareForView()
445    {
446        $fields = [];
447
448        foreach ($this->fields as $groups) {
449            foreach ($groups as $field) {
450                if (null !== $field->getLabel()) {
451                    $labelFor = $field->getName() . (($field->getNodeName() == 'fieldset') ? '1' : '');
452                    $label    = new Child('label', $field->getLabel());
453                    $label->setAttribute('for', $labelFor);
454                    if (null !== $field->getLabelAttributes()) {
455                        $label->setAttributes($field->getLabelAttributes());
456                    }
457                    if ($field->isRequired()) {
458                        if ($label->hasAttribute('class')) {
459                            $label->setAttribute('class', $label->getAttribute('class') . ' required');
460                        } else {
461                            $label->setAttribute('class', 'required');
462                        }
463                    }
464                    $fields[$field->getName() . '_label'] = $label->render();
465                }
466
467                if (null !== $field->getHint()) {
468                    $hint = new Child('span', $field->getHint());
469                    if (null !== $field->getHintAttributes()) {
470                        $hint->setAttributes($field->getHintAttributes());
471                    }
472                    $fields[$field->getName() . '_hint'] = $hint->render();
473                }
474
475                if ($field->hasErrors()) {
476                    $fields[$field->getName() . '_errors'] = $field->getErrors();
477                }
478
479                $fields[$field->getName()] = $field->render();
480            }
481        }
482
483        return $fields;
484    }
485
486    /**
487     * Prepare table
488     *
489     * @return void
490     */
491    protected  function prepareTable()
492    {
493        foreach ($this->fields as $fields) {
494            $table = new Child('table');
495
496            foreach ($fields as $field) {
497                $errors = [];
498                if ($field->hasErrors()) {
499                    foreach ($field->getErrors() as $error) {
500                        $errors[] = (new Child('div', $error))->setAttribute('class', 'error');
501                    }
502                }
503
504                $tr = new Child('tr');
505                if (null !== $field->getLabel()) {
506                    $td = new Child('td');
507                    $labelFor = $field->getName() . (($field->getNodeName() == 'fieldset') ? '1' : '');
508
509                    $label = new Child('label', $field->getLabel());
510                    $label->setAttribute('for', $labelFor);
511                    if (null !== $field->getLabelAttributes()) {
512                        $label->setAttributes($field->getLabelAttributes());
513                    }
514                    if ($field->isRequired()) {
515                        if ($label->hasAttribute('class')) {
516                            $label->setAttribute('class', $label->getAttribute('class') . ' required');
517                        } else {
518                            $label->setAttribute('class', 'required');
519                        }
520                    }
521                    $td->addChild($label);
522                    $tr->addChild($td);
523                }
524
525                $td = new Child('td');
526                if ($field->isErrorPre()) {
527                    $td->addChildren($errors);
528                }
529                $td->addChild($field);
530
531                if (null !== $field->getHint()) {
532                    $hint = new Child('span', $field->getHint());
533                    if (null !== $field->getHintAttributes()) {
534                        $hint->setAttributes($field->getHintAttributes());
535                    }
536                    $td->addChild($hint);
537                }
538
539                if (null === $field->getLabel()) {
540                    $td->setAttribute('colspan', 2);
541                }
542                if (!$field->isErrorPre()) {
543                    $td->addChildren($errors);
544                }
545                $tr->addChild($td);
546                $table->addChild($tr);
547            }
548
549            $this->addChild($table);
550        }
551    }
552
553    /**
554     * Prepare DIV or P
555     *
556     * @param  string $element
557     * @return void
558     */
559    protected  function prepareElement($element)
560    {
561        foreach ($this->fields as $fields) {
562            foreach ($fields as $field) {
563                $errors = [];
564                if ($field->hasErrors()) {
565                    foreach ($field->getErrors() as $error) {
566                        $errors[] = (new Child('div', $error))->setAttribute('class', 'error');
567                    }
568                }
569
570                $container = new Child($element);
571                if (null !== $field->getLabel()) {
572                    $labelFor = $field->getName() . (($field->getNodeName() == 'fieldset') ? '1' : '');
573                    $label    = new Child('label', $field->getLabel());
574                    $label->setAttribute('for', $labelFor);
575                    if (null !== $field->getLabelAttributes()) {
576                        $label->setAttributes($field->getLabelAttributes());
577                    }
578                    if ($field->isRequired()) {
579                        if ($label->hasAttribute('class')) {
580                            $label->setAttribute('class', $label->getAttribute('class') . ' required');
581                        } else {
582                            $label->setAttribute('class', 'required');
583                        }
584                    }
585                    $container->addChild($label);
586                }
587
588                if ($field->isErrorPre()) {
589                    $container->addChildren($errors);
590                }
591                $container->addChild($field);
592
593                if (null !== $field->getHint()) {
594                    $hint = new Child('span', $field->getHint());
595                    if (null !== $field->getHintAttributes()) {
596                        $hint->setAttributes($field->getHintAttributes());
597                    }
598                    $container->addChild($hint);
599                }
600                if (!$field->isErrorPre()) {
601                    $container->addChildren($errors);
602                }
603                $this->addChild($container);
604            }
605        }
606    }
607
608    /**
609     * Prepare DL
610     *
611     * @return void
612     */
613    protected  function prepareDl()
614    {
615        foreach ($this->fields as $fields) {
616            $dl = new Child('dl');
617
618            foreach ($fields as $field) {
619                $errors = [];
620                if ($field->hasErrors()) {
621                    foreach ($field->getErrors() as $error) {
622                        $errors[] = (new Child('div', $error))->setAttribute('class', 'error');
623                    }
624                }
625
626                if (null !== $field->getLabel()) {
627                    $dt = new Child('dt');
628                    $labelFor = $field->getName() . (($field->getNodeName() == 'fieldset') ? '1' : '');
629
630                    $label = new Child('label', $field->getLabel());
631                    $label->setAttribute('for', $labelFor);
632                    if (null !== $field->getLabelAttributes()) {
633                        $label->setAttributes($field->getLabelAttributes());
634                    }
635                    if ($field->isRequired()) {
636                        if ($label->hasAttribute('class')) {
637                            $label->setAttribute('class', $label->getAttribute('class') . ' required');
638                        } else {
639                            $label->setAttribute('class', 'required');
640                        }
641                    }
642                    $dt->addChild($label);
643                    $dl->addChild($dt);
644                }
645
646                $dd = new Child('dd');
647                if ($field->isErrorPre()) {
648                    $dd->addChildren($errors);
649                }
650                $dd->addChild($field);
651
652                if (null !== $field->getHint()) {
653                    $hint = new Child('span', $field->getHint());
654                    if (null !== $field->getHintAttributes()) {
655                        $hint->setAttributes($field->getHintAttributes());
656                    }
657                    $dd->addChild($hint);
658                }
659                if (!$field->isErrorPre()) {
660                    $dd->addChildren($errors);
661                }
662                $dl->addChild($dd);
663            }
664
665            $this->addChild($dl);
666        }
667    }
668
669    /**
670     * Set method to set the property to the value of fields[$name]
671     *
672     * @param  string $name
673     * @param  mixed $value
674     * @return void
675     */
676    public function __set($name, $value)
677    {
678        $this->setFieldValue($name, $value);
679    }
680
681    /**
682     * Get method to return the value of fields[$name]
683     *
684     * @param  string $name
685     * @throws Exception
686     * @return mixed
687     */
688    public function __get($name)
689    {
690        return $this->getFieldValue($name);
691    }
692
693    /**
694     * Return the isset value of fields[$name]
695     *
696     * @param  string $name
697     * @return boolean
698     */
699    public function __isset($name)
700    {
701        return $this->hasField($name);
702    }
703
704    /**
705     * Unset fields[$name]
706     *
707     * @param  string $name
708     * @return void
709     */
710    public function __unset($name)
711    {
712        foreach ($this->fields as $i => $group) {
713            foreach ($group as $key => $value) {
714                if ($key == $name) {
715                    unset($this->fields[$i][$key]);
716                }
717            }
718        }
719    }
720
721    /**
722     * ArrayAccess offsetExists
723     *
724     * @param  mixed $offset
725     * @return boolean
726     */
727    public function offsetExists($offset): bool
728    {
729        return $this->__isset($offset);
730    }
731
732    /**
733     * ArrayAccess offsetGet
734     *
735     * @param  mixed $offset
736     * @return mixed
737     */
738    #[\ReturnTypeWillChange]
739    public function offsetGet($offset)
740    {
741        return $this->__get($offset);
742    }
743
744    /**
745     * ArrayAccess offsetSet
746     *
747     * @param  mixed $offset
748     * @param  mixed $value
749     * @return void
750     */
751    #[\ReturnTypeWillChange]
752    public function offsetSet($offset, $value)
753    {
754        $this->__set($offset, $value);
755    }
756
757    /**
758     * ArrayAccess offsetUnset
759     *
760     * @param  mixed $offset
761     * @return void
762     */
763    #[\ReturnTypeWillChange]
764    public function offsetUnset($offset)
765    {
766        $this->__unset($offset);
767    }
768
769}