File Coverage

blib/lib/Data/Transpose/Validator.pm
Criterion Covered Total %
statement 263 265 99.2
branch 108 130 83.0
condition 37 61 60.6
subroutine 34 34 100.0
pod 15 15 100.0
total 457 505 90.5


line stmt bran cond sub pod time code
1             package Data::Transpose::Validator;
2              
3 11     11   55692 use strict;
  11         12  
  11         542  
4 11     11   31 use warnings;
  11         9  
  11         192  
5 11     11   4431 use Module::Load;
  11         8312  
  11         49  
6 11     11   4454 use Try::Tiny;
  11         16438  
  11         503  
7             # use Data::Dumper;
8 11     11   3577 use Data::Transpose::Validator::Subrefs;
  11         23  
  11         318  
9 11     11   3984 use Data::Transpose::Validator::Group;
  11         17  
  11         285  
10 11     11   3754 use Data::Transpose::Iterator::Errors;
  11         18  
  11         284  
11              
12 11     11   47 use Moo;
  11         11  
  11         26  
13 11     11   1920 use MooX::Types::MooseLike::Base qw(:all);
  11         11  
  11         2597  
14 11     11   46 use namespace::clean;
  11         10  
  11         50  
15              
16             =head1 NAME
17              
18             Data::Transpose::Validator - Filter and validate data.
19              
20             =head1 SYNOPSIS
21              
22             use Data::Transpose::Validator;
23             my $dtv = Data::Transpose::Validator->new();
24             $dtv->prepare(email => {validator => 'EmailValid',
25             required => 1},
26             password => {validator => 'PasswordPolicy',
27             required => 1}
28             );
29            
30             my $form = {
31             email => "aklasdfasdf",
32             password => "1234"
33             };
34            
35             my $clean = $dtv->transpose($form);
36             if ($clean) {
37             # the validator says it's valid, and the hashref $clean is validated
38             # $clean is the validated hash
39             } else {
40             my $errors = $dtv->errors; # arrayref with the errors
41             # old data
42             my $invalid_but_filtered = $dtv->transposed_data; # hashref with the data
43             }
44              
45             =head1 DESCRIPTION
46              
47             This module provides an interface to validate and filter hashrefs,
48             usually (but not necessarily) from HTML forms.
49              
50             =head1 METHODS
51              
52              
53             =head2 new
54              
55             The constructor. It accepts a hash as argument, with options:
56              
57             C: strip leading and trailing whitespace from strings (default: true)
58              
59             C: collapse all the consecutive whitespace
60             characters into a single space. This basically will do a C
61             against the value, so will remove all newlines and tabs as well.
62             Default is false.
63              
64             C: require all the fields of the schema (default: false)
65              
66             C: what to do if other fields, not present in the schema, are passed.
67              
68             =over 4
69              
70             C: The transposing routine will die with a message stating the unknown fields
71              
72             C: The routine will accept them and return them in the validated hash
73              
74             C: The routine will ignore them and not return them in the validated hash. This is the default.
75              
76             =back
77              
78             C: what to do if an optional field is missing
79              
80             =over 4
81              
82             C: do nothing, don't add to the returning hash the missing keys. This is the default.
83              
84             C: add the key with the C value
85              
86             C: set it to the empty string;
87              
88             =back
89              
90             =cut
91              
92             has stripwhite => (is => 'rw',
93             isa => Bool,
94             default => sub { 1 });
95              
96             has collapse_whitespace => (is => 'rw',
97             isa => Bool,
98             default => sub { 0 });
99              
100             has requireall => (is => 'rw',
101             isa => Bool,
102             default => sub { 0 });
103              
104             has unknown => (is => 'rw',
105             isa => Enum[qw/skip fail pass/],
106             default => sub { 'skip' });
107              
108             has missing => (is => 'rw',
109             isa => Enum[qw/pass undefine empty/],
110             default => sub { 'pass' });
111              
112             has success => (is => 'rwp',
113             isa => Maybe[Bool],
114             );
115              
116             has errors_iterator => (is => 'ro',
117             default => sub {
118             Data::Transpose::Iterator::Errors->new;
119             });
120              
121             has _fields => (is => 'rw',
122             isa => HashRef,
123             default => sub { {} });
124              
125             has _ordering => (is => 'rw',
126             isa => ArrayRef,
127             default => sub { [] });
128              
129             has transposed_data => (is => 'rwp',
130             isa => Maybe[HashRef]);
131              
132             has groups => (is => 'rwp',
133             isa => ArrayRef,
134             default => sub { [] });
135              
136              
137             =head2 option($option, [ $value ]);
138              
139             Accessor to the options set. With an optional argument, set that option.
140              
141             $dtv->option("requireall"); # get
142             $dtv->option(requireall => 1); # set
143              
144             This is another way to say $dtv->requireall(1);
145              
146             =cut
147              
148             sub option {
149 1060     1060 1 3561 my ($self, $key, $value) = @_;
150 1060 50       1349 return unless $key;
151 1060         1178 my %supported = map { $_ => 1 } $self->options;
  5300         5922  
152             die "Bad option $key, should be one of " . join(" ", $self->options)
153 1060 50       1961 unless $supported{$key};
154 1060 100       1322 if (defined $value) {
155 3         70 $self->$key($value);
156             }
157 1060         14120 return $self->$key;
158             }
159              
160             =head2 option_for_field($option, $field)
161              
162             Accessor to get the option for this particular field. First it looks
163             into the fields options, then into the global ones, returning the
164             first defined value.
165              
166             $dtv->option(email => "stripwhite");
167              
168             =cut
169              
170             sub option_for_field {
171 581     581 1 1451 my ($self, $option, $field) = @_;
172 581 50 33     1708 return unless ($field && $option);
173 581         714 my $hash = $self->field($field)->dtv_options;
174             # print Dumper($hash);
175 581 100 66     13098 if ($hash and (ref($hash) eq 'HASH') and exists $hash->{$option}) {
      66        
176 3         11 return $hash->{$option};
177             }
178 578         799 return $self->option($option) # return the global one;
179             }
180              
181              
182              
183              
184             =head2 options
185              
186             Accessor to get the list of the options
187              
188             $dtv->options;
189             # -> requireall, stripwhite, unknown
190              
191             =cut
192              
193             sub options {
194 1061     1061 1 1480 return qw/collapse_whitespace
195             missing
196             requireall
197             stripwhite
198             unknown
199             /;
200             }
201              
202             =head2 prepare(%hash) or prepare([ {}, {}, ... ])
203              
204             C takes a hash and pass the key/value pairs to C. This
205             method can accept an hash or an array reference. When an arrayref is
206             passed, the output of the errors will keep the provided sorting (this
207             is the only difference).
208              
209             You can call prepare as many times you want before the transposing.
210             Fields are added or replaced, but you could end up with messy errors
211             if you provide duplicates, so please just don't do it (but feel free
212             to add the fields at different time I
213             them>.
214              
215             To prevent bad configuration, as of version 0.0005 overwriting an
216             existing field raises an exception.
217              
218             $dtv->prepare([
219             { name => "country" ,
220             required => 1,
221             },
222             {
223             name => "country2",
224             validator => 'String'},
225             {
226             name => "email",
227             validator => "EmailValid"
228             },
229             ]
230             );
231            
232             or
233              
234             $dtv->prepare(
235             country => {
236             required => 1,
237             },
238             country2 => {
239             validator => "String"
240             }
241             );
242            
243             ## other code here
244              
245             $dtv->prepare(
246             email => {
247             validator => "EmailValid"
248             }
249             );
250              
251              
252             The validator value can be an string, a hashref or a coderef.
253              
254             When a string is passed, the class which will be loaded will be
255             prefixed by C and initialized without
256             arguments.
257              
258             If a coderef is passed as value of validator, a new object
259             L is created, with the coderef as
260             validator.
261              
262             If a hashref is passed as value of validator, it must contains the key
263             C and optionally C as an hashref. As with the string,
264             the class will be prefixed by C, unless
265             you pass the C key set to a true value.
266              
267              
268             $dtv->prepare(
269             email => {
270             validator => "EmailValid",
271             },
272            
273             # ditto
274             email2 => {
275             validator => {
276             class => "EmailValid",
277             }
278             },
279            
280             # tritto
281             email3 => {
282             validator => {
283             class => "Data::Transpose::Validator::EmailValid",
284             absolute => 1,
285             }
286             },
287              
288             # something more elaborate
289             password => {
290             validator => {
291             class => PasswordPolicy,
292             options => {
293             minlength => 10,
294             maxlength => 50,
295             disabled => {
296             username => 1,
297             }
298             }
299             }
300             }
301             );
302            
303             =head3 Groups
304              
305             You can set the groups either calling C (see below) or with
306             C, using the validator C with C.
307              
308             Using an arrayref:
309              
310             $dtv->prepare([
311             {
312             name => 'password',
313             required => 1,
314             },
315             {
316             name => 'confirm_password',
317             required => 1,
318             },
319             {
320             name => 'passwords',
321             validator => 'Group',
322             fields => [
323             qw/password confirm_password/,
324             ],
325             equal => 1,
326             },
327             ]
328             );
329              
330             Or using an hash
331              
332             $dtv->prepare(password => { required => 1 },
333             confirm_password => { required => 1 },
334             passwords_matching => {
335             validator => 'Group',
336             fields => [ "password", "confirm_password" ]
337             });
338              
339             By default, if a group is set, it will be checked if all the fields
340             match. So using the above schema, you'll get:
341              
342             ok $dtv->transpose({ password => "a", confirm_password => "a" });
343             ok !$dtv->transpose({ password => "a", confirm_password => "b" });
344              
345              
346             =head3 Bundled classes
347              
348             Each class has its own documentation for the available options. The
349             options are passed to the C constructor of the validator's class.
350              
351             =over 4
352              
353             =item CreditCard
354              
355             See L
356              
357             Options: C and C
358              
359             =item EmailValid
360              
361             See L (no special options)
362              
363             =item NumericRange
364              
365             See L
366              
367             Options: C, C, C
368              
369             =item PasswordPolicy
370              
371             See L (plenty of options, refers to
372             the documentation).
373              
374             =item Set
375              
376             See L.
377              
378             Options: C pointing to an arrayref and the C boolean
379             (to validate an arrayref).
380              
381             =item String
382              
383             See L (no special options).
384              
385             =item URL
386              
387             See L (no special options).
388              
389             =back
390              
391             =cut
392              
393             sub prepare {
394 52     52 1 3202 my $self = shift;
395             # groups should be processed at the end, because, expecially if an
396             # hash is passed, they could be processed before the fields are
397             # created.
398 52         60 my @groups;
399 52 100       115 if (@_ == 1) {
400             # we have an array;
401 33         28 my $arrayref = shift;
402 33 50       81 die qq{Wrong usage! If you pass a single argument, must be a arrayref\n"}
403             unless (ref($arrayref) eq 'ARRAY');
404 33         51 foreach my $field (@$arrayref) {
405             # defer the group building
406 251 50 66     1430 if (exists $field->{validator} and $field->{validator}) {
407 246 100       438 if ($field->{validator} eq 'Group') {
408 5         6 push @groups, $field;
409 5         6 next;
410             }
411             }
412 243         211 my $fieldname = $field->{name};
413 243 100       312 die qq{Wrong usage! When an array is passed, "name" must be set!}
414             unless $fieldname;
415 242         303 $self->field($fieldname, $field);
416             }
417             }
418             else {
419 19         46 my %fields = @_;
420 19         76 while (my ($k, $v) = each %fields) {
421 65 100 100     604 if (ref($v)
      66        
      100        
422             and ref($v) eq 'HASH'
423             and exists $v->{validator}
424             and $v->{validator} eq 'Group') {
425 3         10 my $grp = { %$v };
426 3         6 $grp->{name} = $k;
427 3         5 push @groups, $grp;
428 3         10 next;
429             }
430 62         109 $self->field($k, $v);
431             }
432             }
433             # fields are fine, build the groups
434             # in the configuration we can't have objects
435 44         280 foreach my $g (@groups) {
436 8 100       19 die "Missing group name" unless $g->{name};
437 7 100       22 die "Missing fields for $g->{name} group!" unless $g->{fields};
438 6         6 my @gfields;
439 6         6 foreach my $f (@{ $g->{fields} }) {
  6         11  
440 12         16 my $obj = $self->field($f);
441 12 100       57 die "Couldn't retrieve field object for group $g->{name}, field $f"
442             unless $obj;
443 11         13 push @gfields, $obj;
444             }
445 5 50       11 die "No fields found for group $g->{name}" unless @gfields;
446             # build the group
447 5         14 my $group_obj = $self->group($g->{name}, @gfields);
448             # and now loops over the other keys and try to call the methods.
449             # say ->equal(0)
450 5         12 my %skip = (
451             name => 1,
452             fields => 1,
453             validator => 1,
454             );
455 5         14 foreach my $method (keys %$g) {
456 19 100       130 next if $skip{$method};
457             # e.g $group_obj->equal(1)
458 4         58 $group_obj->$method($g->{$method});
459             }
460             }
461             }
462              
463             =head2 field($field)
464              
465             This accessor sets the various fields and their options. It's intended
466             to be used only internally, but you can add individual fields with it
467              
468             $dtv->field(email => { required => 1 });
469              
470             If the second argument is a string, it is assumed as the validator name. E.g.
471              
472             $dtv->field(email => 'EmailValid');
473              
474             This by itself use the EmailValid with the default settings. If you
475             want fine control you need to pass an hashref. Also note that unless
476             you specified C as true in the constructor, you need to
477             set the require.
478              
479             So these syntaxes do the same:
480              
481             $dtv->field(email => { required => 1,
482             validator => 'EmailValid',
483             });
484             $dtv->field(email => 'EmailValid')->required(1);
485              
486             With 1 argument retrieves the object responsible for the validation of
487             that field, so you can call methods on them:
488              
489             $dtv->field(email => { required => 0 })->required(1);
490             $dtv->field('email')->required # return true
491              
492             You can also pass options for the validator, e.g.:
493              
494             $dtv->field('month' => { validator => 'NumericRange',
495             options => {
496             min => 1,
497             max => 12,
498             integer => 1
499             },
500             });
501              
502             WARNING: Earlier versions of this method without any argument would
503             have retrieved the whole structure. Now it dies instead.
504              
505             =cut
506              
507             sub field {
508 1441     1441 1 3083 my ($self, $field, $args) = @_;
509             # initialize
510 1441 100       1764 unless ($field) {
511 1         2 my $deprecation =<<'DEATH';
512             As of version 0.0005, the retrieval of the whole structure without
513             field argument is deprecated, as fields return an object instead!
514             DEATH
515 1 50       6 die $deprecation unless $field;
516             }
517              
518 1440 100       1694 if ($args) {
519 319 100       440 unless (ref($field) eq '') {
520 1         8 die "Wrong usage, $field must be a string with the field name!\n"
521             };
522              
523             # if a string is passed, consider it as a validator
524 318 100       437 unless (ref($args)) {
525 6         15 $args = { validator => $args };
526             }
527             # validate the args and store them
528 318 100       407 if (ref($args) eq 'HASH') {
529 316         719 $self->_field_args_are_valid($field => keys %$args);
530 314         521 my $obj = $self->_build_object($field, $args);
531             # prevent to mix up rules.
532 312 100       3996 if ($self->_fields->{$field}) {
533 1         20 die "$field has already a validation rule!\n";
534             }
535 311         8537 $self->_fields->{$field} = $obj;
536             }
537             else {
538             # raise exception to prevent bad configurations
539 2         18 die "Argument for $field must be an hashref, got $args!\n";
540             }
541             # add the field to the list
542 311         1324 $self->_sorted_fields($field);
543             }
544 1432         18706 return $self->_fields->{$field};
545             }
546              
547             sub _sorted_fields {
548 381     381   668 my ($self, $field) = @_;
549 381 100       593 if ($field) {
550 311         222 push @{$self->_ordering}, $field;
  311         3709  
551             }
552 381         4888 return @{$self->_ordering};
  381         4665  
553             }
554              
555             # return the sorted list of fields
556              
557             =head2 group (name => $field1, $field2, $field3, ...)
558              
559             Create a named group of fields and schedule them for validation.
560              
561             The logic is:
562              
563             First, the individual fields are normally checked according to the
564             rules provided with C or C.
565              
566             If they pass the test, the group operation are checked.
567              
568             Group by itself returns a L object,
569             so you can call methods on them to set the rules.
570              
571             E.g. $self->group("passwords")->equal(1) # not needed it's the default
572              
573             =head2 groups
574              
575             Retrieve the list of the group objects scheduled for validation
576              
577             =cut
578              
579             sub group {
580 11     11 1 243 my ($self, $name, @objects) = @_;
581 11 50 33     49 die "Wrong usage, first argument must be a string!" unless $name && !ref($name);
582 11 100       23 if (@objects) {
583 8         5 my @group;
584 8         14 foreach my $field (@objects) {
585 16         16 my $obj = $field;
586 16 100       25 unless (ref($field)) {
587 6         7 $obj = $self->field($field);
588             }
589             # if we couldn't retrieve the field, die, we can't build the group
590 16 50       40 die "$obj could not be retrieved! Too early for this?" unless $obj;
591 16         18 push @group, $obj;
592             }
593 8         114 my $group = Data::Transpose::Validator::Group->new(name => $name,
594             fields => \@group);
595              
596 8         201 push @{ $self->groups }, $group;
  8         28  
597             # store it in the dtv object and return it
598 8         33 return $group;
599             }
600             # retrieve
601 3         4 foreach my $g (@{ $self->groups }) {
  3         8  
602 3 50       11 if ($g->name eq $name) {
603 3         58 return $g;
604             }
605             }
606 0         0 return;
607             }
608              
609              
610             =head2 transpose
611              
612             The main method. It validates the hash and return a validated one or
613             nothing if there were errors.
614              
615             =cut
616              
617              
618              
619              
620             sub transpose {
621 69     69 1 7519 my ($self, $hash) = @_;
622 69 50 33     361 die "Wrong usage! A hashref is needed as argument for transpose method!\n"
623             unless ($hash and (ref($hash) eq 'HASH'));
624 69         141 $self->reset_self;
625              
626              
627 69         213 my (%output, %status);
628              
629             # remember which keys we had processed
630 69         305 $status{$_} = 1 for keys %$hash;
631              
632             # we loop over the schema
633 69         132 foreach my $field ($self->_sorted_fields) {
634 357         809 my $obj = $self->field($field);
635 357         1809 $obj->reset_dtv_value;
636 357         233 my $value;
637             # the incoming hash could not have such a field
638 357 100       498 if (exists $status{$field}) {
639              
640 220         245 delete $status{$field};
641 220         227 $value = $hash->{$field};
642              
643             # strip white if the option says so
644 220 100       326 if ($self->option_for_field('stripwhite', $field)) {
645 219         5022 $value = $self->_strip_white($value);
646             }
647 220 100       303 if ($self->option_for_field(collapse_whitespace => $field)) {
648 4         22 $value = $self->_collapse_white($value);
649             }
650             # then we set it in the ouput, it could be undef;
651 220         4870 $output{$field} = $value;
652             }
653             else {
654 137         185 my $missingopt = $self->option_for_field('missing', $field);
655             # basically, with "pass", the default, we don't store the
656             # value
657 137 100       3182 if ($missingopt eq 'undefine') {
    100          
658 3         2 $value = undef;
659 3         6 $output{$field} = $value;
660             }
661             elsif ($missingopt eq 'empty') {
662 3         4 $value = "";
663 3         6 $output{$field} = $value;
664             }
665             }
666            
667              
668             # if it's required and the only thing provided is "" or undef,
669             # we set an error
670 357 50 66     1767 if ((not defined $value) or
      66        
      33        
      66        
      33        
      33        
671             ((ref($value) eq '') and $value eq '') or
672             ((ref($value) eq 'HASH') and (not %$value)) or
673             ((ref($value) eq 'ARRAY') and (not @$value))) {
674              
675 155 100       224 if ($self->field_is_required($field)) {
676             # set the error list to ["required" => "Human readable" ];
677 23         459 $self->errors($field,
678             [
679             [ "required" => "Missing required field $field" ]
680             ]
681             );
682             }
683 155         2872 next;
684             }
685             # we have something, validate it
686 202 100       490 unless ($obj->is_valid($value)) {
687 23         57 my @errors = $obj->error;
688 23         59 $self->errors($field, \@errors)
689             }
690 202         3076 $obj->dtv_value($value);
691             }
692              
693              
694             # if there is no error, check the groups
695 69 100       155 unless ($self->errors) {
696 36         29 foreach my $group (@{$self->groups}) {
  36         104  
697 14 100       42 unless ($group->is_valid) {
698 6         13 my @errors = $group->error;
699 6         16 $self->errors($group->name, \@errors);
700             }
701             }
702             }
703              
704             # now the filtering loop has ended. See if we have still things in the hash.
705 69 100       282 if (keys %status) {
706 5         19 my $unknown = $self->option('unknown');
707 5 100       884 if ($unknown eq 'pass') {
    100          
708 1         3 for (keys %status) {
709 1         2 $output{$_} = $hash->{$_};
710             }
711             } elsif ($unknown eq 'fail') {
712 1         9 die "Unknown fields in input: ", join(',', keys %status), "\n";
713             }
714             }
715             # remember what we did
716 68         829 $self->_set_transposed_data(\%output);
717              
718 68 100       6792 if ($self->errors) {
719             # return undef if we have errors
720 39         636 $self->_set_success(0);
721 39         1708 return;
722             }
723              
724             # return the data
725 29         387 $self->_set_success(1);
726              
727 29         1321 return $self->transposed_data;
728             }
729              
730             =head2 success
731              
732             Returns true on success, 0 on failure and undef validation
733             didn't take place.
734              
735             =head2 transposed_data
736              
737             Accessor to the transposed hash. This is handy if you want to retrieve
738             the filtered data after a failure (because C will return
739             undef in that case).
740              
741             =head2 errors
742              
743             Accessor to set or retrieve the errors (returned as an arrayref of
744             hashes). Each element has the key C set to the fieldname and
745             the key C holds the error list. This, in turn, is a list
746             of arrays, where the first element is the error code, and the second
747             the human format set by the module (in English). See the method belows
748             for a more accessible way for the errors.
749              
750             =cut
751              
752             sub errors {
753 229     229 1 9669 my ($self, $field, $error) = @_;
754 229 100 66     545 if ($error and $field) {
755 52         231 $self->errors_iterator->append({field => $field,
756             errors => $error});
757             }
758              
759 229 100       3329 if ($self->errors_iterator->count) {
760 158         3578 return $self->errors_iterator->records;
761             }
762              
763 71         2756 return;
764             }
765              
766             =head2 errors_iterator
767              
768             Returns error iterator.
769              
770             =cut
771              
772             =head2 errors_hash
773              
774             Return an hashref where each key is the name of the error field, and
775             the value is an arrayref of hashrefs with two keys, C and
776             C.
777              
778             Example of the returned hash:
779              
780             {
781             year => [
782             {
783             value => 'Not a number',
784             name => 'notanumber',
785             },
786             {
787             name => 'notinteger',
788             value => 'Not an integer',
789             }
790             ],
791             mail => [
792             {
793             value => 'Missing required field mail',
794             name => 'required',
795             }
796             ],
797             }
798              
799             =cut
800              
801             sub errors_hash {
802 1     1 1 5 my ( $self ) = @_;
803              
804 1         5 return $self->errors_iterator->errors_hash;
805             }
806              
807             sub _reset_errors {
808 69     69   1363 shift->errors_iterator->records([]);
809             }
810              
811             =head2 faulty_fields
812              
813             Accessor to the list of fields where the validator detected errors.
814              
815             =cut
816              
817             sub faulty_fields {
818 24     24 1 18 my $self = shift;
819 24         18 my @ffs;
820              
821 24         49 while (my $err = $self->errors_iterator->next) {
822 34         193 push @ffs, $err->{field};
823             }
824              
825 24         132 $self->errors_iterator->reset;
826              
827 24         46 return @ffs;
828             }
829              
830             =head2 errors_as_hashref_for_humans
831              
832             Accessor to get a list of the failed checks. It returns an hashref
833             with the keys set to the faulty fields, and the value as an arrayref
834             to a list of the error messages.
835              
836             =cut
837              
838             sub errors_as_hashref_for_humans {
839 24     24 1 22 my $self = shift;
840 24         40 return $self->_get_errors_field(1);
841             }
842              
843             =head2 errors_as_hashref
844              
845             Same as above, but for machine processing. It returns the lists of
846             error codes as values.
847              
848             =cut
849              
850             sub errors_as_hashref {
851 14     14 1 5673 my $self = shift;
852 14         26 return $self->_get_errors_field(0);
853             }
854              
855              
856             =head2 packed_errors($fieldsep, $separator)
857              
858             As convenience, this method will join the human readable strings using
859             the second argument, and introduced by the name of the field
860             concatenated to the first argument. Example with the defaults (colon
861             and comma):
862              
863             password: Wrong length, No special characters, No letters in the
864             password, Found common password, Not enough different characters,
865             Found common patterns: 1234
866             country: My error
867             email2: rfc822
868              
869             In scalar context it returns a string, in list context returns the
870             errors as an array, so you still can process it easily.
871              
872             =cut
873              
874              
875             sub packed_errors {
876 24     24 1 990 my $self = shift;
877 24   50     100 my $fieldsep = shift || ": ";
878 24   50     61 my $separator = shift || ", ";
879              
880 24         48 my $errs = $self->errors_as_hashref_for_humans;
881 24         21 my @out;
882             # print Dumper($errs);
883 24         34 foreach my $k ($self->faulty_fields) {
884 34         41 push @out, $k . $fieldsep . join($separator, @{$errs->{$k}});
  34         74  
885             }
886 24 100       232 return wantarray ? @out : join("\n", @out);
887             }
888              
889              
890             sub _get_errors_field {
891 38     38   35 my $self = shift;
892 38         32 my $i = shift;
893 38         29 my %errors;
894              
895 38         136 while (my $err = $self->errors_iterator->next) {
896 52         271 my $f = $err->{field};
897 52 50       124 $errors{$f} = [] unless exists $errors{$f};
898 52         46 foreach my $string (@{$err->{errors}}) {
  52         92  
899 59         44 push @{$errors{$f}}, $string->[$i];
  59         209  
900             }
901             }
902              
903 38         283 $self->errors_iterator->reset;
904              
905 38         80 return \%errors;
906             }
907              
908             =head2 field_is_required($field)
909              
910             Check if the field is required. Return true unconditionally if the
911             option C is set. If not, look into the schema and return
912             the value provided in the schema.
913              
914             =cut
915              
916              
917             sub field_is_required {
918 159     159 1 564 my ($self, $field) = @_;
919 159 50       226 return unless defined $field;
920 159 100       181 return 1 if $self->option("requireall");
921 158         789 return $self->field($field)->required;
922             }
923              
924             sub _build_object {
925 314     314   292 my ($self, $name, $params) = @_;
926 314         268 my $validator = $params->{validator};
927 314         266 my $type = ref($validator);
928 314         209 my $obj;
929             # print "Building $name... " . Dumper($params);
930             # if we got a string, the class is Data::Transpose::$string
931 314 100       437 if ($type eq 'CODE') {
932 5         55 $obj = Data::Transpose::Validator::Subrefs->new($validator);
933             }
934             else {
935 309         196 my ($class, $classoptions);
936 309 100       380 if ($type eq '') {
    50          
937 225   100     388 my $module = $validator || "Base";
938 225 50       297 die "No group is allowed here" if $module eq 'Group';
939 225         321 $class = __PACKAGE__ . '::' . $module;
940             # use options from params
941 225   100     723 $classoptions = $params->{options} || {};
942             }
943             elsif ($type eq 'HASH') {
944 84         86 $class = $validator->{class};
945 84 50       125 die "Missing class for $name!" unless $class;
946 84 100       119 unless ($validator->{absolute}) {
947 60 50       78 die "No group is allowed here" if $class eq 'Group';
948 60         101 $class = __PACKAGE__ . '::' . $class;
949             }
950 84   50     141 $classoptions = $validator->{options} || {};
951             # print Dumper($classoptions);
952             }
953             else {
954 0         0 die "Wrong usage. Pass a string, an hashref or a sub!\n";
955             }
956             # lazy loading, avoiding to load the same class twice
957             try {
958 309     309   11971 $obj = $class->new(%$classoptions);
959             } catch {
960 22     22   214 load $class;
961 20         354 $obj = $class->new(%$classoptions);
962 309         1328 };
963             }
964 312 100       10743 if ($params->{options}) {
965 6         70 $obj->dtv_options($params->{options});
966             }
967 312 100 66     1556 if ($self->option('requireall') || $params->{required}) {
968 141         4852 $obj->required(1);
969             }
970 312         9451 return $obj;
971             }
972              
973             sub _strip_white {
974 219     219   233 my ($self, $string) = @_;
975 219 50       324 return unless defined $string;
976 219 50       331 return $string unless (ref($string) eq ''); # scalars only
977 219 100       305 return "" if ($string eq ''); # return the empty string
978 207         378 $string =~ s/^\s+//;
979 207         367 $string =~ s/\s+$//;
980 207         293 return $string;
981             }
982              
983             sub _collapse_white {
984 4     4   6 my ($self, $string) = @_;
985 4 50       8 return unless defined $string;
986 4 50       7 return $string unless (ref($string) eq '');
987             # convert all
988 4         14 $string =~ s/\s+/ /gs;
989 4         8 return $string;
990             }
991              
992              
993             sub _field_args_are_valid {
994 316     316   387 my ($self, $field, @keys) = @_;
995 316         676 my %valid = (
996             validator => 1,
997             name => 1,
998             required => 1,
999             options => 1,
1000             );
1001 316         388 foreach my $k (@keys) {
1002 666 100       1210 unless ($valid{$k}) {
1003 2         17 die "$field has unrecognized option $k!\n";
1004             }
1005             }
1006             }
1007              
1008              
1009             =head2 reset_self
1010              
1011             Clear all the internal data stored during validations, to make the
1012             reusing of the transposing possible.
1013              
1014             This is called by C before doing any other operation
1015              
1016             =cut
1017              
1018             sub reset_self {
1019 69     69 1 67 my $self = shift;
1020 69         1068 $self->_set_success(undef);
1021 69         6672 $self->_reset_errors;
1022             }
1023              
1024             1;
1025              
1026             __END__