line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Mojolicious::Validator::Validation; |
2
|
51
|
|
|
51
|
|
429
|
use Mojo::Base -base; |
|
51
|
|
|
|
|
224
|
|
|
51
|
|
|
|
|
419
|
|
3
|
|
|
|
|
|
|
|
4
|
51
|
|
|
51
|
|
405
|
use Carp (); |
|
51
|
|
|
|
|
189
|
|
|
51
|
|
|
|
|
1539
|
|
5
|
51
|
|
|
51
|
|
451
|
use Mojo::DynamicMethods -dispatch; |
|
51
|
|
|
|
|
189
|
|
|
51
|
|
|
|
|
445
|
|
6
|
51
|
|
|
51
|
|
462
|
use Scalar::Util (); |
|
51
|
|
|
|
|
194
|
|
|
51
|
|
|
|
|
66881
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
has [qw(csrf_token topic validator)]; |
9
|
|
|
|
|
|
|
has [qw(input output)] => sub { {} }; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
sub BUILD_DYNAMIC { |
12
|
61
|
|
|
61
|
0
|
152
|
my ($class, $method, $dyn_methods) = @_; |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
return sub { |
15
|
65
|
|
|
65
|
|
132
|
my $self = shift; |
|
|
|
|
130
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
|
65
|
|
|
|
16
|
65
|
|
|
|
|
159
|
my $dynamic = $dyn_methods->{$self->validator}{$method}; |
17
|
65
|
50
|
|
|
|
245
|
return $self->check($method => @_) if $dynamic; |
18
|
0
|
|
|
|
|
0
|
my $package = ref $self; |
19
|
0
|
|
|
|
|
0
|
Carp::croak qq{Can't locate object method "$method" via package "$package"}; |
20
|
61
|
|
|
|
|
327
|
}; |
21
|
|
|
|
|
|
|
} |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
sub check { |
24
|
65
|
|
|
65
|
1
|
134
|
my ($self, $check) = (shift, shift); |
25
|
|
|
|
|
|
|
|
26
|
65
|
100
|
|
|
|
121
|
return $self unless $self->is_valid; |
27
|
|
|
|
|
|
|
|
28
|
57
|
|
|
|
|
152
|
my $cb = $self->validator->checks->{$check}; |
29
|
57
|
|
|
|
|
144
|
my $name = $self->topic; |
30
|
57
|
|
|
|
|
128
|
my $values = $self->output->{$name}; |
31
|
57
|
100
|
|
|
|
168
|
for my $value (ref $values eq 'ARRAY' ? @$values : $values) { |
32
|
64
|
100
|
|
|
|
198
|
next unless my $result = $self->$cb($name, $value, @_); |
33
|
22
|
|
|
|
|
98
|
return $self->error($name => [$check, $result, @_]); |
34
|
|
|
|
|
|
|
} |
35
|
|
|
|
|
|
|
|
36
|
35
|
|
|
|
|
211
|
return $self; |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub csrf_protect { |
40
|
10
|
|
|
10
|
1
|
72
|
my $self = shift; |
41
|
10
|
|
|
|
|
27
|
my $token = $self->input->{csrf_token}; |
42
|
10
|
100
|
100
|
|
|
55
|
$self->error(csrf_token => ['csrf_protect']) unless $token && $token eq ($self->csrf_token // ''); |
|
|
|
100
|
|
|
|
|
43
|
10
|
|
|
|
|
58
|
return $self; |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
sub error { |
47
|
57
|
|
|
57
|
1
|
138
|
my ($self, $name) = (shift, shift); |
48
|
57
|
100
|
|
|
|
254
|
return $self->{error}{$name} unless @_; |
49
|
33
|
|
|
|
|
82
|
$self->{error}{$name} = shift; |
50
|
33
|
|
|
|
|
81
|
delete $self->output->{$name}; |
51
|
33
|
|
|
|
|
148
|
return $self; |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
sub every_param { |
55
|
10
|
100
|
66
|
10
|
1
|
36
|
return [] unless defined(my $value = $_[0]->output->{$_[1] // $_[0]->topic}); |
56
|
8
|
100
|
|
|
|
65
|
return [ref $value eq 'ARRAY' ? @$value : $value]; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
|
59
|
6
|
|
|
6
|
1
|
15
|
sub failed { [sort keys %{shift->{error}}] } |
|
6
|
|
|
|
|
60
|
|
60
|
|
|
|
|
|
|
|
61
|
23
|
|
|
23
|
1
|
180
|
sub has_data { !!keys %{shift->input} } |
|
23
|
|
|
|
|
69
|
|
62
|
|
|
|
|
|
|
|
63
|
232
|
100
|
|
232
|
1
|
1366
|
sub has_error { $_[1] ? exists $_[0]{error}{$_[1]} : !!keys %{$_[0]{error}} } |
|
36
|
|
|
|
|
265
|
|
64
|
|
|
|
|
|
|
|
65
|
194
|
|
66
|
194
|
1
|
430
|
sub is_valid { exists $_[0]->output->{$_[1] // $_[0]->topic} } |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub optional { |
68
|
87
|
|
|
87
|
1
|
265
|
my ($self, $name, @filters) = @_; |
69
|
|
|
|
|
|
|
|
70
|
87
|
100
|
|
|
|
213
|
return $self->topic($name) unless defined(my $input = $self->input->{$name}); |
71
|
|
|
|
|
|
|
|
72
|
76
|
100
|
|
|
|
270
|
my @input = ref $input eq 'ARRAY' ? @$input : ($input); |
73
|
76
|
|
|
|
|
186
|
for my $cb (map { $self->validator->filters->{$_} } @filters) { |
|
18
|
|
|
|
|
42
|
|
74
|
18
|
|
|
|
|
33
|
@input = map { $self->$cb($name, $_) } @input; |
|
36
|
|
|
|
|
90
|
|
75
|
|
|
|
|
|
|
} |
76
|
76
|
100
|
100
|
|
|
230
|
$self->output->{$name} = @input > 1 ? \@input : $input[0] if @input && !grep { !defined } @input; |
|
95
|
100
|
|
|
|
483
|
|
77
|
|
|
|
|
|
|
|
78
|
76
|
|
|
|
|
205
|
return $self->topic($name); |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
6
|
|
|
6
|
1
|
24
|
sub param { shift->every_param(shift)->[-1] } |
82
|
|
|
|
|
|
|
|
83
|
3
|
|
|
3
|
1
|
29
|
sub passed { [sort keys %{shift->output}] } |
|
3
|
|
|
|
|
13
|
|
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
sub required { |
86
|
62
|
|
|
62
|
1
|
524
|
my ($self, $name) = (shift, shift); |
87
|
62
|
100
|
|
|
|
166
|
return $self if $self->optional($name, @_)->is_valid; |
88
|
4
|
|
|
|
|
22
|
return $self->error($name => ['required']); |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
1; |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=encoding utf8 |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=head1 NAME |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
Mojolicious::Validator::Validation - Perform validations |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=head1 SYNOPSIS |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
use Mojolicious::Validator; |
102
|
|
|
|
|
|
|
use Mojolicious::Validator::Validation; |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
my $validator = Mojolicious::Validator->new; |
105
|
|
|
|
|
|
|
my $v = Mojolicious::Validator::Validation->new(validator => $validator); |
106
|
|
|
|
|
|
|
$v->input({foo => 'bar'}); |
107
|
|
|
|
|
|
|
$v->required('foo')->in('bar', 'baz'); |
108
|
|
|
|
|
|
|
say $v->param('foo'); |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=head1 DESCRIPTION |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
L performs L validation checks. |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
L implements the following attributes. |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=head2 csrf_token |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
my $token = $v->csrf_token; |
121
|
|
|
|
|
|
|
$v = $v->csrf_token('fa6a08...'); |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
CSRF token. |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=head2 input |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
my $input = $v->input; |
128
|
|
|
|
|
|
|
$v = $v->input({foo => 'bar', baz => [123, 'yada']}); |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
Data to be validated. |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
=head2 output |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
my $output = $v->output; |
135
|
|
|
|
|
|
|
$v = $v->output({foo => 'bar', baz => [123, 'yada']}); |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
Validated data. |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
=head2 topic |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
my $topic = $v->topic; |
142
|
|
|
|
|
|
|
$v = $v->topic('foo'); |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
Name of field currently being validated. |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=head2 validator |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
my $v = $v->validator; |
149
|
|
|
|
|
|
|
$v = $v->validator(Mojolicious::Validator->new); |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
L object this validation belongs to. |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
=head1 METHODS |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
L inherits all methods from L and implements the following new ones. |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=head2 check |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
$v = $v->check('size', 2, 7); |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
Perform validation check on all values of the current L"topic">, no more checks will be performed on them after the |
162
|
|
|
|
|
|
|
first one failed. All checks from L are supported. |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
=head2 csrf_protect |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
$v = $v->csrf_protect; |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
Validate C and protect from cross-site request forgery. |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=head2 error |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
my $err = $v->error('foo'); |
173
|
|
|
|
|
|
|
$v = $v->error(foo => ['custom_check']); |
174
|
|
|
|
|
|
|
$v = $v->error(foo => [$check, $result, @args]); |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
Get or set details for failed validation check, at any given time there can only be one per field. |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# Details about failed validation |
179
|
|
|
|
|
|
|
my ($check, $result, @args) = @{$v->error('foo')}; |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
# Force validation to fail for a field without performing a check |
182
|
|
|
|
|
|
|
$v->error(foo => ['some_made_up_check_name']); |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=head2 every_param |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
my $values = $v->every_param; |
187
|
|
|
|
|
|
|
my $values = $v->every_param('foo'); |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
Similar to L"param">, but returns all values sharing the same name as an array reference. |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
# Get first value |
192
|
|
|
|
|
|
|
my $first = $v->every_param('foo')->[0]; |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=head2 failed |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
my $names = $v->failed; |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
Return an array reference with all names for values that failed validation. |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# Names of all values that failed |
201
|
|
|
|
|
|
|
say for @{$v->failed}; |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
=head2 has_data |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
my $bool = $v->has_data; |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
Check if L"input"> is available for validation. |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=head2 has_error |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
my $bool = $v->has_error; |
212
|
|
|
|
|
|
|
my $bool = $v->has_error('foo'); |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
Check if validation resulted in errors, defaults to checking all fields. |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
=head2 is_valid |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
my $bool = $v->is_valid; |
219
|
|
|
|
|
|
|
my $bool = $v->is_valid('foo'); |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
Check if validation was successful and field has a value, defaults to checking the current L"topic">. |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=head2 optional |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
$v = $v->optional('foo'); |
226
|
|
|
|
|
|
|
$v = $v->optional('foo', @filters); |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
Change validation L"topic"> and apply filters. All filters from L are supported. |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
# Trim value and check size |
231
|
|
|
|
|
|
|
$v->optional('user', 'trim')->size(1, 15); |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=head2 param |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
my $value = $v->param; |
236
|
|
|
|
|
|
|
my $value = $v->param('foo'); |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
Access validated values, defaults to the current L"topic">. If there are multiple values sharing the same name, and |
239
|
|
|
|
|
|
|
you want to access more than just the last one, you can use L"every_param">. |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
# Get value right away |
242
|
|
|
|
|
|
|
my $user = $v->optional('user')->size(1, 15)->param; |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=head2 passed |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
my $names = $v->passed; |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
Return an array reference with all names for values that passed validation. |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
# Names of all values that passed |
251
|
|
|
|
|
|
|
say for @{$v->passed}; |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=head2 required |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
$v = $v->required('foo'); |
256
|
|
|
|
|
|
|
$v = $v->required('foo', @filters); |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
Change validation L"topic">, apply filters, and make sure a value is present. All filters from |
259
|
|
|
|
|
|
|
L are supported. |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
# Trim value and check size |
262
|
|
|
|
|
|
|
$v->required('user', 'trim')->size(1, 15); |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=head1 CHECKS |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
In addition to the L"ATTRIBUTES"> and L"METHODS"> above, you can also call validation checks provided by |
267
|
|
|
|
|
|
|
L"validator"> on L objects, similar to L"check">. |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# Call validation checks |
270
|
|
|
|
|
|
|
$v->required('foo')->size(2, 5)->like(qr/^[A-Z]/); |
271
|
|
|
|
|
|
|
$v->optional('bar')->equal_to('foo'); |
272
|
|
|
|
|
|
|
$v->optional('baz')->in('test', '123'); |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
# Longer version |
275
|
|
|
|
|
|
|
$v->required('foo')->check('size', 2, 5)->check('like', qr/^[A-Z]/); |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=head1 SEE ALSO |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
L, L, L. |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=cut |