Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Passed
Pull Request — main (#5440)
by Cristian
30:05 queued 14:48
created

BackpackCustomRule::validateFieldRules()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
c 0
b 0
f 0
nc 1
nop 3
dl 0
loc 8
rs 10
1
<?php
2
3
namespace Backpack\CRUD\app\Library\Validation\Rules;
4
5
use Backpack\CRUD\app\Library\Validation\Rules\Support\ValidateArrayContract;
6
use Closure;
7
use Illuminate\Contracts\Validation\DataAwareRule;
8
use Illuminate\Contracts\Validation\Rule;
9
use Illuminate\Contracts\Validation\ValidationRule;
10
use Illuminate\Contracts\Validation\ValidatorAwareRule;
11
use Illuminate\Http\UploadedFile;
12
use Illuminate\Support\Arr;
13
use Illuminate\Support\Facades\Validator;
14
use Illuminate\Support\Str;
15
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
42
        return $instance;
43
44
        $instance = new static();
0 ignored issues
show
Unused Code introduced by
$instance = new static() is not reachable.

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 or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

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.

Loading history...
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
105
    {
106
        return tap($this->fieldRules, function ($rule) {
107
            if (is_a($rule, BackpackCustomRule::class, true)) {
108
                $rule = $rule->getFieldRules();
109
            }
110
111
            return $rule;
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);
0 ignored issues
show
Bug introduced by
Accessing customAttributes on the interface Illuminate\Contracts\Validation\Validator suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
Bug introduced by
Accessing customMessages on the interface Illuminate\Contracts\Validation\Validator suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
151
152
        return $validator->errors()->messages()[$attribute] ?? [];
153
    }
154
155
    protected function getValidationAttributeString(string $attribute)
156
    {
157
        return Str::substrCount($attribute, '.') > 1 ?
158
                Str::before($attribute, '.').'.*.'.Str::afterLast($attribute, '.') :
159
                $attribute;
160
    }
161
162
    protected function validateOnSubmit(string $attribute, mixed $value): array
163
    {
164
        return $this->validateRules($attribute, $value);
165
    }
166
167
    protected function validateFieldAndFile(string $attribute, null|array $data = null, array|null $customRules = null): array
168
    {
169
        $fieldErrors = $this->validateFieldRules($attribute, $data, $customRules);
170
        $fileErrors = $this->validateFileRules($attribute, $data);
171
172
        return array_merge($fieldErrors, $fileErrors);
173
    }
174
175
    /**
176
     * Implementation.
177
     */
178
    public function validateFieldRules(string $attribute, null|array|UploadedFile $data = null, array|null $customRules = null): array
179
    {
180
        $data = $data ?? $this->data;
181
        $validationRuleAttribute = $this->getValidationAttributeString($attribute);
182
183
        $data = $this->prepareValidatorData($data, $attribute);
184
185
        return $this->validateAndGetErrors($validationRuleAttribute, $data, $customRules ?? $this->getFieldRules());
186
    }
187
188
    protected function prepareValidatorData(array|UploadedFile $data, string $attribute): array
189
    {
190
        if ($this->validatesArrays() && is_array($data)) {
191
            return Arr::has($data, $attribute) ? $data : [$attribute => Arr::get($data, $attribute)];
192
        }
193
194
        return [$attribute => $data];
195
    }
196
197
    protected function validateFileRules(string $attribute, mixed $data): array
198
    {
199
        $data = $data ?? $this->data;
200
        $items = is_array($data) && array_key_exists($attribute, $data) ? $data[$attribute] : $data;
201
        $items = is_array($items) ? $items : [$items];
202
        $errors = [];
203
        // we validate each file individually to avoid returning messages like: `field.0` is not a pdf.
204
        foreach ($items as $sentFiles) {
205
            if (! is_array($sentFiles)) {
206
                try {
207
                    if (is_file($sentFiles)) {
208
                        $errors[] = $this->validateAndGetErrors($attribute, [$attribute => $sentFiles], $this->getFileRules());
209
                    }
210
                    continue;
211
                } catch(\Exception) {
212
                    $errors[] = 'Unknown datatype, aborting upload process.';
213
                    break;
214
                }
215
            }
216
217
            if (is_multidimensional_array($sentFiles)) {
218
                foreach ($sentFiles as $key => $value) {
219
                    foreach ($value[$attribute] as $file) {
220
                        if (is_file($file)) {
221
                            $errors[] = $this->validateAndGetErrors($attribute, [$attribute => $file], $this->getFileRules());
222
                        }
223
                    }
224
                }
225
                continue;
226
            }
227
228
            foreach ($sentFiles as $key => $value) {
229
                if (is_file($value)) {
230
                    $errors[] = $this->validateAndGetErrors($attribute, [$attribute => $value], $this->getFileRules());
231
                }
232
            }
233
        }
234
235
        return array_unique(array_merge(...$errors));
236
    }
237
238
    public function validateRules(string $attribute, mixed $value): array
239
    {
240
        return $this->validateFieldAndFile($attribute, $value);
241
    }
242
}
243