File Coverage

lib/CGI/ValidOp/Param.pm
Criterion Covered Total %
statement 99 100 99.0
branch 40 44 90.9
condition 20 24 83.3
subroutine 19 19 100.0
pod 0 11 0.0
total 178 198 89.9


line stmt bran cond sub pod time code
1             package CGI::ValidOp::Param;
2 21     21   61628 use strict;
  21         52  
  21         739  
3 21     21   185 use warnings;
  21         44  
  21         775  
4              
5 21     21   108 use base qw/ CGI::ValidOp::Base /;
  21         39  
  21         4774  
6 21     21   132 use Carp;
  21         42  
  21         1559  
7 21     21   115 use Data::Dumper;
  21         35  
  21         964  
8 21     21   21468 use HTML::Entities;
  21         159017  
  21         8645  
9 21     21   61878 use Storable qw(dclone);
  21         89735  
  21         26060  
10              
11             # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12             sub PROPERTIES {
13             {
14 660     660 0 5249 label => undef,
15             checks => [ qw/ text/ ],
16             required => 0,
17             -error_decoration => undef,
18             tainted => undef,
19             on_error_return => 'undef',
20             }
21             }
22              
23             # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24             sub init {
25 666     666 0 1131 my $self = shift;
26 666         936 my( $args ) = @_;
27              
28             # XXX set_name should raise the error, maybe
29 666 50       3669 $self->set_name( $args )
30             or croak 'Name required in CGI::ValidOp::Param::init().';
31 660         2582 $self->SUPER::init( $args );
32 660 100       2209 $self->required( 1 ) # FIXME hack, not a ::Check; can it be?
33             if grep /^required$/ => $self->checks;
34 660         2638 $self;
35             }
36              
37             # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
38             # treats the empty string '' as undef
39             sub tainted {
40 4186     4186 0 5354 my $self = shift;
41 4186         5254 my( $tainted ) = @_;
42              
43 4186 100       20150 return $self->{ tainted } unless @_;
44 1069         1564 delete $self->{ value };
45 1069 100 100     3892 undef $tainted if defined $tainted and $tainted eq '';
46 1069         3504 $self->{ tainted } = $tainted;
47             }
48              
49             # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
50             # returns validated param
51             # take on_error_return into account
52             sub value {
53 440     440 0 595 my $self = shift;
54 440 100       1194 croak 'Cannot directly set parameter value with CGI::ValidOp::Param::value().'
55             if @_;
56 439         864 $self->validate;
57              
58 439 100 100     1141 return encode_entities( $self->tainted )
59             if $self->errors
60             and $self->on_error_return eq 'encoded';
61              
62 434 100 100     907 return $self->tainted
63             if $self->errors
64             and $self->on_error_return eq 'tainted';
65              
66 433 100       895 return if $self->errors; # 'undef' is the default
67             return $self->{ value }
68 397         2088 }
69              
70             # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
71             # validates $self->{ tainted } against all checks defined for it
72             sub validate {
73 806     806 0 1270 my $self = shift;
74              
75             # empty arrayref means "no checks"
76 806 50 33     2191 return unless $self->checks and $self->checks > 0;
77 806         2000 $self->check_required; # this is a little magic; read its comments
78 806         2297 for my $check_name( $self->checks ) {
79 793 100       2053 next if $check_name eq 'required'; #FIXME nasty special case
80              
81 544         1082 delete $self->{ value }; # we'll set the value later if it's ok
82 544 100 100     1122 if( $self->tainted and $self->tainted =~ /\0/ ) { # if multi-value
83 43         139 for( split /\0/, $self->tainted ) {
84 129         310 my $value = $self->check( $_, $check_name );
85 129 50       423 push @{ $self->{ value }} => $value if defined $value;
  129         557  
86             }
87             }
88             else {
89 501         2323 my $value = $self->check( $self->tainted, $check_name );
90 501 100       2906 $self->{ value } = $value
91             if defined $value;
92             }
93             }
94 806         1982 return;
95             }
96              
97             # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
98             # checks a single value against one check
99             # returns a good value, or adds an error and returns undef
100             sub check {
101 1048     1048 0 3443 my $self = shift;
102 1048         2300 my( $tainted, $check_name ) = @_;
103              
104 1048         2340 my $check = $self->load_check( $check_name );
105 1045         4425 my( $value, $errmsg ) = $check->check( $tainted );
106 1043 100       6246 return $value unless $errmsg;
107              
108 202         694 $self->add_error( $check_name, $errmsg );
109 202         1002 return;
110             }
111              
112             # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
113             # check_string can be any of (e.g.):
114             # foo, foo::bar, foo(2,4), foo::bar(2,4)
115             sub load_check {
116 1054     1054 0 2666 my $self = shift;
117 1054         1376 my( $check_string ) = @_;
118              
119 1054 100 66     5588 croak "Must pass a scalar check name to CGI::ValidOp::Param::load_check()"
120             if !$check_string or ref $check_string;
121              
122             # strip out trailing parens and capture anything inside them as a list
123 1050         2888 ( my $check_name = $check_string ) =~ s/(.*)\((.*)\)/$1/;
124 1050 100       4260 my @params = $2
125             ? split /,/ => $2
126             : undef;
127              
128 1050         3492 my( $package, $method ) = split /::/, $check_name;
129 1050         2658 $package = "CGI::ValidOp::Check::$package";
130 1050         70631 eval "require $package";
131 1050 100       4245 $@ and croak "Failed to require $package in CGI::ValidOp::Param::check(): ". $@;
132              
133 1049         4644 $package->new( $method, @params );
134             }
135              
136             # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
137             # FIXME this should go into ::Check
138             # | $param-> | defined | | RETURNS | | add |
139             # if | required | tainted | then | undef | tainted | and | error? |
140             # |----------|---------| |-------|---------| |--------|
141             # | X | | | X | | | X |
142             # | | | | X | | | |
143             # | X | X | | | X | | |
144             # | | X | | | X | | |
145             sub check_required {
146 806     806 0 1067 my $self = shift;
147              
148 806 100       1518 if( defined $self->tainted ) {
149 719         1425 $self->{ value } = $self->tainted;
150 719         1599 return $self->{ value };
151             }
152 87 100       305 $self->add_error( 'required', '$label is required.' )
153             if $self->required;
154 87         177 return;
155             }
156              
157             # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
158             # returns error if it was added, undef otherwise
159             sub add_error {
160 241     241 0 356 my $self = shift;
161 241         436 my( $check_name, $error ) = @_;
162              
163 241 100 100     1263 return unless $check_name and $error;
164 239         661 $check_name =~ s/(.*)\((.*)\)/$1/; # removes trailing parens
165 239         1025 $self->{ errors }{ $check_name } = $error;
166             }
167              
168             # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
169             # copy constructor.
170             sub clone {
171 40     40 0 3042 return dclone(shift);
172             }
173              
174             # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
175             # errors are structured like:
176             # $param = {
177             # ...
178             # errors => {
179             # $check_name => $error_message,
180             # }
181             sub errors {
182 1822     1822 0 2197 my $self = shift;
183              
184 1822 100       6959 return unless $self->{ errors };
185 302         1409 my @errors;
186 302         919 my( $b, $e ) = $self->error_decoration;
187 302         458 for( sort values %{ $self->{ errors }}) {
  302         1315  
188 319   66     1163 my $label = $self->label || $self->name;
189             { # don't care if these exist
190 21     21   229 no warnings qw/ uninitialized /;
  21         49  
  21         5047  
  319         485  
191 319         1099 $label = $b . $label . $e;
192             }
193 319         1090 $_ =~ s/\$label/$label/g;
194 319         1104 push @errors => $_
195             }
196 302 50       3061 return \@errors if @errors;
197 0           return;
198             }
199              
200             1;
201              
202             __END__