File Coverage

blib/lib/MongoDBx/Tiny/Validator.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package MongoDBx::Tiny::Validator;
2 1     1   1082 use strict;
  1         2  
  1         31  
3 1     1   6 use warnings;
  1         2  
  1         30  
4              
5             =head1 NAME
6              
7             MongoDBx::Tiny::Validator - validation on insert and update.
8              
9             =cut
10              
11 1     1   6 use MongoDBx::Tiny::Util;
  1         2  
  1         78  
12 1     1   480 use Params::Validate qw(:all);
  0            
  0            
13             use Carp qw(confess);
14             use Data::Dumper;
15              
16             =head1 SUBROUTINES/METHODS
17              
18             =head2 new
19              
20             $validator = MongoDBx::Tiny::Validator->new(
21             $collection_name,
22             $document,
23             $tiny,
24             );
25              
26             =cut
27              
28             sub new {
29             my $class = shift;
30             my $c_name = shift || confess q/no collection name/;
31             my $document = shift || confess q/no document/;
32             my $tiny = shift || confess q/no tiny/;
33            
34             return bless {
35             document => $document,
36             collection_name => $c_name,
37             tiny => $tiny,
38             errors => [],
39             }, $class;
40             }
41              
42             =head2 document, collection_name, tiny
43              
44             # alias
45             $document = $validator->document;
46             $collection_name = $validator->collection_name;
47             $tiny = $validator->tiny;
48              
49             =cut
50              
51             sub document { shift->{document} }
52              
53             sub collection_name { shift->{collection_name} }
54              
55             sub tiny { shift->{tiny} }
56              
57             =head2 has_error
58              
59             $validator->has_error && die;
60              
61             =cut
62              
63             sub has_error { @{shift->{errors}} }
64              
65             =head2 set_error
66              
67             $validator->set_error(
68             $name => [
69             'error-code','message',
70             ]
71             );
72              
73             =cut
74              
75             sub set_error {
76             my $self = shift;
77             validate_pos(
78             @_,
79             1,
80             { type => ARRAYREF }
81             );
82             my $field = shift;
83             my $error = shift;
84             my ($code,$message) = @{$error};
85              
86             my %error = (
87             collection => $self->collection_name,
88             field => $field,
89             code => $code || 'nocode',
90             message => $message || (sprintf "fail: %s",$code)
91             );
92             push @{$self->{errors}},\%error;
93             }
94              
95             =head2 errors
96              
97             # erros: [{ field => 'field1', code => 'errorcode', message => 'message1' },,,]
98             @erros = $validator->erros;
99            
100             @fields = $validator->errors('field');
101             @error_code = $validator->errors('code');
102             @error_message = $validator->errors('message');
103              
104             =cut
105              
106             sub errors {
107             my $self = shift;
108             my $field = shift; # list field(field,code,message)
109             if ($field) {
110             return map { $_->{$field} } @{$self->{errors}};
111             }
112             return wantarray ? @{$self->{errors}} : $self->{errors};
113             }
114              
115             =head2 check
116              
117             # no_validate: bool
118             # state: [insert,update]
119             $validator->check($opt);
120              
121             =cut
122              
123             sub check {
124             my $self = shift;
125             my $opt = shift;
126              
127             return $self if $opt->{no_validate};
128              
129             my $c_class = util_document_class($self->collection_name, ref $self->tiny || $self->tiny );
130             my $document = $self->document;
131             my $field = $c_class->field;
132              
133             my $all_fields = { map { $_ => 1 } $field->list };
134             my @fail_fields = grep { ! $all_fields->{$_} } keys %{$document};
135             for (@fail_fields) {
136             $self->set_error(
137             $_ => ['not_field', (sprintf "%s is not field",$_)]
138             );
139             }
140              
141             if ($opt->{state} eq 'insert') {
142              
143             for my $name ($field->list('REQUIRED')) {
144             unless (exists $document->{$name}) {
145             $self->set_error(
146             $name => [
147             'required',(sprintf "%s is required",$name)
148             ]
149             );
150             }
151             }
152              
153             for my $name ($field->list) {
154             unless (exists $document->{$name}) {
155             $document->{$name} = undef;
156             }
157             }
158             }
159              
160             for my $name (keys %$document) {
161             for my $attr ( @{ $field->get($name) || [] } ) {
162             my $func = $attr->{callback};
163             my ($status,$ret) = $func->($document->{$name}, $self->tiny, $opt);
164             $ret ||= {};
165             validate_with(
166             params => $ret,
167             spec => {
168             message => 0,
169             target => 0,
170             }
171             );
172              
173             if (!$status) {
174             $self->set_error(
175             $name => [$attr->{name},$ret->{message}]
176             )
177             } else {
178             $document->{$name} = $ret->{target} if defined $ret->{target};
179             }
180             }
181             }
182             $self->{document} = $document;
183             return $self;
184             }
185              
186             1;
187             __END__