General   C
last analyzed

Complexity

Total Complexity 54

Size/Duplication

Total Lines 300
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 86
c 3
b 0
f 0
dl 0
loc 300
rs 6.4799
wmc 54

14 Methods

Rating   Name   Duplication   Size   Complexity  
A required() 0 4 3
A email() 0 5 3
A captcha() 0 8 3
B creditCard() 0 35 8
A iban() 0 21 4
A starts() 0 5 3
B date() 0 15 7
A streetAddress() 0 11 5
A unique() 0 9 3
A same() 0 5 3
A phoneNumber() 0 7 3
A name() 0 5 3
A regex() 0 5 3
A jsonString() 0 7 3

How to fix   Complexity   

Complex Class

Complex classes like General often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use General, and based on these observations, apply Extract Interface, too.

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.7
13
 */
14
15
namespace Quantum\Libraries\Validation\Rules;
16
17
use Quantum\Libraries\Database\Exceptions\DatabaseException;
18
use Quantum\Libraries\Captcha\Factories\CaptchaFactory;
19
use Quantum\Config\Exceptions\ConfigException;
20
use Quantum\Model\Exceptions\ModelException;
21
use Quantum\App\Exceptions\BaseException;
22
use Quantum\Model\Factories\ModelFactory;
23
use Quantum\Di\Exceptions\DiException;
24
use ReflectionException;
25
26
/**
27
 * Trait General
28
 * @package Quantum\Libraries\Validation
29
 */
30
trait General
31
{
32
33
    /**
34
     * Adds validation Error
35
     * @param string $field
36
     * @param string $rule
37
     * @param mixed|null $param
38
     */
39
    abstract protected function addError(string $field, string $rule, $param = null);
40
41
    /**
42
     * Checks Field Required
43
     * @param string $field
44
     * @param string $value
45
     * @param null|mixed $param
46
     */
47
    protected function required(string $field, string $value, $param = null)
48
    {
49
        if ($value == false || empty($value)) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $value of type string to the boolean false. If you are specifically checking for an empty string, consider using the more explicit === '' instead.
Loading history...
50
            $this->addError($field, 'required', $param);
51
        }
52
    }
53
54
    /**
55
     * Checks Email
56
     * @param string $field
57
     * @param string $value
58
     * @param null|mixed $param
59
     */
60
    protected function email(string $field, string $value, $param = null)
61
    {
62
        if (!empty($value)) {
63
            if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
64
                $this->addError($field, 'email', $param);
65
            }
66
        }
67
    }
68
69
    /**
70
     * Check Captcha
71
     * @param string $field
72
     * @param string $value
73
     * @param $param
74
     * @return void
75
     * @throws ConfigException
76
     * @throws DiException
77
     * @throws ReflectionException
78
     * @throws BaseException
79
     */
80
    protected function captcha(string $field, string $value, $param = null)
81
    {
82
        if (!empty($value)) {
83
            $captcha = CaptchaFactory::get();
84
85
            if (!$captcha->verify($value)){
86
                $errorCode = $captcha->getErrorMessage();
87
                $this->addError($field, 'captcha.'.$errorCode, $param);
88
            }
89
        }
90
    }
91
92
    /**
93
     * Checks for a valid credit card number
94
     * @param string $field
95
     * @param string $value
96
     * @param null|mixed $param
97
     */
98
    protected function creditCard(string $field, string $value, $param = null)
99
    {
100
        if (!empty($value)) {
101
            $number = preg_replace('/\D/', '', $value);
102
103
            if (function_exists('mb_strlen')) {
104
                $number_length = mb_strlen($number);
105
            } else {
106
                $number_length = strlen($number);
107
            }
108
109
            if ($number_length == 0) {
110
                $this->addError($field, 'creditCard', $param);
111
            }
112
113
            $parity = $number_length % 2;
114
115
            $total = 0;
116
117
            for ($i = 0; $i < $number_length; ++$i) {
118
                $digit = $number[$i];
119
120
                if ($i % 2 == $parity) {
121
                    $digit *= 2;
122
123
                    if ($digit > 9) {
124
                        $digit -= 9;
125
                    }
126
                }
127
128
                $total += $digit;
129
            }
130
131
            if ($total % 10 != 0) {
132
                $this->addError($field, 'creditCard', $param);
133
            }
134
        }
135
    }
136
137
    /**
138
     * Checks for a valid IBAN
139
     * @param string $field
140
     * @param string $value
141
     * @param null|mixed $param
142
     */
143
    protected function iban(string $field, string $value, $param = null)
144
    {
145
        if (!empty($value)) {
146
            static $character = [
147
                'A' => 10, 'C' => 12, 'D' => 13, 'E' => 14, 'F' => 15, 'G' => 16,
148
                'H' => 17, 'I' => 18, 'J' => 19, 'K' => 20, 'L' => 21, 'M' => 22,
149
                'N' => 23, 'O' => 24, 'P' => 25, 'Q' => 26, 'R' => 27, 'S' => 28,
150
                'T' => 29, 'U' => 30, 'V' => 31, 'W' => 32, 'X' => 33, 'Y' => 34,
151
                'Z' => 35, 'B' => 11,
152
            ];
153
154
            if (!preg_match("/\A[A-Z]{2}\d{2} ?[A-Z\d]{4}( ?\d{4}){1,} ?\d{1,4}\z/", $value)) {
155
                $this->addError($field, 'iban', $param);
156
            }
157
158
            $iban = str_replace(' ', '', $value);
159
            $iban = substr($iban, 4) . substr($iban, 0, 4);
160
            $iban = strtr($iban, $character);
161
162
            if (bcmod($iban, 97) != 1) {
163
                $this->addError($field, 'iban', $param);
164
            }
165
        }
166
    }
