File Coverage

blib/lib/Catmandu/Validator.pm
Criterion Covered Total %
statement 54 55 98.1
branch 21 22 95.4
condition 11 11 100.0
subroutine 8 8 100.0
pod 2 2 100.0
total 96 98 97.9


line stmt bran cond sub pod time code
1              
2             use Catmandu::Sane;
3 7     7   3563  
  7         15  
  7         40  
4             our $VERSION = '1.2018';
5              
6             use Catmandu::Util qw(:is);
7 7     7   53 use Moo::Role;
  7         16  
  7         1660  
8 7     7   47 use namespace::clean;
  7         26  
  7         52  
9 7     7   3103  
  7         15  
  7         40  
10             requires 'validate_data';
11              
12             has 'last_errors' =>
13             (is => 'rwp', clearer => '_clear_last_errors', init_arg => undef,);
14              
15             has 'after_callback' => (is => 'ro', clearer => 1,);
16              
17             has 'error_callback' => (is => 'ro', clearer => 1,);
18              
19             has 'error_field' => (is => 'ro', clearer => 1,);
20              
21             has ['valid_count', 'invalid_count'] =>
22             (is => 'rwp', init_arg => undef, default => sub {0},);
23              
24             my ($self, $data) = @_;
25              
26 10     10 1 28 if (!is_hash_ref($data)) {
27             Catmandu::BadArg->throw('Cannot validate data of this type');
28 10 50       35 }
29 0         0  
30             $self->_clear_last_errors;
31             $self->_set_valid_count(0);
32 10         259 $self->_set_invalid_count(0);
33 10         72  
34 10         29 my $errors = $self->validate_data($data);
35              
36 10         33 if ($errors) {
37             $self->_set_last_errors($errors);
38 10 100       33 $self->_set_invalid_count(1);
39 6         23 return 0;
40 6         16 }
41 6         35 else {
42             $self->_set_valid_count(1);
43             }
44 4         12  
45             1;
46             }
47 4         33  
48             my ($self, $data) = @_;
49              
50             $self->_set_valid_count(0);
51 12     12 1 3298 $self->_set_invalid_count(0);
52              
53 12         38 # handle a single record
54 12         20 if (is_hash_ref($data)) {
55             return $self->_process_record($data);
56             }
57 12 100       45  
58 5         14 # handle arrayref, returns a new arrayref
59             if (is_array_ref($data)) {
60             return [grep {defined} map {$self->_process_record($_)} @$data];
61             }
62 7 100       18  
63 5         8 # handle iterators, returns a new iterator
  16         51  
  16         46  
64             if (is_invocant($data)) {
65             return $data->select(sub {$self->_process_record($_[0])});
66             }
67 2 100       10  
68 1     3   7 Catmandu::BadArg->throw('Cannot validate data of this type');
  3         5  
69             }
70              
71 1         29 my ($self, $data) = @_;
72              
73             my $error_field
74             = ($self->error_field || 0) eq '1'
75 24     24   39 ? '_validation_errors'
76             : $self->error_field;
77 24 100 100     90  
78             $self->_clear_last_errors;
79             my $errors = $self->validate_data($data);
80             $self->_set_last_errors($errors);
81              
82 24         379 if ($errors) {
83 24         118 $self->_set_invalid_count(1 + $self->invalid_count);
84 24         103 }
85             else {
86 24 100       41 $self->_set_valid_count(1 + $self->valid_count);
87 14         28 }
88              
89             if ($errors && $error_field) {
90 10         23 $data->{$error_field} = $errors;
91             }
92              
93 24 100 100     66 if ($self->after_callback) {
94 4         6 return $self->after_callback->($data, $errors);
95             }
96              
97 24 100       51 if ($errors && $self->error_callback) {
98 8         12 $self->error_callback->($data, $errors);
99             return;
100             }
101 16 100 100     38  
102 2         6 return if $errors && !$error_field;
103 2         50  
104             $data;
105             }
106 14 100 100     43  
107             1;
108 11         33  
109              
110             =pod
111              
112             =head1 NAME
113              
114             Catmandu::Validator - Namespace for packages that can validate items in Catmandu
115              
116             =head1 SYNOPSIS
117              
118             use Catmandu::Validator::Simple;
119              
120             my $validator = Catmandu::Validator::Simple->new(
121             handler => sub {
122             $data = shift;
123             return "error" unless $data->{title} =~ m/good title/;
124             return;
125             }
126             );
127              
128             if ( $validator->is_valid($hashref) ) {
129             save_record_in_database($hashref);
130             } else {
131             reject_form($validator->last_errors);
132             }
133              
134             my $validator = Catmandu::Validator::Simple->new(
135             handler => sub { ...},
136             error_callback => sub {
137             my ($data, $errors) = @_;
138             print "Validation errors for record $data->{_id}:\n";
139             print "$_\n" for @{$errors};
140             }
141             };
142              
143             my $validated_arrayref = $validator->validate($arrayref);
144              
145             $validator->validate($iterator, {
146             after_callback => sub {
147             my ($record, $errors) = @_;
148             if ($errors) {
149             add_to_failure_report($rec, $errors);
150             #omit the invalid record from the result
151             return undef;
152             }
153             return $rec;
154             }
155             })->each( sub {
156             my $record = shift;
157             publish_record($record);
158             });
159              
160             See L<Catmandu::Fix::validate> and L<Catmandu::Fix::Condition::valid> to use validators in fixes (L<Catmandu::Fix>).
161              
162             =head1 DESCRIPTION
163              
164             A Catmandu::Validator is a base class for Perl packages that can validate data.
165              
166             =head1 METHODS
167              
168             =head2 new()
169              
170             Create a new Catmandu::Validator.
171              
172             =head2 new( after_callback => \&callback )
173              
174             The after_callback is called after each record has been validated.
175             The callback function should take $hashref to each data record, and $arrayref to list of validation errors
176             for the record as arguments.
177              
178             =head2 new( error_field => $field_name )
179              
180             If the error_field parameter is set, then during validation each record that
181             fails validation will get an extra field added containing an
182             arrayref to the validation errors. The name of the key will be the
183             value passed or '_validation_errors' if 1 is passed. By default it is not set.
184              
185             =head2 is_valid( \%hash )
186              
187             Validates a single record. Returns 1 success and 0 on failure. Information about the validation errors
188             can be retrieved with the L</"last_errors()"> method.
189              
190             =head2 validate( \%hash )
191              
192             =head2 validate( $iterator )
193              
194             =head2 validate( \@array )
195              
196             Validates a single record or multiple records in an iterator or an array. Returns validated records in the same type of
197             container for multiple records or the record itself for a single record. The default behaviour is to return the records that passed validation unchanged and omit the invalid records.
198             This behaviour can be changed by setting the I<after_callback> or the I<error_field> in the constructor. Returns undef on validation failure for single records.
199              
200             =head2 last_errors()
201              
202             Returns arrayref of errors from the record that was last validated if that record failed validation
203             or undef if there were no errors.
204              
205             =head2 valid_count()
206              
207             Returns the number of valid records from last validate operation.
208              
209             =head2 invalid_count()
210              
211             Returns the number of invalid records from the last validate operation.
212              
213             =head1 SEE ALSO
214              
215             L<Catmandu::Validator::Env> and L<Catmandu::Validator::Simple>.
216              
217             L<Catmandu::Iterable>
218              
219             =cut