Passed
Pull Request — master (#27)
by Jitendra
01:52
created

Validation::cancelOnFail()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 3
nop 1
1
<?php
2
3
namespace PhalconExt\Validation;
4
5
use Phalcon\Validation as BaseValidation;
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use Phalcon\Validation\Validator;
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use Phalcon\Validation\ValidatorInterface;
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\ValidatorInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use PhalconExt\Validators;
0 ignored issues
show
Bug introduced by
The type PhalconExt\Validators was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
10
/**
11
 * Phalcon Validation with batteries.
12
 *
13
 * @author  Jitendra Adhikari <[email protected]>
14
 * @license MIT
15
 *
16
 * @link    https://github.com/adhocore/phalcon-ext
17
 */
18
class Validation extends BaseValidation
19
{
20
    /** @var array The alias of available validators */
21
    protected $validators = [
22
        'alnum'        => Validator\Alnum::class,
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\Alnum was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
        'alpha'        => Validator\Alpha::class,
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\Alpha was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
        'between'      => Validator\Between::class,
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\Between was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
25
        'confirmation' => Validator\Confirmation::class,
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\Confirmation was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
        'creditcard'   => Validator\CreditCard::class,
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\CreditCard was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
27
        'date'         => Validator\Date::class,
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\Date was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
28
        'digit'        => Validator\Digit::class,
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\Digit was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
29
        'email'        => Validator\Email::class,
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\Email was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
30
        'not_in'       => Validator\ExclusionIn::class,
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\ExclusionIn was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
31
        'file'         => Validator\File::class,
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\File was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
32
        'identical'    => Validator\Identical::class,
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\Identical was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
33
        'in'           => Validator\InclusionIn::class,
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\InclusionIn was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
34
        'numeric'      => Validator\Numericality::class,
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\Numericality was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
35
        'required'     => Validator\PresenceOf::class,
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\PresenceOf was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
36
        'regex'        => Validator\Regex::class,
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\Regex was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
37
        'length'       => Validator\StringLength::class,
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\StringLength was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
38
        'unique'       => Validator\Uniqueness::class,
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\Uniqueness was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
39
        'url'          => Validator\Url::class,
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\Url was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
40
        'exist'        => Existence::class,
41
    ];
42
43
    /** @var array The custom validation callbacks */
44
    protected $callbacks = [];
45
46
    /** @var ValidatorInterface The currently validating Validator. */
47
    protected $validator;
48
49
    /**
50
     * Register a custom validation rule.
51
     *
52
     * @param string             $ruleName
53
     * @param callable|Validator $handler
54
     * @param string             $message  Message to use when validation fails
55
     *
56
     * @return self
57
     */
58
    public function register(string $ruleName, $handler, string $message = ''): self
59
    {
60
        if (isset($this->validators[$ruleName])) {
61
            return $this;
62
        }
63
64
        if ($message) {
65
            $this->_defaultMessages += [$ruleName => $message];
66
        }
67
68
        $this->validators[$ruleName] = $this->getHandler($ruleName, $handler);
69
70
        return $this;
71
    }
72
73
    /**
74
     * Get validation handler description].
75
     *
76
     * @param string $ruleName
77
     * @param mixed  $handler
78
     *
79
     * @return string
80
     */
81
    protected function getHandler(string $ruleName, $handler)
82
    {
83
        if ($handler instanceof \Closure) {
84
            $handler = \Closure::bind($handler, $this);
85
        }
86
87
        if (\is_callable($handler)) {
88
            $this->callbacks[$ruleName] = $handler;
89
            $handler                    = Validator\Callback::class;
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\Callback was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
90
        }
91
92
        if (!\is_subclass_of($handler, Validator::class)) {
93
            throw new \InvalidArgumentException('Unsupported validation rule: ' . $ruleName);
94
        }
95
96
        return $handler;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $handler also could return the type Closure which is incompatible with the documented return type string.
Loading history...
97
    }
98
99
    /**
100
     * Registers multiple custom validation rules at once!
101
     *
102
     * @param array $ruleHandlers ['rule1' => <handler>, ...]
103
     * @param array $messages     ['rule1' => 'message', ...]
104
     *
105
     * @return self
106
     */
107
    public function registerRules(array $ruleHandlers, array $messages = []): self
108
    {
109
        foreach ($ruleHandlers as $ruleName => $handler) {
110
            $this->register($ruleName, $handler, $messages[$ruleName] ?? '');
111
        }
112
113
        return $this;
114
    }
115
116
    /**
117
     * Check if the validation passes.
118
     *
119
     * @return bool
120
     */
121
    public function pass(): bool
122
    {
123
        return \count($this->_messages) === 0;
124
    }
125
126
    /**
127
     * Check if the validation fails.
128
     *
129
     * @return bool
130
     */
131
    public function fail(): bool
132
    {
133
        return !$this->pass();
134
    }
135
136
    /**
137
     * Get the error messages.
138
     *
139
     * @return array
140
     */
141
    public function getErrorMessages(): array
142
    {
143
        $messages = [];
144
145
        foreach ($this->_messages as $message) {
146
            $messages[] = [
147
                'code'    => $message->getCode(),
148
                'message' => $message->getMessage(),
149
                'field'   => $message->getField(),
150
            ];
151
        }
152
153
        return $messages;
154
    }
155
156
    /**
157
     * self validation with given ruleSet against given arbitrary dataSet.
158
     *
159
     * @param array        $ruleSet
160
     * @param array|object $dataSet
161
     *
162
     * @return self
163
     */
164
    public function run(array $ruleSet, $dataSet): self
165
    {
166
        $this->_messages = $this->_validators = [];
0 ignored issues
show
Bug Best Practice introduced by
The property _validators does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
Bug Best Practice introduced by
The property _messages does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
167
168
        // See if it is arrayable!
169
        if (\is_object($dataSet)) {
170
            $dataSet = $this->prepareDate($dataSet);
171
        }
172
173
        // OK, must be entity!
174
        if (\is_object($dataSet)) {
175
            $this->_entity = $dataSet;
0 ignored issues
show
Bug Best Practice introduced by
The property _entity does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
176
        } else {
177
            $this->_data = $dataSet;
0 ignored issues
show
Bug Best Practice introduced by
The property _data does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
178
        }
179
180
        $this->addRules($ruleSet)->validate();
181
182
        return $this;
183
    }
184
185
    /**
186
     * Prepare data &/or entity.
187
     *
188
     * @param array|object $dataSet
189
     *
190
     * @return array|object
191
     */
192
    protected function prepareDate($dataSet)
193
    {
194
        if ($dataSet instanceof \stdClass) {
195
            return (array) $dataSet;
196
        }
197
198
        if (\method_exists($dataSet, 'toArray')) {
199
            return $dataSet->toArray();
200
        }
201
202
        if (\method_exists($dataSet, 'getData')) {
203
            return $dataSet->getData();
204
        }
205
206
        return $dataSet;
207
    }
208
209
    /**
210
     * Run the validation rules on data set.
211
     *
212
     * @param array $ruleSet
213
     *
214
     * @return self
215
     */
216
    protected function addRules(array $ruleSet): self
217
    {
218
        foreach ($ruleSet as $attribute => $rules) {
219
            $rules = $this->normalizeRules($rules);
220
221
            // Only validate if attribute exists in dataSet when so configured.
222
            if (isset($rules['if_exist']) && null === $this->getValue($attribute)) {
223
                continue;
224
            }
225
226
            $rules = $this->cancelOnFail($rules);
227
228
            unset($rules['if_exist']);
229
            $this->attributeRules($attribute, $rules);
230
        }
231
232
        return $this;
233
    }
234
235
    /**
236
     * Make the validator cancel on fail i.e bail on first ever invalid field.
237
     *
238
     * @param array $rules
239
     *
240
     * @return array
241
     */
242
    protected function cancelOnFail(array $rules): array
243
    {
244
        if (!isset($rules['abort'])) {
245
            return $rules;
246
        }
247
248
        unset($rules['abort']);
249
        foreach ($rules as &$rule) {
250
            $rule = (array) $rule + ['cancelOnFail' => true];
251
        }
252
253
        return $rules;
254
    }
255
256
    /**
257
     * Normalize rules if needed.
258
     *
259
     * @param mixed $rules
260
     *
261
     * @return array
262
     */
263
    protected function normalizeRules($rules): array
264
    {
265
        if (\is_string($rules)) {
266
            return $this->parseRules($rules);
267
        }
268
269
        if (!\is_array($rules)) {
270
            throw new \UnexpectedValueException('The rules should be an array or string');
271
        }
272
273
        return $rules;
274
    }
275
276
    /**
277
     * Parse string representation of the rules and make it array.
278
     *
279
     * Rule Format: `rule1:key1:value11,value12;key2:value22|rule2:key21:value21|rule3`
280
     *
281
     * @param string $rules Example: 'required|length:min:1;max:2;|in:domain:1,12,30'
282
     *
283
     * @return array
284
     */
285
    protected function parseRules(string $rules): array
286
    {
287
        $parsed = [];
288
289
        foreach (\explode('|', $rules) as $rule) {
290
            if (false === \strpos($rule, ':')) {
291
                $parsed[$rule] = [];
292
                continue;
293
            }
294
295
            list($name, $options) = \explode(':', $rule, 2);
296
            $parsed[$name]        = $this->parseOptions($options);
297
        }
298
299
        return $parsed;
300
    }
301
302
    /**
303
     * Parse rule options.
304
     *
305
     * @param string $options
306
     *
307
     * @return array
308
     */
309
    protected function parseOptions(string $options): array
310
    {
311
        $parsed = [];
312
313
        foreach (\explode(';', $options) as $parts) {
314
            list($key, $value) = \explode(':', $parts) + ['', ''];
315
            if (\strpos($value, ',')) {
316
                $value = \explode(',', $value);
317
            }
318
319
            $parsed[$key] = $value;
320
        }
321
322
        return $parsed;
323
    }
324
325
    /**
326
     * Add all the rules for given attribute to validators list.
327
     *
328
     * @param string $attribute
329
     * @param array  $rules
330
     *
331
     * @return void
332
     */
333
    protected function attributeRules(string $attribute, array $rules)
334
    {
335
        foreach ($rules as $rule => $options) {
336
            if (!isset($this->validators[$rule])) {
337
                throw new \InvalidArgumentException('Unknown validation rule: ' . $rule);
338
            }
339
340
            $validator = $this->validators[$rule];
341
            $options   = (array) $options + [
342
                'callback' => $this->callbacks[$rule] ?? null,
343
                'message'  => $this->_defaultMessages[$rule] ?? null,
344
                '__field'  => $attribute,
345
            ];
346
347
            $this->add($attribute, new $validator($options));
348
        }
349
    }
350
351
    /**
352
     * {@inheritdoc}
353
     */
354
    protected function preChecking($field, ValidatorInterface $validator): bool
355
    {
356
        $this->validator = $validator;
357
358
        return parent::preChecking($field, $validator);
359
    }
360
361
    /**
362
     * Get current value being validated.
363
     *
364
     * @return mixed
365
     */
366
    public function getCurrentValue()
367
    {
368
        return $this->getValue($this->validator->getOption('__field'));
369
    }
370
371
    /**
372
     * Delegate calls to current validator.
373
     *
374
     * @param string $method
375
     * @param mixed  $args
376
     *
377
     * @return mixed
378
     */
379
    public function __call($method, $args)
380
    {
381
        return $this->validator->$method(...$args);
382
    }
383
}
384