Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
63 / 63
100.00% covered (success)
100.00%
12 / 12
CRAP
100.00% covered (success)
100.00%
1 / 1
AbstractInputSet
100.00% covered (success)
100.00%
63 / 63
100.00% covered (success)
100.00%
12 / 12
33
100.00% covered (success)
100.00%
1 / 1
 appendInputWithSpan
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
4
 setDisabled
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 setReadonly
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
4
 setInputAttribute
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 setInputAttributes
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 setLegend
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getLegend
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setContainer
100.00% covered (success)
100.00%
2 / 2
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
 getFieldsetChildNodes
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
5
 validate
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 render
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <nick@popphp.org>
8 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Form\Element;
16
17use Pop\Dom\Child;
18
19/**
20 * Abstract form input set class
21 *
22 * @category   Pop
23 * @package    Pop\Form
24 * @author     Nick Sagona, III <nick@popphp.org>
25 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
26 * @license    https://www.popphp.org/license     New BSD License
27 * @version    5.0.0
28 */
29abstract class AbstractInputSet extends AbstractElement
30{
31
32    /**
33     * Array of input elements
34     * @var array
35     */
36    protected array $inputs = [];
37
38    /**
39     * Fieldset legend
40     * @var ?string
41     */
42    protected ?string $legend = null;
43
44    /**
45     * Fieldset container
46     * @var ?string
47     */
48    protected ?string $container = null;
49
50    /**
51     * Create an input element, wrap it with its span and append it (and the input) to the set
52     *
53     * @param  AbstractElement $input
54     * @param  mixed           $nodeValue
55     * @param  string          $spanClass
56     * @param  ?string         $indent
57     * @param  string          $containerClass
58     * @return void
59     */
60    protected function appendInputWithSpan(
61        AbstractElement $input, mixed $nodeValue, string $spanClass, ?string $indent, string $containerClass
62    ): void
63    {
64        $span = new Child('span');
65        if ($indent !== null) {
66            $span->setIndent($indent);
67        }
68        $span->setAttribute('class', $spanClass);
69        $span->setNodeValue(($nodeValue !== null) ? (string)$nodeValue : null);
70
71        if (!empty($this->container)) {
72            $container = new Child($this->container);
73            $container->setAttribute('class', $containerClass);
74            $container->addChildren([$input, $span]);
75            $this->addChildren([$container]);
76        } else {
77            $this->addChildren([$input, $span]);
78        }
79
80        $this->inputs[] = $input;
81    }
82
83    /**
84     * Set whether the form element is disabled
85     *
86     * @param  bool $disabled
87     * @return static
88     */
89    public function setDisabled(bool $disabled): static
90    {
91        $childNodes = $this->getFieldsetChildNodes();
92        if ($disabled) {
93            foreach ($childNodes as $childNode) {
94                $childNode->setAttribute('disabled', 'disabled');
95            }
96        } else {
97            foreach ($childNodes as $childNode) {
98                $childNode->removeAttribute('disabled');
99            }
100        }
101
102        parent::setDisabled($disabled);
103        return $this;
104    }
105
106    /**
107     * Set whether the form element is readonly
108     *
109     * @param  bool $readonly
110     * @return static
111     */
112    public function setReadonly(bool $readonly): static
113    {
114        $childNodes = $this->getFieldsetChildNodes();
115        if ($readonly) {
116            foreach ($childNodes as $childNode) {
117                $childNode->setAttribute('readonly', 'readonly');
118                $childNode->setAttribute('onclick', 'return false;');
119            }
120        } else {
121            foreach ($childNodes as $childNode) {
122                $childNode->removeAttribute('readonly');
123                $childNode->removeAttribute('onclick');
124            }
125        }
126
127        parent::setReadonly($readonly);
128        return $this;
129    }
130
131    /**
132     * Set an attribute for the input elements
133     *
134     * @param  string $a
135     * @param  string $v
136     * @return static
137     */
138    protected function setInputAttribute(string $a, string $v): static
139    {
140        foreach ($this->inputs as $input) {
141            $input->setAttribute($a, $v);
142            if ($a == 'tabindex') {
143                $v = (string)((int)$v + 1);
144            }
145        }
146        return $this;
147    }
148
149    /**
150     * Set an attribute or attributes for the input elements
151     *
152     * @param  array $a
153     * @return static
154     */
155    protected function setInputAttributes(array $a): static
156    {
157        if (isset($a['tabindex'])) {
158            $a['tabindex'] = (string)$a['tabindex'];
159        }
160        foreach ($this->inputs as $input) {
161            $input->setAttributes($a);
162            if (isset($a['tabindex'])) {
163                $a['tabindex'] = (string)((int)$a['tabindex'] + 1);
164            }
165        }
166        return $this;
167    }
168
169    /**
170     * Method to set fieldset legend
171     *
172     * @param  string $legend
173     * @return static
174     */
175    public function setLegend(string $legend): static
176    {
177        $this->legend = $legend;
178        return $this;
179    }
180
181    /**
182     * Method to get fieldset legend
183     *
184     * @return ?string
185     */
186    public function getLegend(): ?string
187    {
188        return $this->legend;
189    }
190
191    /**
192     * Method to set fieldset container
193     *
194     * @param  string $container
195     * @return static
196     */
197    public function setContainer(string $container): static
198    {
199        $this->container = $container;
200        return $this;
201    }
202
203    /**
204     * Method to get fieldset container
205     *
206     * @return ?string
207     */
208    public function getContainer(): ?string
209    {
210        return $this->container;
211    }
212
213    /**
214     * Method to get fieldset child nodes
215     *
216     * @return array
217     */
218    public function getFieldsetChildNodes(): array
219    {
220        if (!empty($this->container)) {
221            $childNodes = [];
222            foreach ($this->childNodes as $childNode) {
223                if (($childNode->getNodeName() == $this->container) && ($childNode->hasChildNodes())) {
224                    $childNodes = array_merge($childNodes, $childNode->getChildNodes());
225                }
226            }
227            return $childNodes;
228        } else {
229            return $this->childNodes;
230        }
231    }
232
233    /**
234     * Validate the form element object
235     *
236     * @param  array $formValues
237     * @return bool
238     */
239    public function validate(array $formValues = []): bool
240    {
241        $value = $this->getValue();
242
243        // Check if the element is required
244        if (($this->required) && empty($value)) {
245            $this->errors[] = $this->getRequiredMessage();
246        }
247
248        $this->validateValue($value, $formValues);
249
250        return (count($this->errors) == 0);
251    }
252
253    /**
254     * Render the child and its child nodes
255     *
256     * @param  int     $depth
257     * @param  ?string $indent
258     * @param  bool    $inner
259     * @return string
260     */
261    public function render(int $depth = 0, ?string $indent = null, bool $inner = false): string
262    {
263        if (!empty($this->legend)) {
264            $this->addChild(new Child('legend', $this->legend));
265        }
266        return parent::render($depth, $indent, $inner);
267    }
268
269}