167
168
    /**
169
     * Checks for a valid format human name
170
     * @param string $field
171
     * @param string $value
172
     * @param null|mixed $param
173
     */
174
    protected function name(string $field, string $value, $param = null)
175
    {
176
        if (!empty($value)) {
177
            if (preg_match("/^([a-z \p{L} '-])+$/i", $value) === 0) {
178
                $this->addError($field, 'name', $param);
179
            }
180
        }
181
    }
182
183
    /**
184
     * Checks that the provided string is a likely street address.
185
     * @param string $field
186
     * @param string $value
187
     * @param null|mixed $param
188
     */
189
    protected function streetAddress(string $field, string $value, $param = null)
190
    {
191
        if (!empty($value)) {
192
            $hasLetter = preg_match('/[a-zA-Z]/', $value);
193
            $hasDigit = preg_match('/\d/', $value);
194
            $hasSpace = preg_match('/\s/', $value);
195
196
            $passes = $hasLetter && $hasDigit && $hasSpace;
197
198
            if (!$passes) {
199
                $this->addError($field, 'streetAddress', $param);
200
            }
201
        }
202
    }
203
204
    /**
205
     * Validates the phone number // 555-555-5555 , 5555425555, 555 555 5555, 1(519) 555-4444, 1 (519) 555-4422, +1-555-555-5555
206
     * @param string $field
207
     * @param string $value
208
     * @param null|mixed $param
209
     */
210
    protected function phoneNumber(string $field, string $value, $param = null)
211
    {
212
        if (!empty($value)) {
213
            $regex = '/^(\+*\d[\s-]?)?[\(\[\s-]{0,2}?\d{3}[\)\]\s-]{0,2}?\d{3}[\s-]?\d{4}$/i';
214
215
            if (!preg_match($regex, $value)) {
216
                $this->addError($field, 'phoneNumber', $param);
217
            }
218
        }
219
    }
220
221
    /**
222
     * Determines if the provided input is a valid date
223
     * @param string $field
224
     * @param string $value
225
     * @param string|null $param format
226
     */
227
    protected function date(string $field, string $value, string $param = null)
228
    {
229
        if (!empty($value)) {
230
            if (!$param) {
231
                $cdate1 = date('Y-m-d', strtotime($value));
232
                $cdate2 = date('Y-m-d H:i:s', strtotime($value));
233
234
                if ($cdate1 != $value && $cdate2 != $value) {
235
                    $this->addError($field, 'date', $param);
236
                }
237
            } else {
238
                $date = \DateTime::createFromFormat($param, $value);
239
240
                if ($date === false || $value != date($param, $date->getTimestamp())) {
241
                    $this->addError($field, 'date', $param);
242
                }
243
            }
244
        }
245
    }
246
247
    /**
248
     * Ensures the value starts with a certain character / set of character
249
     * @param string $field
250
     * @param string $value
251
     * @param string $param
252
     */
253
    protected function starts(string $field, string $value, string $param)
254
    {
255
        if (!empty($value)) {
256
            if (strpos($value, $param) !== 0) {
257
                $this->addError($field, 'starts', $param);
258
            }
259
        }
260
    }
261
262
    /**
263
     * Custom regex validator
264
     * @param string $field
265
     * @param string $value
266
     * @param string $param
267
     */
268
    protected function regex(string $field, string $value, string $param)
269
    {
270
        if (!empty($value)) {
271
            if (!preg_match($param, $value)) {
272
                $this->addError($field, 'regex', $param);
273
            }
274
        }
275
    }
276
277
    /**
278
     * Validates JSON string
279
     * @param string $field
280
     * @param string $value
281
     * @param null|mixed $param
282
     */
283
    protected function jsonString(string $field, string $value, $param = null)
284
    {
285
        if (!empty($value)) {
286
            $value = htmlspecialchars_decode($value, ENT_QUOTES);
287
288
            if (!is_object(json_decode($value))) {
289
                $this->addError($field, 'jsonString', $param);
290
            }
291
        }
292
    }
293
294
    /**
295
     * Validates same value for both fields
296
     * @param string $field
297
     * @param string $value
298
     * @param null|mixed $param
299
     */
300
    protected function same(string $field, string $value, $param = null)
301
    {
302
        if (!empty($value)) {
303
            if ($value != $this->data[$param]) {
304
                $this->addError($field, 'same', $param);
305
            }
306
        }
307
    }
308
309
    /**
310
     *  Validates uniqueness
311
     * @param string $field
312
     * @param $value
313
     * @param string $param
314
     * @return void
315
     * @throws ConfigException
316
     * @throws DiException
317
     * @throws ReflectionException
318
     * @throws DatabaseException
319
     * @throws ModelException
320
     */
321
    protected function unique(string $field, $value, string $param)
322
    {
323
        if (!empty($value)) {
324
            $model = ModelFactory::get(ucfirst($param));
325
326
            $row = $model->findOneBy($field, $value);
327
328
            if ($row->count()) {
329
                $this->addError($field, 'unique', null);
330
            }
331
        }
332
    }
333
}