We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.
Total Complexity | 44 |
Total Lines | 224 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like BackpackCustomRule 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 BackpackCustomRule, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
16 | abstract class BackpackCustomRule implements ValidationRule, DataAwareRule, ValidatorAwareRule |
||
17 | { |
||
18 | use Support\HasFiles; |
||
19 | |||
20 | /** |
||
21 | * @var \Illuminate\Contracts\Validation\Validator |
||
22 | */ |
||
23 | protected $validator; |
||
24 | |||
25 | protected array $data; |
||
26 | |||
27 | public array $fieldRules = []; |
||
28 | |||
29 | public bool $implicit = true; |
||
30 | |||
31 | public static function field(string|array|ValidationRule|Rule $rules = []): self |
||
32 | { |
||
33 | $instance = new static(); |
||
34 | $instance->fieldRules = self::getRulesAsArray($rules); |
||
35 | |||
36 | if($instance->validatesArrays()) { |
||
37 | if (! in_array('array', $instance->getFieldRules())) { |
||
38 | $instance->fieldRules[] = 'array'; |
||
39 | } |
||
40 | } |
||
41 | return $instance; |
||
42 | |||
43 | |||
44 | $instance = new static(); |
||
|
|||
45 | $instance->fieldRules = self::getRulesAsArray($rules); |
||
46 | |||
47 | if (! in_array('array', $instance->getFieldRules())) { |
||
48 | $instance->fieldRules[] = 'array'; |
||
49 | } |
||
50 | |||
51 | return $instance; |
||
52 | } |
||
53 | |||
54 | /** |
||
55 | * Run the validation rule. |
||
56 | * |
||
57 | * @param string $attribute |
||
58 | * @param mixed $value |
||
59 | * @param Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail |
||
60 | * @return void |
||
61 | */ |
||
62 | public function validate(string $attribute, mixed $value, Closure $fail): void |
||
63 | { |
||
64 | $value = $this->ensureValueIsValid($value); |
||
65 | |||
66 | if ($value === false) { |
||
67 | $fail('Invalid value for the attribute.')->translate(); |
||
68 | |||
69 | return; |
||
70 | } |
||
71 | |||
72 | $errors = $this->validateOnSubmit($attribute, $value); |
||
73 | foreach ($errors as $error) { |
||
74 | $fail($error)->translate(); |
||
75 | } |
||
76 | } |
||
77 | |||
78 | /** |
||
79 | * Set the performing validator. |
||
80 | * |
||
81 | * @param \Illuminate\Contracts\Validation\Validator $validator |
||
82 | * @return $this |
||
83 | */ |
||
84 | public function setValidator($validator) |
||
85 | { |
||
86 | $this->validator = $validator; |
||
87 | |||
88 | return $this; |
||
89 | } |
||
90 | |||
91 | /** |
||
92 | * Set the data under validation. |
||
93 | * |
||
94 | * @param array $data |
||
95 | * @return $this |
||
96 | */ |
||
97 | public function setData($data) |
||
98 | { |
||
99 | $this->data = $data; |
||
100 | |||
101 | return $this; |
||
102 | } |
||
103 | |||
104 | public function getFieldRules(): array |
||
112 | }); |
||
113 | } |
||
114 | |||
115 | protected static function getRulesAsArray($rules) |
||
116 | { |
||
117 | if (is_string($rules)) { |
||
118 | $rules = explode('|', $rules); |
||
119 | } |
||
120 | |||
121 | if (! is_array($rules)) { |
||
122 | $rules = [$rules]; |
||
123 | } |
||
124 | |||
125 | return $rules; |
||
126 | } |
||
127 | |||
128 | protected function ensureValueIsValid($value) |
||
129 | { |
||
130 | if($this->validatesArrays() && ! is_array($value)) { |
||
131 | try { |
||
132 | $value = json_decode($value, true) ?? []; |
||
133 | } catch(\Exception $e) { |
||
134 | return false; |
||
135 | } |
||
136 | } |
||
137 | |||
138 | return $value; |
||
139 | } |
||
140 | |||
141 | private function validatesArrays(): bool |
||
142 | { |
||
143 | return is_a($this, ValidateArrayContract::class); |
||
144 | } |
||
145 | |||
146 | private function validateAndGetErrors(string $attribute, mixed $value, array $rules): array |
||
147 | { |
||
148 | $validator = Validator::make($value, [ |
||
149 | $attribute => $rules, |
||
150 | ], $this->validator->customMessages, $this->validator->customAttributes); |
||
151 | return $validator->errors()->messages()[$attribute] ?? []; |
||
152 | } |
||
153 | |||
154 | protected function getValidationAttributeString(string $attribute) |
||
155 | { |
||
156 | return Str::substrCount($attribute, '.') > 1 ? |
||
157 | Str::before($attribute, '.').'.*.'.Str::afterLast($attribute, '.') : |
||
158 | $attribute; |
||
159 | } |
||
160 | |||
161 | protected function validateOnSubmit(string $attribute, mixed $value): array |
||
162 | { |
||
163 | return $this->validateRules($attribute, $value); |
||
164 | } |
||
165 | |||
166 | protected function validateFieldAndFile(string $attribute, null|array $data = null, array|null $customRules = null): array |
||
167 | { |
||
168 | $fieldErrors = $this->validateFieldRules($attribute, $data, $customRules); |
||
169 | $fileErrors = $this->validateFileRules($attribute, $data); |
||
170 | |||
171 | return array_merge($fieldErrors, $fileErrors); |
||
172 | } |
||
173 | |||
174 | /** |
||
175 | * Implementation. |
||
176 | */ |
||
177 | public function validateFieldRules(string $attribute, null|array|UploadedFile $data = null, array|null $customRules = null): array |
||
178 | { |
||
179 | $data = $data ?? $this->data; |
||
180 | $validationRuleAttribute = $this->getValidationAttributeString($attribute); |
||
181 | |||
182 | $data = $this->prepareValidatorData($data, $attribute); |
||
183 | |||
184 | return $this->validateAndGetErrors($validationRuleAttribute, $data, $customRules ?? $this->getFieldRules()); |
||
185 | } |
||
186 | |||
187 | protected function prepareValidatorData(array|UploadedFile $data, string $attribute): array |
||
194 | } |
||
195 | |||
196 | protected function validateFileRules(string $attribute, mixed $data): array |
||
197 | { |
||
198 | $data = $data ?? $this->data; |
||
199 | $items = is_array($data) && array_key_exists($attribute, $data) ? $data[$attribute] : $data; |
||
200 | $items = is_array($items) ? $items : [$items]; |
||
201 | $errors = []; |
||
202 | // we validate each file individually to avoid returning messages like: `field.0` is not a pdf. |
||
203 | foreach ($items as $sentFiles) { |
||
204 | if(!is_array($sentFiles)) { |
||
205 | try { |
||
206 | if (is_file($sentFiles)) { |
||
207 | $errors[] = $this->validateAndGetErrors($attribute, [$attribute => $sentFiles], $this->getFileRules()); |
||
208 | } |
||
209 | continue; |
||
210 | }catch(\Exception) { |
||
211 | $errors[] = 'Unknown datatype, aborting upload process.'; |
||
212 | break; |
||
213 | } |
||
214 | } |
||
215 | |||
216 | if (is_multidimensional_array($sentFiles)) { |
||
217 | foreach ($sentFiles as $key => $value) { |
||
218 | foreach ($value[$attribute] as $file) { |
||
219 | if (is_file($file)) { |
||
220 | $errors[] = $this->validateAndGetErrors($attribute, [$attribute => $file], $this->getFileRules()); |
||
221 | } |
||
222 | } |
||
223 | } |
||
224 | continue; |
||
225 | } |
||
226 | |||
227 | foreach ($sentFiles as $key => $value) { |
||
228 | if (is_file($value)) { |
||
229 | $errors[] = $this->validateAndGetErrors($attribute, [$attribute => $value], $this->getFileRules()); |
||
230 | } |
||
231 | } |
||
232 | } |
||
233 | |||
234 | return array_unique(array_merge(...$errors)); |
||
235 | } |
||
236 | |||
237 | public function validateRules(string $attribute, mixed $value): array |
||
240 | } |
||
241 | } |
||
242 |
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return
,die
orexit
statements that have been added for debug purposes.In the above example, the last
return false
will never be executed, because a return statement has already been met in every possible execution path.