Passed
Push — master ( c34495...8adf73 )
by Darío
03:13
created

FormValidator::validation()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 7

Importance

Changes 0
Metric Value
cc 7
eloc 15
nc 6
nop 4
dl 0
loc 25
ccs 15
cts 15
cp 1
crap 7
rs 8.8333
c 0
b 0
f 0
1
<?php
2
/**
3
 * DronePHP (http://www.dronephp.com)
4
 *
5
 * @link      http://github.com/Pleets/DronePHP
6
 * @copyright Copyright (c) 2016-2018 Pleets. (http://www.pleets.org)
7
 * @license   http://www.dronephp.com/license
8
 * @author    Darío Rivera <[email protected]>
9
 */
10
11
namespace Drone\Validator;
12
13
use Drone\Dom\Element\Form;
14
use Drone\Dom\Element\ElementFactory;
15
use Zend\Validator\NotEmpty;
16
use Zend\Validator\Digits;
17
use Zend\Validator\StringLength;
18
use Zend\Validator\Step;
19
use Zend\Validator\LessThan;
20
use Zend\Validator\GreaterThan;
21
use Zend\Validator\EmailAddress;
22
use Zend\Validator\Date;
23
use Zend\Validator\Uri;
24
25
/**
26
 * FormValidator class
27
 *
28
 * Form validation implements Zend validator to check html form parameters.
29
 * n-dimensional arrays (name='example[][]') are supported.
30
 */
