Completed
Push — master ( 8219b7...c7f806 )
by Gabor
03:21
created

AbstractElement::hasErrors()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
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\Web;
13
14
use Exception;
15
use InvalidArgumentException;
16
use Iterator;
17
use RuntimeException;
18
use WebHemi\Form\Element\FormElementInterface;
19
use WebHemi\Form\Element\NestedElementInterface;
20
use WebHemi\Form\Element\Traits\IteratorTrait;
21
use WebHemi\Validator\ValidatorInterface;
22
23
/**
24
 * Class AbstractElement
25
 */
26
abstract class AbstractElement implements FormElementInterface, Iterator
27
{
28
    /** @var string */
29
    protected $type = '';
30
    /** @var int */
31
    protected static $tabIndex = 1;
32
33
    /** @var string */
34
    protected $name;
35
    /** @var string */
36
    protected $label;
37
    /** @var mixed */
38
    protected $value;
39
    /** @var array */
40
    protected $attributes = [];
41
    /** @var array<ValidatorInterface> */
42
    protected $validators = [];
43
    /** @var array */
44
    protected $errors = [];
45
    /** @var FormElementInterface */
46
    protected $parentNode;
47
    /** @var array */
48
    protected $mandatoryParentTypes = [];
49
50
    // The implementation of the Iterator interface.
51
    use IteratorTrait;
52
53
    /**
54
     * AbstractFormElement constructor.
55
     *
56
     * @param string $name
57
     * @param string $label
58
     * @param mixed  $value
59
     */
60 7
    public function __construct($name = '', $label = '', $value = null)
61
    {
62 7
        $this->name = preg_replace('/[^a-z0-9]/', '_', strtolower($name));
63 7
        $this->label = $label;
64 7
        $this->value = $value;
65 7
    }
66
67
    /**
68
     * Returns the element type.
69
     *
70
     * @throws Exception
71
     * @return string
72
     */
73
    final public function getType()
74
    {
75
        if (empty($this->type)) {
76
            throw new Exception('You must specify the element type in the $type class property.');
77
        }
78
79
        return $this->type;
80
    }
81
82
    /**
83
     * Sets element name. The implementation should decide if it is allowed after init.
84
     *
85
     * @param string $name
86
     * @return AbstractElement
87
     */
88 7
    public function setName($name)
89
    {
90 7
        $this->name = $name;
91
92 7
        return $this;
93
    }
94
95
    /**
96
     * Returns the element name. If parameter is TRUE, then the method should include all the parents' names as well.
97
     *
98
     * @param boolean $getFulNodeName
99
     * @return string
100
     */
101 7
    public function getName($getFulNodeName = true)
102
    {
103 7
        $name = $this->name;
104
105 7
        if ($getFulNodeName) {
106 3
            if ($this->parentNode instanceof FormElementInterface) {
107
                $name = $this->parentNode->getName().'['.$this->name.']';
108
            }
109
        }
110
111 7
        return $name;
112
    }
113
114
    /**
115
     * Sets element label.
116
     *
117
     * @param string $label
118
     * @return AbstractElement
119
     */
120
    public function setLabel($label)
121
    {
122
        $this->label = $label;
123
124
        return $this;
125
    }
126
127
    /**
128
     * Returns the element label.
129
     *
130
     * @return string
131
     */
132
    public function getLabel()
133
    {
134
        return $this->label;
135
    }
136
137
    /**
138
     * Sets element value.
139
     *
140
     * @param mixed $value
141
     * @return AbstractElement
142
     */
143 7
    public function setValue($value)
144
    {
145 7
        $this->value = $value;
146
147 7
        return $this;
148
    }
149
150
    /**
151
     * Returns element value.
152
     *
153
     * @return mixed
154
     */
155 1
    public function getValue()
156
    {
157 1
        return $this->value;
158
    }
159
160
    /**
161
     * Gets element Id.
162
     *
163
     * @return string
164
     */
165
    public function getId()
166
    {
167
        $name = $this->getName();
168
        $md5Match = [];
169
170
        // Rip off the unique form prefix to make possible to work with fixed CSS id selectors.
171
        if (preg_match('/^[-z0-9\_\-\[\]]+\_(?P<md5>[a-f0-9]{32}).*$/', $name, $md5Match)) {
172
            $name = str_replace('_'.$md5Match['md5'], '', $name);
173
        }
174
175
        $elementId = 'id_'.trim(preg_replace('/[^a-z0-9]/', '_', $name), '_');
176
177
        return str_replace('__', '_', $elementId);
178
    }
179
180
    /**
181
     * Sets multiple attributes.
182
     *
183
     * @param array $attributes
184
     * @return AbstractElement
185
     */
186 7
    public function setAttributes(array $attributes)
187
    {
188 7
        $this->attributes = [];
189
190 7
        foreach ($attributes as $key => $value) {
191 7
            $this->setAttribute($key, $value);
192
        }
193
194 7
        return $this;
195
    }
196
197
    /**
198
     * Sets element attribute.
199
     *
200
     * @param string $key
201
     * @param mixed $value
202
     * @throws InvalidArgumentException
203
     * @return AbstractElement
204
     */
205 7
    protected function setAttribute($key, $value)
206
    {
207 7
        if (!is_scalar($value)) {
208
            throw new InvalidArgumentException('Element attribute can hold scalar data only.');
209
        }
210
211 7
        $this->attributes[$key] = $value;
212
213 7
        return $this;
214
    }
215
216
    /**
217
     * Gets all the attributes.
218
     *
219
     * @return array
220
     */
221 4
    public function getAttributes()
222
    {
223 4
        return $this->attributes;
224
    }
225
226
    /**
227
     * Gets element attribute.
228
     *
229
     * @param string $name
230
     * @return mixed
231
     */
232
    public function getAttribute($name)
233
    {
234
        if (!isset($this->attributes[$name])) {
235
            throw new InvalidArgumentException(sprintf('Invalid attribute: `%s`', $name));
236
        }
237
238
        return $this->attributes[$name];
239
    }
240
241
    /**
242
     * Sets and increments the tabulator index globally. This method should be used only on visible elements.
243
     *
244
     * @return AbstractElement
245
     */
246 7
    public function setTabIndex()
247
    {
248 7
        $this->attributes['tabindex'] = self::$tabIndex++;
249
250 7
        return $this;
251
    }
252
253
    /**
254
     * Sets the element errors. Usually the validator should set it, but it is allowed to set from outside too.
255
     *
256
     * @param array $errors
257
     * @return AbstractElement
258
     */
259
    public function setErrors(array $errors)
260
    {
261
        $this->errors = $errors;
262
263
        return $this;
264
    }
265
266
    /**
267
     * Checks if there are error messages set.
268
     *
269
     * @return boolean
270
     */
271
    public function hasErrors()
272
    {
273
        return !empty($this->errors);
274
    }
275
276
    /**
277
     * Gets validation errors.
278
     *
279
     * @return array
280
     */
281
    public function getErrors()
282
    {
283
        return $this->errors;
284
    }
285
286
    /**
287
     * Sets the element validators.
288
     *
289
     * @param array<ValidatorInterface> $validators
290
     * @return FormElementInterface
291
     */
292
    public function setValidators(array $validators)
293
    {
294
        $this->validators = [];
295
296
        foreach ($validators as $validator) {
297
            $this->addValidator($validator);
298
        }
299
300
        return $this;
301
    }
302
303
    /**
304
     * Adds validator to the form.
305
     *
306
     * @param ValidatorInterface $validator
307
     * @return AbstractElement
308
     */
309
    protected function addValidator(ValidatorInterface $validator)
310
    {
311
        $this->validators[] = $validator;
312
313
        return $this;
314
    }
315
316
    /**
317
     * Gets the element validators.
318
     *
319
     * @return array<ValidatorInterface>
320
     */
321
    public function getValidators()
322
    {
323
        return $this->validators;
324
    }
325
326
    /**
327
     * Validates element value.
328
     *
329
     * @param bool $reValidate
330
     * @return bool
331
     */
332 1
    public function isValid($reValidate = false)
333
    {
334 1
        if ($reValidate) {
335
            $this->errors = [];
336
337
            /** @var ValidatorInterface $validator */
338
            foreach ($this->validators as $validator) {
339
                if (!$validator->validate($this->value)) {
340
                    $this->errors[] = $validator->getError();
341
                }
342
            }
343
        }
344
345 1
        return empty($this->errors);
346
    }
347
348
    /**
349
     * Sets the parent element.
350
     *
351
     * @param FormElementInterface $formElement
352
     * @throws RuntimeException
353
     * @return AbstractElement
354
     */
355 7
    public function setParentNode(FormElementInterface $formElement)
356
    {
357 7
        if (!$formElement instanceof NestedElementInterface) {
358
            throw new RuntimeException(
359
                sprintf(
360
                    'Cannot set `%s` as child element of `%s`.',
361
                    $this->getType(),
362
                    $formElement->getType()
363
                )
364
            );
365
        }
366
367 7
        $this->parentNode = $formElement;
368
369 7
        return $this;
370
    }
371
372
    /**
373
     * Gets the parent element.
374
     *
375
     * @return FormElementInterface
376
     */
377
    public function getParentNode()
378
    {
379
        return $this->parentNode;
380
    }
381
}
382