Completed
Push — master ( d94286...918439 )
by Arthur
03:31
created

ResolvesValidation::filterRulesRecursively()   A

Complexity

Conditions 6
Paths 1

Size

Total Lines 32
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 6.0087

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 15
c 1
b 0
f 0
dl 0
loc 32
ccs 15
cts 16
cp 0.9375
rs 9.2222
cc 6
nc 1
nop 1
crap 6.0087
1
<?php
2
3
namespace Larapie\Actions\Concerns;
4
5
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
6
use Illuminate\Support\Arr;
7
use Illuminate\Validation\ValidationException;
8
use Illuminate\Validation\Validator;
9
use Larapie\Actions\Attribute;
10
11
trait ResolvesValidation
12
{
13
    protected $errorBag = 'default';
14
15
    /**
16
     * @var Validator
17
     */
18
    protected $validator;
19
20 1
    public function validate($rules = [], $messages = [], $customAttributes = [])
21
    {
22 1
        return app(ValidationFactory::class)
23 1
            ->make($this->validationData(), $rules, $messages, $customAttributes)
24 1
            ->validate();
25
    }
26
27 48
    public function buildRules()
28
    {
29 48
        $rules = [];
30 48
        foreach ($this->rules() as $key => $rule) {
31 17
            if ($rule instanceof Attribute) {
32 6
                $rule = $rule->getRules();
33
            }
34 17
            $rules[$key] = $rule;
35
        }
36
37 48
        foreach ($this->includes() as $key => $included) {
0 ignored issues
show
Bug introduced by
It seems like includes() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

37
        foreach ($this->/** @scrutinizer ignore-call */ includes() as $key => $included) {
Loading history...
38 2
            if (!array_key_exists($key, $rules)) {
39 1
                $rules[$key] = 'required';
40
            }
41
        }
42
43 48
        return $rules;
44
    }
45
46 48
    public function passesValidation()
47
    {
48 48
        return $this->getValidatorInstance()->passes();
49
    }
50
51 48
    public function setValidator(Validator $validator)
52
    {
53 48
        $this->validator = $validator;
54
55 48
        return $this;
56
    }
57
58 43
    public function validated(bool $recursive = true)
59
    {
60 43
        return $recursive ? $this->filterRulesRecursively($this->validator->validated()) : $this->validator->validated();
61
    }
62
63 43
    protected function filterRulesRecursively(array $data)
64
    {
65
        //Dot notation makes it possible to parse nested values without recursion
66 43
        $original = Arr::dot($data);
67
68 43
        $filtered = [];
69 43
        $rules = collect($this->buildRules());
70 43
        $keys = $rules->keys();
71
        $rules->each(function ($rules, $key) use ($original, $keys, &$filtered) {
72
            //Allow for array or pipe-delimited rule-sets
73 13
            if (is_string($rules)) {
74 8
                $rules = explode('|', $rules);
75
            }
76
            //In case a rule requires an element to be an array, look for nested rules
77
            $nestedRules = $keys->filter(function ($otherKey) use ($key) {
78 13
                return (strpos($otherKey, "$key.") === 0);
79 13
            });
80
            //If the input must be an array, default missing nested rules to a wildcard
81 13
            if (in_array('array', $rules) && $nestedRules->isEmpty()) {
82
                $key .= ".*";
83
            }
84
85 13
            foreach ($original as $dotIndex => $element) {
86
                //fnmatch respects wildcard asterisks
87 10
                if (fnmatch($key, $dotIndex)) {
88
                    //array_set respects dot-notation, building out a normal array
89 10
                    array_set($filtered, $dotIndex, $element);
0 ignored issues
show
Deprecated Code introduced by
The function array_set() has been deprecated: Arr::set() should be used directly instead. Will be removed in Laravel 5.9. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

89
                    /** @scrutinizer ignore-deprecated */ array_set($filtered, $dotIndex, $element);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
90
                }
91
            }
92 43
        });
93
94 43
        return $filtered;
95
    }
96
97 38
    public function rules()
98
    {
99 38
        return [];
100
    }
101
102 47
    public function messages()
103
    {
104 47
        return [];
105
    }
106
107 47
    public function attributes()
108
    {
109 47
        return [];
110
    }
111
112 46
    protected function resolveValidation()
113
    {
114 46
        if (!$this->passesValidation()) {
115 5
            $this->failedValidation();
116
        }
117
118 42
        return $this;
119
    }
120
121 48
    protected function getValidatorInstance()
122
    {
123 48
        if ($this->validator) {
124 3
            return $this->validator;
125
        }
126
127 48
        $factory = app(ValidationFactory::class);
128
129 48
        $validator = method_exists($this, 'validator')
130 1
            ? $this->validator($factory)
131 48
            : $this->createDefaultValidator($factory);
132
133 48
        if (method_exists($this, 'withValidator')) {
134 1
            $this->resolveAndCall($this, 'withValidator', compact('validator'));
0 ignored issues
show
Bug introduced by
It seems like resolveAndCall() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

134
            $this->/** @scrutinizer ignore-call */ 
135
                   resolveAndCall($this, 'withValidator', compact('validator'));
Loading history...
135
        }
136
137 48
        if (method_exists($this, 'afterValidator')) {
138
            $validator->after(function ($validator) {
139 1
                $this->resolveAndCall($this, 'afterValidator', compact('validator'));
140 1
            });
141
        }
142
143 48
        $this->setValidator($validator);
144
145 48
        return $this->validator;
146
    }
147
148 47
    protected function createDefaultValidator(ValidationFactory $factory)
149
    {
150 47
        return $factory->make(
151 47
            $this->validationData(), $this->buildRules(),
152 47
            $this->messages(), $this->attributes()
153
        );
154
    }
155
156 5
    protected function failedValidation()
157
    {
158 5
        throw (new ValidationException($this->validator))
159 5
            ->errorBag($this->errorBag)
160 5
            ->redirectTo($this->getRedirectUrl());
161
    }
162
163 5
    protected function getRedirectUrl()
164
    {
165 5
        return redirect()->getUrlGenerator()->previous();
166
    }
167
168 47
    protected function validationData()
169
    {
170 47
        return $this->all();
0 ignored issues
show
Bug introduced by
It seems like all() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

170
        return $this->/** @scrutinizer ignore-call */ all();
Loading history...
171
    }
172
}
173