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 | 53 | public function parentRules() |
|||||
28 | { |
||||||
29 | 53 | return []; |
|||||
30 | } |
||||||
31 | |||||||
32 | 53 | public function buildRules() |
|||||
33 | { |
||||||
34 | 53 | $rules = []; |
|||||
35 | 53 | foreach (array_merge($this->parentRules(), $this->rules()) as $key => $rule) { |
|||||
36 | 22 | if ($rule instanceof Attribute) { |
|||||
37 | 9 | $rule = $rule->getRules(); |
|||||
38 | } |
||||||
39 | 22 | $rules[$key] = $rule; |
|||||
40 | } |
||||||
41 | |||||||
42 | 53 | foreach ($this->includes() as $key => $included) { |
|||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||||
43 | 2 | if (! array_key_exists($key, $rules)) { |
|||||
44 | 1 | $rules[$key] = 'required'; |
|||||
45 | } |
||||||
46 | } |
||||||
47 | |||||||
48 | 53 | return $rules; |
|||||
49 | } |
||||||
50 | |||||||
51 | 53 | public function passesValidation() |
|||||
52 | { |
||||||
53 | 53 | return $this->getValidatorInstance()->passes(); |
|||||
54 | } |
||||||
55 | |||||||
56 | 53 | public function setValidator(Validator $validator) |
|||||
57 | { |
||||||
58 | 53 | $this->validator = $validator; |
|||||
59 | |||||||
60 | 53 | return $this; |
|||||
61 | } |
||||||
62 | |||||||
63 | 12 | public function validated(bool $recursive = true) |
|||||
64 | { |
||||||
65 | 12 | $data = $this->validator->validated(); |
|||||
66 | |||||||
67 | 12 | return array_merge($recursive ? $this->filterRulesRecursively($data) : $data, $this->includes()); |
|||||
68 | } |
||||||
69 | |||||||
70 | 11 | protected function filterRulesRecursively(array $data) |
|||||
71 | { |
||||||
72 | //Dot notation makes it possible to parse nested values without recursion |
||||||
73 | 11 | $original = Arr::dot($data); |
|||||
74 | |||||||
75 | 11 | $filtered = []; |
|||||
76 | 11 | $rules = collect($this->buildRules()); |
|||||
77 | 11 | $keys = $rules->keys(); |
|||||
78 | 11 | $rules->each(function ($rules, $key) use ($original, $keys, &$filtered) { |
|||||
79 | //Allow for array or pipe-delimited rule-sets |
||||||
80 | 11 | if (is_string($rules)) { |
|||||
81 | 3 | $rules = explode('|', $rules); |
|||||
82 | } |
||||||
83 | //In case a rule requires an element to be an array, look for nested rules |
||||||
84 | 11 | $nestedRules = $keys->filter(function ($otherKey) use ($key) { |
|||||
85 | 11 | return strpos($otherKey, "$key.") === 0; |
|||||
86 | 11 | }); |
|||||
87 | //If the input must be an array, default missing nested rules to a wildcard |
||||||
88 | 11 | if (in_array('array', $rules) && $nestedRules->isEmpty()) { |
|||||
89 | 1 | $key .= '.*'; |
|||||
90 | } |
||||||
91 | |||||||
92 | 11 | foreach ($original as $dotIndex => $element) { |
|||||
93 | //fnmatch respects wildcard asterisks |
||||||
94 | 11 | if (fnmatch($key, $dotIndex)) { |
|||||
95 | //array_set respects dot-notation, building out a normal array |
||||||
96 | 11 | Arr::set($filtered, $dotIndex, $element); |
|||||
97 | } |
||||||
98 | } |
||||||
99 | 11 | }); |
|||||
100 | |||||||
101 | 11 | return $filtered; |
|||||
102 | } |
||||||
103 | |||||||
104 | 51 | public function rules() |
|||||
105 | { |
||||||
106 | 51 | return []; |
|||||
107 | } |
||||||
108 | |||||||
109 | 52 | public function messages() |
|||||
110 | { |
||||||
111 | 52 | return []; |
|||||
112 | } |
||||||
113 | |||||||
114 | 52 | public function attributes() |
|||||
115 | { |
||||||
116 | 52 | return []; |
|||||
117 | } |
||||||
118 | |||||||
119 | 51 | protected function resolveValidation() |
|||||
120 | { |
||||||
121 | 51 | if (! $this->passesValidation()) { |
|||||
122 | 6 | $this->failedValidation(); |
|||||
123 | } |
||||||
124 | |||||||
125 | 47 | return $this; |
|||||
126 | } |
||||||
127 | |||||||
128 | 51 | protected function setValidatorInstance($validator){ |
|||||
129 | 51 | $this->validator = $validator; |
|||||
130 | 51 | } |
|||||
131 | |||||||
132 | 53 | protected function getValidatorInstance() |
|||||
133 | { |
||||||
134 | 53 | if ($this->validator) { |
|||||
135 | return $this->validator; |
||||||
136 | } |
||||||
137 | |||||||
138 | 53 | $factory = app(ValidationFactory::class); |
|||||
139 | |||||||
140 | 53 | $validator = method_exists($this, 'validator') |
|||||
141 | 1 | ? $this->validator($factory) |
|||||
142 | 53 | : $this->createDefaultValidator($factory); |
|||||
143 | |||||||
144 | 53 | if (method_exists($this, 'withValidator')) { |
|||||
145 | 1 | $this->resolveAndCall($this, 'withValidator', compact('validator')); |
|||||
0 ignored issues
–
show
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
![]() |
|||||||
146 | } |
||||||
147 | |||||||
148 | 53 | if (method_exists($this, 'afterValidator')) { |
|||||
149 | 1 | $validator->after(function ($validator) { |
|||||
150 | 1 | $this->resolveAndCall($this, 'afterValidator', compact('validator')); |
|||||
151 | 1 | }); |
|||||
152 | } |
||||||
153 | |||||||
154 | 53 | $this->setValidator($validator); |
|||||
155 | |||||||
156 | 53 | return $this->validator; |
|||||
157 | } |
||||||
158 | |||||||
159 | 52 | protected function createDefaultValidator(ValidationFactory $factory) |
|||||
160 | { |
||||||
161 | 52 | return $factory->make( |
|||||
162 | 52 | $this->validationData(), $this->buildRules(), |
|||||
163 | 52 | $this->messages(), $this->attributes() |
|||||
164 | ); |
||||||
165 | } |
||||||
166 | |||||||
167 | 6 | protected function failedValidation() |
|||||
168 | { |
||||||
169 | 6 | throw (new ValidationException($this->validator)) |
|||||
170 | 6 | ->errorBag($this->errorBag) |
|||||
171 | 6 | ->redirectTo($this->getRedirectUrl()); |
|||||
172 | } |
||||||
173 | |||||||
174 | 6 | protected function getRedirectUrl() |
|||||
175 | { |
||||||
176 | 6 | return redirect()->getUrlGenerator()->previous(); |
|||||
177 | } |
||||||
178 | |||||||
179 | 52 | protected function validationData() |
|||||
180 | { |
||||||
181 | 52 | return $this->all(); |
|||||
0 ignored issues
–
show
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
![]() |
|||||||
182 | } |
||||||
183 | } |
||||||
184 |