31
class FormValidator
32
{
33
    use \Drone\Error\ErrorTrait;
34
35
    /**
36
     * The result of latest validation
37
     *
38
     * It's null before validate() execution
39
     *
40
     * @var boolean|null
41
     */
42
    private $valid;
43
44
    /**
45
     * Form instance
46
     *
47
     * @var Form
48
     */
49
    private $form;
50
51
    /**
52
     * Element options
53
     *
54
     * @var array
55
     */
56
    private $options;
0 ignored issues
show
introduced by
The private property $options is not used, and could be removed.
Loading history...
57
58
    /**
59
     * Translator object
60
     *
61
     * @var \Zend\Mvc\I18n\Translator
62
     */
63
    private $translator;
64
65
    /**
66
     * Returns the valid attribute after validation
67
     *
68
     * @return boolean
69
     */
70 5
    public function isValid()
71
    {
72 5
        if (is_null($this->valid)) {
73
            # This error is thrown because of 'setValid' method has not been executed.
74
            throw new \LogicException('No validation has been executed!');
75
        }
76
77 5
        return $this->valid;
78
    }
79
80
    /**
81
     * Sets valid atribute after each validation
82
     *
83
     * @param boolean $valid
84
     *
85
     * @return null
86
     */
87 5
    private function setValid($valid)
88
    {
89 5
        $this->valid = (is_null($this->valid) ? true : $this->valid) && $valid;
90 5
    }
91
92
    /**
93
     * Constructor
94
     *
95
     * @param Form   $form
96
     * @param string $locale
97
     */
98 5
    public function __construct(Form $form, $locale = null)
99
    {
100 5
        $this->form = $form;
101
102 5
        if (is_null($locale)) {
103
            $locale = 'en';
104
        }
105
106 5
        $i18nTranslator = \Zend\I18n\Translator\Translator::factory(
107
            [
108 5
                'locale'  => "$locale",
109
                'translation_files' => [
110
                    [
111 5
                        "type" => 'phparray',
112 5
                        "filename" => "vendor/zendframework/zend-i18n-resources/languages/$locale/Zend_Validate.php"
113
                    ]
114
                ]
115
            ]
116
        );
117
118 5
        $this->translator = new \Zend\Mvc\I18n\Translator($i18nTranslator);
119 5
    }
120
121
    /**
122
     * Checks all form rules
123
     *
124
     * @throws LogicException
125
     * @throws RuntimeException
126
     *
127
     * @return null
128
     */
129 5
    public function validate()
130
    {
131 5
        $this->valid = null;
132
133 5
        $this->setValid(true);
134 5
        $elements = $this->form->getChildren();
135
136 5
        foreach ($elements as $label => $element) {
137 5
            if (!$element->isFormControl()) {
138
                continue;
139
            }
140
141 5
            $attribs = $element->getAttributes();
142
143 5
            $all_attribs = [];
144
145 5
            foreach ($attribs as $attr) {
146 5
                $all_attribs[$attr->getName()] = $attr->getValue();
147
            }
148
149 5
            $required = array_key_exists('required', $all_attribs) ? $all_attribs["required"] : false;
150
151 5
            foreach ($attribs as $attr) {
152 5
                $name  = $attr->getName();
153 5
                $value = $attr->getValue();
154
155 5
                $attrib = $element->getAttribute("value");
156 5
                $form_value = (!is_null($attrib)) ? $attrib->getValue() : null;
157
158 5
                $validator = null;
159
160 5
                switch ($name) {
161 5
                    case 'required':
162 1
                        $validator = new NotEmpty();
163 1
                        break;
164
165 5
                    case 'minlength':
166 5
                        $validator = new StringLength(['min' => $value]);
167 5
                        break;
168
169 5
                    case 'maxlength':
170 5
                        $validator = new StringLength(['max' => $value]);
171 5
                        break;
172
173 5
                    case 'type':
174 5
                        switch ($value) {
175 5
                            case 'number':
176 1
                                $validator = new Digits();
177 1
                                break;
178
179 5
                            case 'email':
180 2
                                $validator = new EmailAddress();
181 2
                                break;
182
183 5
                            case 'date':
184
                                $validator = new Date();
185
                                break;
186
187 5
                            case 'url':
188
                                $validator = new Uri();
189
                                break;
190
                        }
191
192 5
                        break;
193
194 5
                    case 'min':
195 1
                        if (array_key_exists('type', $all_attribs) &&
196 1
                            in_array($all_attribs['type'], ['number', 'range'])
197
                        ) {
198 1
                            $validator = new GreaterThan(['min' => $value, 'inclusive' => true]);
199
                        } else {
200
                            throw new \LogicException("The input type must be 'range' or 'number'");
201
                        }
202
203 1
                        break;
204
205 5
                    case 'max':
206
                        if (array_key_exists('type', $all_attribs) &&
207
                            in_array($all_attribs['type'], ['number', 'range'])
208
                        ) {
209
                            $validator = new LessThan(['max' => $value, 'inclusive' => true]);
210
                        } else {
211
                            throw new \LogicException("The input type must be 'range' or 'number'");
212
                        }
213
214
                        break;
215
216 5
                    case 'step':
217
                        $baseValue = (array_key_exists('min', $all_attribs)) ? $all_attribs['min'] : 0;
218
219
                        if (array_key_exists('type', $all_attribs) && in_array($all_attribs['type'], ['range'])) {
220
                            $validator = new Step(['baseValue' => $baseValue, 'step' => $value]);
221
                        } else {
222
                            throw new \LogicException("The input type must be 'range'");
223
                        }
224
225
                        break;
226
227 5
                    case 'data-validators':
228 1
                        if (!is_array($value)) {
229
                            throw new \InvalidArgumentException(
230
                                "Invalid type given. Array expected in 'data-validators' attribute."
231
                            );
232
                        }
233
234 1
                        foreach ($value as $class => $params) {
235 1
                            $className = "\Zend\Validator\\" . $class;
236
237 1
                            if (!class_exists($className)) {
238 1
                                $className = "\Zend\I18n\Validator\\" . $class;
239
240 1
                                if (!class_exists($className)) {
241
                                    throw new \RuntimeException(
242
                                        "The class '$userInputClass' or '$className' does not exists"
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $userInputClass seems to be never defined.
Loading history...
243
                                    );
244
                                }
245
                            }
246
247 1
                            $validator = new $className($params);
248
249 1
                            $validator->setTranslator($this->translator);
250 1
                            $this->validation($validator, $form_value, $label, $required);
251
                        }
252
253 1
                        break;
254
                }
255
256 5
                if (in_array(
257 5
                    $name,
258 5
                    ['required', 'digits', 'minlength', 'maxlength', 'type', 'min', 'max', 'date', 'step']
259 5
                ) && !is_null($validator)) {
260 5
                    $validator->setTranslator($this->translator);
261 5
                    $this->validation($validator, $form_value, $label, $required);
262
                }
263
            }
264
        }
265 5
    }
266
267
    /**
268
     * Validate all field values iteratively
269
     *
270
     * Supports n-dimensional arrays (name='example[][]')
271
     *
272
     * @param \Zend\Validator $validator
273
     * @param mixed           $form_value
274
     * @param string          $label
275
     * @param boolean         $required
276
     *
277
     * @return null
278
     */
279 5
    private function validation($validator, $form_value, $label, $required)
280
    {
281 5
        if (gettype($form_value) != 'array') {
282 5
            $val = $form_value;
283
284
            # Check if the value is required. If it is, check the other rules.
285 5
            $v = new NotEmpty();
286 5
            $v->setTranslator($this->translator);
287 5
            $notEmpty = $v->isValid($val);
288
289 5
            if (!$required && !$notEmpty) {
290 1
                return null;
291
            }
292
293 5
            $valid = $validator->isValid($val);
294 5
            $this->setValid($valid);
295
296 5
            if (!$valid) {
297 4
                foreach ($validator->getMessages() as $message) {
298 5
                    $this->error($label ."-~-". (count($this->getErrors()) + 1), $message);
0 ignored issues
show
Bug introduced by
The method error() does not exist on Drone\Validator\FormValidator. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

298
                    $this->/** @scrutinizer ignore-call */ 
299
                           error($label ."-~-". (count($this->getErrors()) + 1), $message);
Loading history...
299
                }
300
            }
301
        } else {
302 1
            foreach ($form_value as $val) {
303 1
                $this->validation($validator, $val, $label, $required);
304
            }
305
        }
306 5
    }
307
308
    /**
309
     * {@inheritDoc}
310
     *
311
     * @return array
312
     */
313 5
    public function getErrors()
314
    {
315 5
        $errors = [];
316
317 5
        if (count($this->errors)) {
318 4
            foreach ($this->errors as $key => $value) {
319 4
                $errorLbl = explode("-~-", $key);
320 4
                $label = array_shift($errorLbl);
321
322 4
                if (!array_key_exists($label, $errors)) {
323 4
                    $errors[$label] = [];
324
                }
325
326 4
                $errors[$label][] = $value;
327
            }
328
        }
329
330 5
        return $errors;
331
    }
332
}
333