Passed
Pull Request — master (#312)
by Arman
03:34
created

Validator::addValidation()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 3
nc 2
nop 2
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Quantum PHP Framework
5
 *
6
 * An open source software development framework for PHP
7
 *
8
 * @package Quantum
9
 * @author Arman Ag. <[email protected]>
10
 * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org)
11
 * @link http://quantum.softberg.org/
12
 * @since 2.9.8
13
 */
14
15
namespace Quantum\Libraries\Validation;
16
17
use Quantum\Libraries\Validation\Rules\Resource;
18
use Quantum\Libraries\Validation\Rules\General;
19
use Quantum\Libraries\Validation\Rules\Length;
20
use Quantum\Libraries\Validation\Rules\Lists;
21
use Quantum\Libraries\Validation\Rules\Type;
22
use Quantum\Libraries\Validation\Rules\File;
23
use Closure;
24
25
/**
26
 * Class Validator
27
 * @package Quantum\Libraries\Validation
28
 */
29
class Validator
30
{
31
32
    use General;
33
    use Type;
34
    use File;
35
    use Lists;
36
    use Length;
37
    use Resource;
38
39
    /**
40
     * Rules
41
     * @var array
42
     */
43
    private $rules = [];
44
45
    /**
46
     * Validation Errors
47
     * @var array
48
     */
49
    private $errors = [];
50
51
    /**
52
     * Request data
53
     * @var array
54
     */
55
    private $data = [];
56
57
    /**
58
     * Custom validation callbacks
59
     * @var Closure[]
60
     */
61
    private $customValidations = [];
62
63
    /**
64
     * Add rules for a single field
65
     * @param string $field
66
     * @param array $rules Format: [['ruleName' => param], ...]
67
     */
68
    public function addRule(string $field, array $rules)
69
    {
70
        if (empty($field)) {
71
            return;
72
        }
73
74
        if (!isset($this->rules[$field])) {
75
            $this->rules[$field] = [];
76
        }
77
78
        foreach ($rules as $rule) {
79
            $ruleName = key($rule);
80
            $ruleParam = current($rule);
81
            $this->rules[$field][$ruleName] = $ruleParam;
82
        }
83
    }
84
85
    /**
86
     * Add multiple rules for multiple fields
87
     * @param array $rules Format: ['field' => [ ['rule' => param], ... ], ...]
88
     */
89
    public function addRules(array $rules): void
90
    {
91
        foreach ($rules as $field => $fieldRules) {
92
            $this->addRule($field, $fieldRules);
93
        }
94
    }
95
96
    /**
97
     * Update a single rule for a field if exists
98
     * @param string $field
99
     * @param array $rule Format: ['ruleName' => param]
100
     */
101
    public function updateRule(string $field, array $rule)
102
    {
103
        if (empty($field)) {
104
            return;
105
        }
106
107
        $ruleName = key($rule);
108
        $ruleParam = current($rule);
109
110
        if (isset($this->rules[$field][$ruleName])) {
111
            $this->rules[$field][$ruleName] = $ruleParam;
112
        }
113
    }
114
115
    /**
116
     * Delete a rule or all rules for a given field
117
     * @param string $field
118
     * @param string|null $rule Specific rule to delete; if null deletes all rules for field
119
     * @return void
120
     */
121
    public function deleteRule(string $field, string $rule = null): void
122
    {
123
        if (empty($field) || !isset($this->rules[$field])) {
124
            return;
125
        }
126
127
        if ($rule !== null) {
128
            unset($this->rules[$field][$rule]);
129
            if (empty($this->rules[$field])) {
130
                unset($this->rules[$field]);
131
            }
132
        } else {
133
            unset($this->rules[$field]);
134
        }
135
    }
136
137
    /**
138
     * Flush all rules and errors
139
     * @return void
140
     */
141
    public function flushRules(): void
142
    {
143
        $this->rules = [];
144
        $this->flushErrors();
145
    }
146
147
    /**
148
     * Validate given data against defined rules
149
     * @param array $data
150
     * @return bool True if valid, false otherwise
151
     */
152
    public function isValid(array $data): bool
153
    {
154
        $this->data = $data;
155
        $this->flushErrors();
156
157
        if (empty($this->rules)) {
158
            return true;
159
        }
160
161
        foreach ($this->rules as $field => $_) {
162
            if (!array_key_exists($field, $data)) {
163
                $data[$field] = '';
164
            }
165
        }
166
167
        foreach ($data as $field => $value) {
168
            if (!isset($this->rules[$field])) {
169
                continue;
170
            }
171
172
            foreach ($this->rules[$field] as $rule => $param) {
173
                if (method_exists($this, $rule) && is_callable([$this, $rule])) {
174
                    $this->$rule($field, $value, $param);
175
                } elseif (isset($this->customValidations[$rule])) {
176
                    $this->executeCustomRule($rule, $field, $value, $param);
177
                }
178
            }
179
        }
180
181
        return empty($this->errors);
182
    }
183
184
    /**
185
     * Add a custom validation rule
186
     * @param string $rule Rule name
187
     * @param Closure $function Callback function with signature function($value, $param): bool
188
     * @return void
189
     */
190
    public function addValidation(string $rule, Closure $function): void
191
    {
192
        if (empty($rule) || !is_callable($function)) {
193
            return;
194
        }
195
196
        $this->customValidations[$rule] = $function;
197
    }
198
199
    /**
200
     * Gets validation errors with translations
201
     * @return array
202
     */
203
    public function getErrors(): array
204
    {
205
        if (empty($this->errors)) {
206
            return [];
207
        }
208
209
        $messages = [];
210
211
        foreach ($this->errors as $field => $fieldErrors) {
212
            foreach ($fieldErrors as $rule => $param) {
213
                $translationParams = [t('common.' . $field)];
214
                if ($param !== null && $param !== '') {
215
                    $translationParams[] = $param;
216
                }
217
218
                $messages[$field][] = t("validation.$rule", $translationParams);
219
            }
220
        }
221
222
        return $messages;
223
    }
224
225
    /**
226
     * Adds an error for a field and rule
227
     * @param string $field
228
     * @param string $rule
229
     * @param mixed|null $param
230
     * @return void
231
     */
232
    protected function addError(string $field, string $rule, $param = null): void
233
    {
234
        if (!isset($this->errors[$field])) {
235
            $this->errors[$field] = [];
236
        }
237
238
        $this->errors[$field][$rule] = $param;
239
    }
240
241
    /**
242
     * Flush all errors
243
     * @return void
244
     */
245
    public function flushErrors(): void
246
    {
247
        $this->errors = [];
248
    }
249
250
    /**
251
     * Executes user defined rule
252
     * @param string $rule
253
     * @param string $field
254
     * @param $value
255
     * @param $param
256
     */
257
    protected function executeCustomRule(string $rule, string $field, $value, $param)
258
    {
259
        if ($value === '' || $value === null) {
260
            return;
261
        }
262
263
        $function = $this->customValidations[$rule];
264
265
        if (!$function($value, $param)) {
266
            $this->addError($field, $rule, $param);
267
        }
268
    }
269
}
270