Completed
Push — master ( 5ff101...73de08 )
by Gabor
08:09
created

FormElement::setValidators()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 0
cts 7
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
crap 6
1
<?php
2
/**
3
 * WebHemi.
4
 *
5
 * PHP version 5.6
6
 *
7
 * @copyright 2012 - 2016 Gixx-web (http://www.gixx-web.com)
8
 * @license   https://opensource.org/licenses/MIT The MIT License (MIT)
9
 *
10
 * @link      http://www.gixx-web.com
11
 */
12
namespace WebHemi\Form\Element;
13
14
use InvalidArgumentException;
15
use RuntimeException;
16
use WebHemi\Form\Validator\FormValidatorInterface;
17
18
/**
19
 * Class FormElement
20
 */
21
final class FormElement extends AbstractFormElement
22
{
23
    /** @var array */
24
    private $options = [];
25
    /** @var array */
26
    private $optionGroups = [];
27
28
    /**
29
     * FormElement constructor.
30
     *
31
     * @param string $tagName
32
     * @param string $name
33
     * @param string $label
34
     * @param mixed  $value
35
     */
36
    public function __construct($tagName, $name = '', $label = '', $value = null)
37
    {
38
        $this->tagName = $tagName;
39
        $this->name = preg_replace('/[^a-z0-9]/', '_', strtolower($name));
40
        $this->label = $label;
41
        $this->value = $value;
42
43
        if (in_array($tagName, $this->tabIndexableTags)) {
44
            $this->attributes['tabindex'] = self::$tabIndex++;
45
        }
46
    }
47
48
    /**
49
     * Sets element name.
50
     *
51
     * @param string $name
52
     * @return FormElement
53
     */
54
    public function setName($name)
55
    {
56
        $this->name = $name;
57
58
        return $this;
59
    }
60
61
    /**
62
     * Returns the element name.
63
     *
64
     * @return string
65
     */
66
    public function getName()
67
    {
68
        $name = $this->name;
69
70
        if ($this->parentNode instanceof FormElementInterface) {
71
            $name = $this->parentNode->getName() . '[' . $this->name . ']';
72
        }
73
74
        if (count($this->options) > 1
75
            && $this->tagName  == self::TAG_SELECT
76
            && !empty($this->attributes['multiple'])
77
        ) {
78
            $name .= '[]';
79
        }
80
81
        return $name;
82
    }
83
84
    /**
85
     * Sets element label.
86
     *
87
     * @param string $label
88
     * @return FormElement
89
     */
90
    public function setLabel($label)
91
    {
92
        $this->label = $label;
93
94
        return $this;
95
    }
96
97
    /**
98
     * Sets element value.
99
     *
100
     * @param mixed $value
101
     * @return FormElement
102
     */
103
    public function setValue($value)
104
    {
105
        $this->value = $value;
106
107
        return $this;
108
    }
109
110
    /**
111
     * Gets element Id.
112
     *
113
     * @return string
114
     */
115
    public function getId()
116
    {
117
        $name = $this->getName();
118
        $md5Match = [];
119
120
        // Rip off the unique form prefix to make possible to work with fixed CSS id selectors.
121
        if (preg_match('/^[a-z0-9]+\_(?P<md5>[a-f0-9]{32}).*$/', $name, $md5Match)) {
122
            $name = str_replace('_' . $md5Match['md5'], '', $name);
123
        }
124
125
        return 'id_' . trim(preg_replace('/[^a-z0-9]/', '_', $name), '_');
126
    }
127
128
    /**
129
     * Set label-value options for the element.
130
     *
131
     * @param array $options
132
     * @throws RuntimeException
133
     * @return FormElement
134
     */
135
    public function setOptions(array $options)
136
    {
137
        foreach ($options as $option) {
138
            $checked = !empty($option['checked']);
139
            $group = !empty($option['group']) ? $option['group'] : 'Default';
140
            $this->setOption($option['label'], $option['value'], $checked, $group);
141
        }
142
143
        return $this;
144
    }
145
146
    /**
147
     * Checks if the element has value options.
148
     *
149
     * @return bool
150
     */
151
    public function hasOptions()
152
    {
153
        return !empty($this->options);
154
    }
155
156
    /**
157
     * Gets element value options.
158
     *
159
     * @return array
160
     */
161
    public function getOptions()
162
    {
163
        return $this->options;
164
    }
165
166
    /**
167
     * Sets label-value option for the element.
168
     *
169
     * @param string  $label
170
     * @param string  $value
171
     * @param boolean $checked
172
     * @param string  $group
173
     * @return FormElement
174
     */
175
    public function setOption($label, $value, $checked = false, $group = 'Default')
176
    {
177
        if (!in_array($this->tagName, $this->multiOptionTags)) {
178
            throw new RuntimeException(sprintf('Cannot set value options for `%s` element.', $this->tagName));
179
        }
180
181
        $option = &$this->options;
182
183
        // For <select> tag, the option groupping is allowed.
184
        if ($this->tagName == self::TAG_SELECT) {
185
            if (!isset($this->options[$group])) {
186
                $this->options[$group] = [];
187
            }
188
189
            $option = &$this->options[$group];
190
191
            $this->optionGroups[$group] = $group;
192
        }
193
194
        $option[$label] = [
195
            'label' => $label,
196
            'value' => $value,
197
            'checked' => $checked
198
        ];
199
200
        return $this;
201
    }
202
203
    /**
204
     * Checks if the Select box has groupped options.
205
     *
206
     * @return bool
207
     */
208
    public function isGrouppedSelect()
209
    {
210
        return count($this->optionGroups) > 1;
211
    }
212
213
    /**
214
     * Sets element attribute.
215
     *
216
     * @param string $key
217
     * @param mixed $value
218
     * @throws InvalidArgumentException
219
     * @return FormElement
220
     */
221
    public function setAttribute($key, $value)
222
    {
223
        if (!is_scalar($value)) {
224
            throw new InvalidArgumentException('Element attribute can hold scalar data only.');
225
        }
226
227
        $this->attributes[$key] = $value;
228
229
        return $this;
230
    }
231
232
    /**
233
     * Sets multiple attributes.
234
     *
235
     * @param array $attributes
236
     * @return FormElement
237
     */
238
    public function setAttributes(array $attributes)
239
    {
240
        foreach ($attributes as $key => $value) {
241
            $this->setAttribute($key, $value);
242
        }
243
244
        return $this;
245
    }
246
247
    /**
248
     * Gets element attribute.
249
     *
250
     * @param string $name
251
     * @return mixed
252
     */
253
    public function getAttribute($name)
254
    {
255
        if (!isset($this->attributes[$name])) {
256
            throw new RuntimeException(sprintf('Invalid attribute: `%s`', $name));
257
        }
258
259
        return $this->attributes[$name];
260
    }
261
262
    /**
263
     * Sets the element errors.
264
     *
265
     * @param array $errors
266
     * @return FormElement
267
     */
268
    public function setErrors(array $errors)
269
    {
270
        $this->errors = $errors;
271
    }
272
273
    /**
274
     * Sets the element validators.
275
     *
276
     * @param array<FormValidatorInterface> $validators
277
     * @return FormElement
278
     */
279
    public function setValidators(array $validators)
280
    {
281
        foreach ($validators as $validator) {
282
            $this->addValidator($validator);
283
        }
284
285
        return $this;
286
    }
287
288
    /**
289
     * Adds validator to the form.
290
     *
291
     * @param FormValidatorInterface $validator
292
     * @return FormElement
293
     */
294
    public function addValidator(FormValidatorInterface $validator)
295
    {
296
        $this->validators[] = $validator;
297
298
        return $this;
299
    }
300
301
    /**
302
     * Validates element value.
303
     *
304
     * @param bool $reValidate
305
     * @return bool
306
     */
307
    public function isValid($reValidate = false)
308
    {
309
        if ($reValidate) {
310
            $this->errors = [];
311
312
            /** @var FormValidatorInterface $validator */
313
            foreach ($this->validators as $validator) {
314
                if (!$validator->validate($this->value)) {
315
                    $this->errors[] = $validator->getError();
316
                }
317
            }
318
        }
319
320
        return empty($this->errors);
321
    }
322
323
    /**
324
     * Sets the parent element.
325
     *
326
     * @param FormElementInterface $formElement
327
     * @throws RuntimeException
328
     * @return FormElementInterface
329
     */
330
    public function setParentNode(FormElementInterface $formElement)
331
    {
332
        $parentTagName = $formElement->getTagName();
333
334
        if (isset($this->mandatoryTagParents[$this->tagName])
335
            && !in_array($parentTagName, $this->mandatoryTagParents[$this->tagName])
336
        ) {
337
            throw new RuntimeException(
338
                sprintf(
339
                    'Cannot set `%s` as child element of `%s`.',
340
                    $this->tagName,
341
                    $parentTagName
342
                )
343
            );
344
        }
345
346
        $this->parentNode = $formElement;
347
348
        return $this;
349
    }
350
351
    /**
352
     * Set the child nodes for the element.
353
     *
354
     * @param array<FormElementInterface> $childNodes
355
     * @return FormElement
356
     */
357
    public function setChildNodes(array $childNodes)
358
    {
359
        foreach ($childNodes as $formElement) {
360
            $this->addChildNode($formElement);
361
        }
362
363
        return $this;
364
    }
365
366
    /**
367
     * Set child node for the element.
368
     *
369
     * @param FormElementInterface $childNode
370
     * @return FormElement
371
     */
372
    public function addChildNode(FormElementInterface $childNode)
373
    {
374
        $childNode->setParentNode($this);
375
376
        $this->childNodes[] = $childNode;
377
378
        return $this;
379
    }
380
381
    /**
382
     * Gets the child nodes of the element.
383
     *
384
     * @return array<FormElement>
385
     */
386
    public function getChildNodes()
387
    {
388
        return $this->childNodes;
389
    }
390
}
391