Passed
Push — master ( 23a0db...57c0d1 )
by Runner
02:35
created

Validator   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 214
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 64
dl 0
loc 214
ccs 72
cts 72
cp 1
rs 9.84
c 0
b 0
f 0
wmc 32

12 Methods

Rating   Name   Duplication   Size   Complexity  
A fails() 0 3 1
A data() 0 3 1
A messages() 0 3 1
A runValidateRule() 0 5 2
A __construct() 0 5 1
A hasField() 0 17 4
A formatRuleName() 0 9 1
A __call() 0 9 2
A addExtension() 0 9 3
B validate() 0 20 8
A parseRules() 0 9 6
A getField() 0 10 2
1
<?php
2
/**
3
 * @author: RunnerLee
4
 * @email: [email protected]
5
 * @time: 17-2-20 15:22
6
 */
7
8
namespace Runner\Validator;
9
10
use BadMethodCallException;
11
use Runner\Validator\Concerns\MessagesAttributes;
12
use Runner\Validator\Concerns\ValidatesAttributes;
13
14
/**
15
 * Class Validator.
16
 */
17
class Validator
18
{
19
    use ValidatesAttributes, MessagesAttributes;
20
21
    /**
22
     * @var array
23
     */
24
    protected $data = [];
25
26
    /**
27
     * @var array
28
     */
29
    protected $ruleGroups = [];
30
31
    /**
32
     * @var array
33
     */
34
    protected $messages = [];
35
36
    /**
37
     * @var array
38
     */
39
    protected static $forceRules = ['Required', 'RequiredIf', 'RequiredWith', 'RequiredUnless', 'RequiredWithout'];
40
41
    /**
42
     * @var array
43
     */
44
    protected static $extensions = [];
45
46
    /**
47
     * @var array
48
     */
49
    protected static $extensionTemplates = [];
50
51
    /**
52
     * Validator constructor.
53
     *
54
     * @param array  $data
55
     * @param array  $rules
56
     * @param array  $customMessages
57
     * @param string $file
58
     */
59 4
    public function __construct(array $data, array $rules, array $customMessages = [], $file = __DIR__.'/messages/en.php')
60
    {
61 4
        $this->data = $data;
62 4
        $this->parseRules($rules);
63 4
        $this->loadMessageTemplate($file, $customMessages);
64 4
    }
65
66
    /**
67
     * @param $name
68
     * @param $callback
69
     * @param bool   $isForce
70
     * @param string $message
71
     */
72 3
    public static function addExtension($name, $callback, $isForce = false, $message = null)
73
    {
74 3
        $name = self::formatRuleName($name);
75
76 3
        self::$extensions[$name] = $callback;
77
78 3
        $isForce && self::$forceRules[] = $name;
79
80 3
        !empty($message) && (static::$extensionTemplates[$name] = $message);
81 3
    }
82
83
    /**
84
     * @return bool
85
     */
86 4
    public function validate()
87
    {
88 4
        foreach ($this->ruleGroups as $field => $rules) {
89 4
            if ($this->hasField($field)) {
90 4
                $value = $this->getField($field);
91 4
                foreach ($rules as $rule => $parameters) {
92 4
                    if (!$this->runValidateRule($rule, $field, $value, $parameters)) {
93 4
                        $this->messages[$field][$rule] = $this->buildMessage($rule, $field, $parameters);
94
                    }
95
                }
96 1
            } elseif ($forceRules = array_intersect(self::$forceRules, array_keys($rules))) {
97 1
                foreach ($forceRules as $rule) {
98 1
                    if (!$this->runValidateRule($rule, $field, null, $rules[$rule])) {
99 4
                        $this->messages[$field][$rule] = $this->buildMessage($rule, $field, $rules[$rule]);
100
                    }
101
                }
102
            }
103
        }
104
105 4
        return 0 === count($this->messages);
106
    }
107
108
    /**
109
     * @return array
110
     */
111 1
    public function fails()
112
    {
113 1
        return array_keys($this->messages);
114
    }
115
116
    /**
117
     * @return array
118
     */
119 2
    public function messages()
120
    {
121 2
        return $this->messages;
122
    }
123
124
    /**
125
     * @return array
126
     */
127 1
    public function data()
128
    {
129 1
        return $this->data;
130
    }
131
132
    /**
133
     * @param array $ruleGroups
134
     */
135 4
    protected function parseRules(array $ruleGroups)
136
    {
137 4
        $map = [];
138 4
        foreach ($ruleGroups as $field => $rules) {
139 4
            foreach (explode('|', $rules) as $rule) {
140 4
                list($rule, $parameters) = explode(':', (false === strpos($rule, ':') ? ($rule.':') : $rule), 2);
141 4
                !isset($map[$rule]) && $map[$rule] = self::formatRuleName($rule);
142 4
                $rule = $map[$rule];
143 4
                $this->ruleGroups[$field][$rule] = ('' === $parameters ? [] : explode(',', $parameters));
144
            }
145
        }
146 4
    }
147
148
    /**
149
     * @param $name
150
     *
151
     * @return string
152
     */
153 4
    protected static function formatRuleName($name)
154
    {
155 4
        return implode(
156 4
            '',
157 4
            array_map(
158 4
                function ($value) {
159 4
                    return ucfirst($value);
160 4
                },
161 4
                explode('_', $name)
162
            )
163
        );
164
    }
165
166
    /**
167
     * @param string $field
168
     *
169
     * @return bool
170
     */
171 4
    protected function hasField($field)
172
    {
173 4
        $field = explode('.', $field);
174 4
        $item = array_shift($field);
175 4
        if (!array_key_exists($item, $this->data)) {
176 1
            return false;
177
        }
178 4
        $value = $this->data[$item];
179
180 4
        foreach ($field as $item) {
181 1
            if (!array_key_exists($item, $value)) {
182 1
                return false;
183
            }
184 1
            $value = $value[$item];
185
        }
186
187 4
        return true;
188
    }
189
190
    /**
191
     * @param string $field
192
     *
193
     * @return mixed
194
     */
195 4
    protected function getField($field)
196
    {
197 4
        $field = explode('.', $field);
198 4
        $item = array_shift($field);
199 4
        $value = $this->data[$item];
200 4
        foreach ($field as $item) {
201 1
            $value = $value[$item];
202
        }
203
204 4
        return $value;
205
    }
206
207
    /**
208
     * @param $field
209
     * @param $value
210
     * @param $rule
211
     * @param array $parameters
212
     *
213
     * @return bool
214
     */
215 4
    protected function runValidateRule($rule, $field, $value, array $parameters = [])
216
    {
217 4
        $callback = array_key_exists($rule, self::$extensions) ? self::$extensions[$rule] : [$this, "validate{$rule}"];
218
219 4
        return (bool) call_user_func($callback, $field, $value, $parameters, $this);
220
    }
221
222 1
    public function __call($method, $arguments)
223
    {
224 1
        $rule = self::formatRuleName(substr($method, 8));
225
226 1
        if (!isset(self::$extensions[$rule])) {
227 1
            throw new BadMethodCallException(sprintf('Method %s::%s does not exists', static::class, $method));
228
        }
229
230 1
        return $this->runValidateRule($rule, ...$arguments);
0 ignored issues
show
Bug introduced by
The call to Runner\Validator\Validator::runValidateRule() has too few arguments starting with value. ( Ignorable by Annotation )

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

230
        return $this->/** @scrutinizer ignore-call */ runValidateRule($rule, ...$arguments);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
231
    }
232
}
233