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   92096 use strict;
  11         24  
  11         378  
4 11     11   91 use warnings;
  11         18  
  11         359  
5 11     11   7810 use Module::Load;
  11         13665  
  11         73  
6 11     11   7262 use Try::Tiny;
  11         15695  
  11         777  
7             # use Data::Dumper;
8 11     11   5427 use Data::Transpose::Validator::Subrefs;
  11         40  
  11         417  
9 11     11   5792 use Data::Transpose::Validator::Group;
  11         29  
  11         439  
10 11     11   5933 use Data::Transpose::Iterator::Errors;
  11         27  
  11         422  
11              
12 11     11   72 use Moo;
  11         14  
  11         43  
13 11     11   2991 use MooX::Types::MooseLike::Base qw(:all);
  11         22  
  11         4314  
14 11     11   62 use namespace::clean;
  11         14  
  11         90  
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 6640 my ($self, $key, $value) = @_;
150 1060 50       2150 return unless $key;
151 1060         1794 my %supported = map { $_ => 1 } $self->options;
  5300         9314  
152             die "Bad option $key, should be one of " . join(" ", $self->options)
153 1060 50       2937 unless $supported{$key};
154 1060 100       1993 if (defined $value) {
155 3         111 $self->$key($value);
156             }
157 1060         24475 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 2890 my ($self, $option, $field) = @_;
172 581 50 33     2741 return unless ($field && $option);
173 581         1006 my $hash = $self->field($field)->dtv_options;
174             # print Dumper($hash);
175 581 100 66     21218 if ($hash and (ref($hash) eq 'HASH') and exists $hash->{$option}) {
      66        
176 3         17 return $hash->{$option};
177             }
178 578         1184 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 2327 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 5864 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         88 my @groups;
399 52 100       172 if (@_ == 1) {
400             # we have an array;
401 33         61 my $arrayref = shift;
402 33 50       140 die qq{Wrong usage! If you pass a single argument, must be a arrayref\n"}
403             unless (ref($arrayref) eq 'ARRAY');
404 33         92 foreach my $field (@$arrayref) {
405             # defer the group building
406 251 50 66     2201 if (exists $field->{validator} and $field->{validator}) {
407 246 100       689 if ($field->{validator} eq 'Group') {
408 5         12 push @groups, $field;
409 5         15 next;
410             }
411             }
412 243         327 my $fieldname = $field->{name};
413 243 100       460 die qq{Wrong usage! When an array is passed, "name" must be set!}
414             unless $fieldname;
415 242         585 $self->field($fieldname, $field);
416             }
417             }
418             else {
419 19         62 my %fields = @_;
420 19         93 while (my ($k, $v) = each %fields) {
421 65 100 100     793 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         7 $grp->{name} = $k;
427 3         5 push @groups, $grp;
428 3         11 next;
429             }
430 62         123 $self->field($k, $v);
431             }
432             }
433             # fields are fine, build the groups
434             # in the configuration we can't have objects
435 44         485 foreach my $g (@groups) {
436 8 100       33 die "Missing group name" unless $g->{name};
437 7 100       38 die "Missing fields for $g->{name} group!" unless $g->{fields};
438 6         8 my @gfields;
439 6         9 foreach my $f (@{ $g->{fields} }) {
  6         16  
440 12         29 my $obj = $self->field($f);
441 12 100       93 die "Couldn't retrieve field object for group $g->{name}, field $f"
442             unless $obj;
443 11         23 push @gfields, $obj;
444             }
445 5 50       21 die "No fields found for group $g->{name}" unless @gfields;
446             # build the group
447 5         19 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         21 my %skip = (
451             name => 1,
452             fields => 1,
453             validator => 1,
454             );
455 5         19 foreach my $method (keys %$g) {
456 16 100       122 next if $skip{$method};
457             # e.g $group_obj->equal(1)
458 4         89 $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 5192 my ($self, $field, $args) = @_;
509             # initialize
510 1441 100       2521 unless ($field) {
511 1         4 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       12 die $deprecation unless $field;
516             }
517              
518 1440 100       2392 if ($args) {
519 319 100       678 unless (ref($field) eq '') {
520 1         11 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       682 unless (ref($args)) {
525 6         20 $args = { validator => $args };
526             }
527             # validate the args and store them
528 318 100       595 if (ref($args) eq 'HASH') {
529 316         1267 $self->_field_args_are_valid($field => keys %$args);
530 314         741 my $obj = $self->_build_object($field, $args);
531             # prevent to mix up rules.
532 312 100       6327 if ($self->_fields->{$field}) {
533 1         31 die "$field has already a validation rule!\n";
534             }
535 311         13104 $self->_fields->{$field} = $obj;
536             }
537             else {
538             # raise exception to prevent bad configurations
539 2         19 die "Argument for $field must be an hashref, got $args!\n";
540             }
541             # add the field to the list
542 311         2101 $self->_sorted_fields($field);
543             }
544 1432         31264 return $self->_fields->{$field};
545             }
546              
547             sub _sorted_fields {
548 381     381   1134 my ($self, $field) = @_;
549 381 100       803 if ($field) {
550 311         307 push @{$self->_ordering}, $field;
  311         6193  
551             }
552 381         7313 return @{$self->_ordering};
  381         7647  
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 889 my ($self, $name, @objects) = @_;
581 11 50 33     76 die "Wrong usage, first argument must be a string!" unless $name && !ref($name);
582 11 100       41 if (@objects) {
583 8         10 my @group;
584 8         22 foreach my $field (@objects) {
585 16         25 my $obj = $field;
586 16 100       40 unless (ref($field)) {
587 6         22 $obj = $self->field($field);
588             }
589             # if we couldn't retrieve the field, die, we can't build the group
590 16 50       74 die "$obj could not be retrieved! Too early for this?" unless $obj;
591 16         37 push @group, $obj;
592             }
593 8         203 my $group = Data::Transpose::Validator::Group->new(name => $name,
594             fields => \@group);
595              
596 8         355 push @{ $self->groups }, $group;
  8         54  
597             # store it in the dtv object and return it
598 8         66 return $group;
599             }
600             # retrieve
601 3         6 foreach my $g (@{ $self->groups }) {
  3         13  
602 3 50       17 if ($g->name eq $name) {
603 3         85 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 15929 my ($self, $hash) = @_;
622 69 50 33     587 die "Wrong usage! A hashref is needed as argument for transpose method!\n"
623             unless ($hash and (ref($hash) eq 'HASH'));
624 69         243 $self->reset_self;
625              
626              
627 69         303 my (%output, %status);
628              
629             # remember which keys we had processed
630 69         472 $status{$_} = 1 for keys %$hash;
631              
632             # we loop over the schema
633 69         234 foreach my $field ($self->_sorted_fields) {
634 357         1306 my $obj = $self->field($field);
635 357         3009 $obj->reset_dtv_value;
636 357         341 my $value;
637             # the incoming hash could not have such a field
638 357 100       786 if (exists $status{$field}) {
639              
640 220         371 delete $status{$field};
641 220         366 $value = $hash->{$field};
642              
643             # strip white if the option says so
644 220 100       532 if ($self->option_for_field('stripwhite', $field)) {
645 219         7735 $value = $self->_strip_white($value);
646             }
647 220 100       487 if ($self->option_for_field(collapse_whitespace => $field)) {
648 4         38 $value = $self->_collapse_white($value);
649             }
650             # then we set it in the ouput, it could be undef;
651 220         7707 $output{$field} = $value;
652             }
653             else {
654 137         308 my $missingopt = $self->option_for_field('missing', $field);
655             # basically, with "pass", the default, we don't store the
656             # value
657 137 100       9374 if ($missingopt eq 'undefine') {
    100          
658 3         3 $value = undef;
659 3         15 $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     2934 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       1918 if ($self->field_is_required($field)) {
676             # set the error list to ["required" => "Human readable" ];
677 23         856 $self->errors($field,
678             [
679             [ "required" => "Missing required field $field" ]
680             ]
681             );
682             }
683 155         4843 next;
684             }
685             # we have something, validate it
686 202 100       792 unless ($obj->is_valid($value)) {
687 23         86 my @errors = $obj->error;
688 23         94 $self->errors($field, \@errors)
689             }
690 202         4868 $obj->dtv_value($value);
691             }
692              
693              
694             # if there is no error, check the groups
695 69 100       262 unless ($self->errors) {
696 36         56 foreach my $group (@{$self->groups}) {
  36         176  
697 14 100       69 unless ($group->is_valid) {
698 6         23 my @errors = $group->error;
699 6         31 $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       489 if (keys %status) {
706 5         14 my $unknown = $self->option('unknown');
707 5 100       1738 if ($unknown eq 'pass') {
    100          
708 1         4 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         1406 $self->_set_transposed_data(\%output);
717              
718 68 100       11213 if ($self->errors) {
719             # return undef if we have errors
720 39         1143 $self->_set_success(0);
721 39         2856 return;
722             }
723              
724             # return the data
725 29         667 $self->_set_success(1);
726              
727 29         2077 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 21177 my ($self, $field, $error) = @_;
754 229 100 66     789 if ($error and $field) {
755 52         432 $self->errors_iterator->append({field => $field,
756             errors => $error});
757             }
758              
759 229 100       5285 if ($self->errors_iterator->count) {
760 158         5709 return $self->errors_iterator->records;
761             }
762              
763 71         4488 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 10 my ( $self ) = @_;
803              
804 1         9 return $self->errors_iterator->errors_hash;
805             }
806              
807             sub _reset_errors {
808 69     69   1687 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 41 my $self = shift;
819 24         33 my @ffs;
820              
821 24         81 while (my $err = $self->errors_iterator->next) {
822 34         388 push @ffs, $err->{field};
823             }
824              
825 24         225 $self->errors_iterator->reset;
826              
827 24         74 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 41 my $self = shift;
840 24         62 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 16961 my $self = shift;
852 14         58 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 2504 my $self = shift;
877 24   50     153 my $fieldsep = shift || ": ";
878 24   50     115 my $separator = shift || ", ";
879              
880 24         77 my $errs = $self->errors_as_hashref_for_humans;
881 24         31 my @out;
882             # print Dumper($errs);
883 24         79 foreach my $k ($self->faulty_fields) {
884 34         84 push @out, $k . $fieldsep . join($separator, @{$errs->{$k}});
  34         138  
885             }
886 24 100       575 return wantarray ? @out : join("\n", @out);
887             }
888              
889              
890             sub _get_errors_field {
891 38     38   56 my $self = shift;
892 38         45 my $i = shift;
893 38         50 my %errors;
894              
895 38         203 while (my $err = $self->errors_iterator->next) {
896 52         401 my $f = $err->{field};
897 52 50       237 $errors{$f} = [] unless exists $errors{$f};
898 52         63 foreach my $string (@{$err->{errors}}) {
  52         155  
899 59         68 push @{$errors{$f}}, $string->[$i];
  59         429  
900             }
901             }
902              
903 38         385 $self->errors_iterator->reset;
904              
905 38         146 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 1196 my ($self, $field) = @_;
919 159 50       354 return unless defined $field;
920 159 100       291 return 1 if $self->option("requireall");
921 158         1446 return $self->field($field)->required;
922             }
923              
924             sub _build_object {
925 314     314   416 my ($self, $name, $params) = @_;
926 314         393 my $validator = $params->{validator};
927 314         376 my $type = ref($validator);
928 314         274 my $obj;
929             # print "Building $name... " . Dumper($params);
930             # if we got a string, the class is Data::Transpose::$string
931 314 100       656 if ($type eq 'CODE') {
932 5         111 $obj = Data::Transpose::Validator::Subrefs->new($validator);
933             }
934             else {
935 309         318 my ($class, $classoptions);
936 309 100       587 if ($type eq '') {
    50          
937 225   100     626 my $module = $validator || "Base";
938 225 50       447 die "No group is allowed here" if $module eq 'Group';
939 225         503 $class = __PACKAGE__ . '::' . $module;
940             # use options from params
941 225   100     1045 $classoptions = $params->{options} || {};
942             }
943             elsif ($type eq 'HASH') {
944 84         147 $class = $validator->{class};
945 84 50       183 die "Missing class for $name!" unless $class;
946 84 100       201 unless ($validator->{absolute}) {
947 60 50       131 die "No group is allowed here" if $class eq 'Group';
948 60         161 $class = __PACKAGE__ . '::' . $class;
949             }
950 84   50     236 $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   16916 $obj = $class->new(%$classoptions);
959             } catch {
960 22     22   317 load $class;
961 20         634 $obj = $class->new(%$classoptions);
962 309         2167 };
963             }
964 312 100       17350 if ($params->{options}) {
965 6         144 $obj->dtv_options($params->{options});
966             }
967 312 100 66     2803 if ($self->option('requireall') || $params->{required}) {
968 141         6849 $obj->required(1);
969             }
970 312         14896 return $obj;
971             }
972              
973             sub _strip_white {
974 219     219   333 my ($self, $string) = @_;
975 219 50       485 return unless defined $string;
976 219 50       513 return $string unless (ref($string) eq ''); # scalars only
977 219 100       489 return "" if ($string eq ''); # return the empty string
978 207         620 $string =~ s/^\s+//;
979 207         579 $string =~ s/\s+$//;
980 207         461 return $string;
981             }
982              
983             sub _collapse_white {
984 4     4   9 my ($self, $string) = @_;
985 4 50       11 return unless defined $string;
986 4 50       14 return $string unless (ref($string) eq '');
987             # convert all
988 4         21 $string =~ s/\s+/ /gs;
989 4         10 return $string;
990             }
991              
992              
993             sub _field_args_are_valid {
994 316     316   597 my ($self, $field, @keys) = @_;
995 316         1099 my %valid = (
996             validator => 1,
997             name => 1,
998             required => 1,
999             options => 1,
1000             );
1001 316         548 foreach my $k (@keys) {
1002 666 100       1773 unless ($valid{$k}) {
1003 2         15 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 106 my $self = shift;
1020 69         1648 $self->_set_success(undef);
1021 69         10985 $self->_reset_errors;
1022             }
1023              
1024             1;
1025              
1026             __END__