Completed
Push — master ( b21ed9...484a4b )
by Sebastian
02:44
created

Filter::filterOne()   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
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
ccs 0
cts 3
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Linna Filter
5
 *
6
 * @author Sebastian Rapetti <[email protected]>
7
 * @copyright (c) 2018, Sebastian Rapetti
8
 * @license http://opensource.org/licenses/MIT MIT License
9
 */
10
declare(strict_types = 1);
11
12
namespace Linna\Filter;
13
14
use ReflectionClass;
15
use ReflectionMethod;
16
17
/**
18
 * Filter.
19
 */
20
class Filter
21
{
22
    /**
23
     * @var array User data.
24
     */
25
    private $data = [];
26
27
    /**
28
     * @var array Sanitized data.
29
     */
30
    private $sanitizedData = [];
31
32
    /**
33
     * @var array Error messages.
34
     */
35
    private $messages = [];
36
37
    /**
38
     * @var int Occurred errors.
39
     */
40
    private $errors = 0;
41
42
    /**
43
     * @var array Filters working rules.
44
     */
45
    private $rules;
46
47
    /**
48
     * Class Constructor.
49
     */
50 50
    public function __construct()
51
    {
52 50
        $this->rules = RuleBuilder::build();
53 50
    }
54
55
    /**
56
     * Filter one element with given rules.
57
     *
58
     * @param mixed $data
59
     * @param string $rule
60
     */
61
    public function filterOne($data, string $rule): void
62
    {
63
        $this->data = ['data' => $data];
64
        $this->interpreteRules(['data '.$rule]);
65
    }
66
67
    /**
68
     * Filter an array of elementes with given rules.
69
     *
70
     * @param array $data
71
     * @param array $rules
72
     */
73 50
    public function filterMulti(array $data, array $rules): void
74
    {
75 50
        $this->data = $data;
76 50
        $this->interpreteRules($rules);
77 50
    }
78
79
    /**
80
     * Return occurred error number.
81
     *
82
     * @return int
83
     */
84 41
    public function getErrors(): int
85
    {
86 41
        return $this->errors;
87
    }
88
89
    /**
90
     * Return error messages.
91
     *
92
     * @return array
93
     */
94 1
    public function getMessages(): array
95
    {
96 1
        return $this->messages;
97
    }
98
99
    /**
100
     * Return passed data.
101
     *
102
     * @return array
103
     */
104 23
    public function getData(): array
105
    {
106 23
        return $this->data;
107
    }
108
109
    /**
110
     * Get parsed rules.
111
     */
112 50
    private function interpreteRules($rules): void
113
    {
114 50
        $parser = new Parser();
115
116 50
        foreach ($rules as $rule) {
117 50
            $this->ruleToField(
118 50
                $parser->parse(
119 50
                    Lexer::tokenize($rule),
120 50
                    $this->rules
121
                )
122
            );
123
        }
124 50
    }
125
126
    /**
127
     * Apply rules to a field.
128
     *
129
     * @param array $rules
130
     */
131 50
    private function ruleToField(array $rules): void
132
    {
133 50
        foreach ($rules as $rule) {
134 50
            $field = $rule[0];
135 50
            $filter = $rule[2]['class'];
136
137 50
            $class = 'Linna\Filter\Rules\\' . $filter;
138 50
            $refClass = new ReflectionClass($class);
139
140 50
            $instance = $refClass->newInstance();
141
142
            //check if value is isset in data
143 50
            if ($this->checkValue($field, $filter)) {
144 3
                continue;
145
            }
146
147 48
            if ($this->invokeValidate($refClass, $class, $field, $rule, $filter, $instance)) {
148 16
                continue;
149
            }
150
            
151 38
            $this->invokeSanitize($refClass, $field, $instance);
152
        }
153 50
    }
154
155
    /**
156
     * Check if a field exist in data.
157
     *
158
     * @param string $field
159
     * @param string $filter
160
     *
161
     * @return bool
162
     */
163 50
    private function checkValue(string &$field, string &$filter): bool
164
    {
165 50
        if (isset($this->data[$field])) {
166 48
            return false;
167
        }
168
        
169
        //sollevare una ottima eccezione!
170 3
        $this->errors++;
171 3
        $this->messages[$field][$filter] = "Form field '{$field}' missing.";
172
        
173 3
        return true;
174
    }
175
    
176
    /**
177
     * Invoke validate.
178
     *
179
     * @param ReflectionClass $refClass
180
     * @param string $class
181
     * @param string $field
182
     * @param array $rule
183
     * @param string $filter
184
     * @param mixed $instance
185
     *
186
     * @return bool
187
     */
188 48
    private function invokeValidate(
189
        ReflectionClass &$refClass,
190
        string &$class,
191
        string &$field,
192
        array &$rule,
193
        string &$filter,
194
        &$instance
195
    ) : bool {
196 48
        if ($refClass->hasMethod('validate')) {
197 39
            if ((new ReflectionMethod($class, 'validate'))->invokeArgs($instance, $this->getArguments($rule[2]['args_count'], $rule[3], $this->data[$field]))) {
198 16
                $this->errors++;
199 16
                $this->messages[$field][$filter] = ['expected' => $rule[3], 'received' => $this->data[$field]];
200
201 16
                return true;
202
            }
203
        }
204
        
205 38
        return false;
206
    }
207
    
208
    /**
209
     * Invoke Sanitize.
210
     *
211
     * @param ReflectionClass $refClass
212
     * @param string $field
213
     * @param mixed $instance
214
     */
215 38
    private function invokeSanitize(ReflectionClass &$refClass, string &$field, &$instance): void
216
    {
217 38
        if ($refClass->hasMethod('sanitize')) {
218 23
            $instance->sanitize($this->data[$field]);
219
        }
220 38
    }
221
    
222
    /**
223
     * Return arguments for validation.
224
     *
225
     * @param int $args
226
     * @param mixed $expected
227
     * @param mixed $received
228
     *
229
     * @return array
230
     */
231 39
    private function getArguments(int $args, $expected, $received): array
232
    {
233 39
        if ($args === 0) {
234 21
            return [$received];
235
        }
236
237 31
        if (is_array($expected)) {
238 5
            array_unshift($expected, $received);
239 5
            return $expected;
240
        }
241
242 26
        return [$received, $expected];
243
    }
244
}
245