Validator   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 202
Duplicated Lines 5.94 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 4
Bugs 1 Features 1
Metric Value
c 4
b 1
f 1
dl 12
loc 202
wmc 21
lcom 1
cbo 1
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 15 1
A validate() 0 7 1
B make() 0 55 8
A prepareData() 0 16 4
C prepareRules() 12 32 7

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/**
4
 * @author: Abdul Qureshi. <[email protected]>
5
 * 
6
 * This file has been modified from the original source.
7
 * See original here:
8
 *
9
 * @link: https://github.com/progsmile/request-validator
10
 */
11
namespace TheSupportGroup\Common\Validator;
12
13
use TheSupportGroup\Common\ValidationInterop\ValidationProviderInterface;
14
use TheSupportGroup\Common\Validator\Contracts\Helpers\RulesFactoryInterface;
15
use TheSupportGroup\Common\Validator\Contracts\Helpers\ValidationResultProcessorInterface;
16
use TheSupportGroup\Common\Validator\Rules\BaseRule;
17
18
final class Validator
19
{
20
    /**
21
     * @var ValidationResultProcessor
22
     */
23
    private static $ValidationResultProcessor = null;
0 ignored issues
show
Unused Code introduced by
The property $ValidationResultProcessor is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
24
25
    /**
26
     * Use to separate rules.
27
     *
28
     * firstname: max(255)|min(8)
29
     */
30
    private static $ruleSeparator = '|';
31
32
    /**
33
     * Use to separate field(s) and rule(s).
34
     *
35
     * firstname: max(255)
36
     */
37
    private static $ruleParamSeparator = ':';
38
39
    /**
40
     * Used to separate multiple field definitions for the same rules.
41
     *
42
     * firstname,lastname: max(255)
43
     */
44
    private static $multiFieldSeparator = ',';
45
46
    /**
47
     * Provide predefined config.
48
     */
49
    private static $config = [];
50
51
    /**
52
     * Rules factory.
53
     */
54
    private $rulesFactory;
55
56
    /**
57
     * @param ValidationProviderInterface $validationProvider
58
     * @param ValidationResultProcessorInterface $validationResultProcessor
59
     * @param RulesFactoryInterface $rulesFactory
60
     * @param array $inputData
61
     * @param array $rules
62
     * @param array $errorMessages
63
     */
64
    public function __construct(
65
        ValidationProviderInterface $validationProvider,
66
        ValidationResultProcessorInterface $validationResultProcessor,
67
        RulesFactoryInterface $rulesFactory,
68
        array $inputData,
69
        array $rules = [],
70
        array $errorMessages = []
71
    ) {
72
        $this->rules = $rules;
0 ignored issues
show
Bug introduced by
The property rules does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
73
        $this->inputData = $inputData;
0 ignored issues
show
Bug introduced by
The property inputData does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
74
        $this->validationProvider = $validationProvider;
0 ignored issues
show
Bug introduced by
The property validationProvider does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
75
        $this->validationResultProcessor = $validationResultProcessor;
0 ignored issues
show
Bug introduced by
The property validationResultProcessor does not seem to exist. Did you mean ValidationResultProcessor?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
76
        $this->validationResultProcessor->fieldsErrorBag->setUserMessages($errorMessages);
0 ignored issues
show
Bug introduced by
The property validationResultProcessor does not seem to exist. Did you mean ValidationResultProcessor?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
Bug introduced by
Accessing fieldsErrorBag on the interface TheSupportGroup\Common\V...esultProcessorInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
77
        $this->rulesFactory = $rulesFactory;
78
    }
79
80
    /**
81
     * Validate input data against the rules provided.
82
     */
83
    public function validate()
84
    {
85
        return $this->make(
86
            $this->inputData,
87
            $this->rules
88
        );
89
    }
90
91
    /**
92
     * Make validation.
93
     *
94
     * @param array $data user request data
95
     * @param array $rules validation rules
96
     *
97
     * @return ValidatorRule
98
     */
99
    private function make(
100
        array $data,
101
        array $rules
102
    ) {
103
        $data = $this->prepareData($data);
104
        $rules = $this->prepareRules($rules);
105
106
        foreach ($rules as $fieldName => $fieldRules) {
107
            $fieldName = trim($fieldName);
108
            $fieldRules = trim($fieldRules);
109
110
            if (!$fieldRules) {
111
                //no rules
112
                throw new Excpetion('No rules provided.');
113
            }
114
115
            $groupedRules = explode(self::$ruleSeparator, $fieldRules);
116
117
            foreach ($groupedRules as $concreteRule) {
118
                $ruleNameParam = explode(self::$ruleParamSeparator, $concreteRule);
119
                $ruleName = $ruleNameParam[0];
120
121
                // For date/time validators.
122
                if (count($ruleNameParam) >= 2) {
123
                    $ruleValue = implode(self::$ruleParamSeparator, array_slice(
124
                        $ruleNameParam,
125
                        1
126
                    ));
127
                    //for other params
128
                } else {
129
                    $ruleValue = isset($ruleNameParam[1]) ? $ruleNameParam[1] : '';
130
                }
131
132
                self::$config[BaseRule::CONFIG_DATA] = $data;
133
                self::$config[BaseRule::CONFIG_FIELD_RULES] = $fieldRules;
134
135
                $ruleInstance = $this->rulesFactory->createRule(
136
                    $ruleName,
137
                    self::$config,
138
                    [
139
                        $fieldName,                                        // The field name
140
                        isset($data[$fieldName]) ? $data[$fieldName] : '', // The provided value
141
                        $ruleValue,                                        // The rule's value
142
                    ],
143
                    $this->validationProvider
144
                );
145
146
                if (! $ruleInstance->isValid()) {
147
                    $this->validationResultProcessor->chooseErrorMessage($ruleInstance);
0 ignored issues
show
Bug introduced by
The property validationResultProcessor does not seem to exist. Did you mean ValidationResultProcessor?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
148
                }
149
            }
150
        }
151
152
        return $this->validationResultProcessor;
0 ignored issues
show
Bug introduced by
The property validationResultProcessor does not seem to exist. Did you mean ValidationResultProcessor?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
153
    }
154
155
    /**
156
     * Prepare user data for validator.
157
     *
158
     * @param array $data
159
     *
160
     * @return array
161
     */
162
    private function prepareData(array $data)
163
    {
164
        $newData = [];
165
166
        foreach ($data as $paramName => $paramValue) {
167
            if (is_array($paramValue)) {
168
                foreach ($paramValue as $newKey => $newValue) {
169
                    $newData[trim($paramName).'['.trim($newKey).']'] = trim($newValue);
170
                }
171
            } else {
172
                $newData[trim($paramName)] = trim($paramValue);
173
            }
174
        }
175
176
        return $newData;
177
    }
178
179
    /**
180
     * Merges all field's rules into one
181
     * if you have elegant implementation, you are welcome.
182
     *
183
     * @param array $rules
184
     *
185
     * @return array
186
     */
187
    private function prepareRules(array $rules)
188
    {
189
        $mergedRules = [];
190
191
        foreach ($rules as $ruleFields => $ruleConditions) {
192
            if (strpos($ruleFields, self::$multiFieldSeparator) !== false) {
193
                foreach (explode(self::$multiFieldSeparator, $ruleFields) as $fieldName) {
194
                    $fieldName = trim($fieldName);
195 View Code Duplication
                    if (!isset($mergedRules[$fieldName])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
196
                        $mergedRules[$fieldName] = $ruleConditions;
197
                    } else {
198
                        $mergedRules[$fieldName] .= self::$ruleSeparator.$ruleConditions;
199
                    }
200
                }
201 View Code Duplication
            } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
202
                if (!isset($mergedRules[$ruleFields])) {
203
                    $mergedRules[$ruleFields] = $ruleConditions;
204
                } else {
205
                    $mergedRules[$ruleFields] .= self::$ruleSeparator.$ruleConditions;
206
                }
207
            }
208
        }
209
210
        $finalRules = [];
211
212
        // Remove duplicated rules.
213
        foreach ($mergedRules as $newRule => $rule) {
214
            $finalRules[$newRule] = implode(self::$ruleSeparator, array_unique(explode(self::$ruleSeparator, $rule)));
215
        }
216
217
        return $finalRules;
218
    }
219
}
220