Subject: | Fix for proper handling of multivalued query params |
Currently, validate_query() does not handle multivalued fields properly. In particular, with a
querystring like "?val=1&val=2" the following
$app->validate_query({
val => { optional=>0 }
});
will change the query to produce something like
{
val => 'ARRAY(0x8a8e97c)'
}
rather than the expected
{
val => ['1', '2'] # or null-separated "12"
}
Attached is a patch to correct this behavior, along with related tests. The patch also improves
the return value of validate_query() so that it more accurately matches the documentation.
Thanks!
--Matt
Subject: | multivalued-fields.patch |
diff -rupN CGI-Application-Plugin-ValidateQuery-1.0.2-orig/lib/CGI/Application/Plugin/ValidateQuery.pm CGI-Application-Plugin-ValidateQuery-1.0.2-patched/lib/CGI/Application/Plugin/ValidateQuery.pm
--- CGI-Application-Plugin-ValidateQuery-1.0.2-orig/lib/CGI/Application/Plugin/ValidateQuery.pm 2009-07-17 11:29:15.000000000 -0400
+++ CGI-Application-Plugin-ValidateQuery-1.0.2-patched/lib/CGI/Application/Plugin/ValidateQuery.pm 2009-10-16 10:27:14.000000000 -0400
@@ -119,8 +119,9 @@ sub validate_query {
croak $log_msg;
}
- # account for default values.
- map { $self->query->param($_ => $validated{$_}) } keys %validated;
+ # Account for default values, and use the expanded -name / -value
+ # suntax for CGI to ensure proper handling of multivalued fields.
+ map { $self->query->param( -name=>$_ , -value=>$validated{$_} ) } keys %validated;
return %validated;
}
diff -rupN CGI-Application-Plugin-ValidateQuery-1.0.2-orig/t/02-validate.t CGI-Application-Plugin-ValidateQuery-1.0.2-patched/t/02-validate.t
--- CGI-Application-Plugin-ValidateQuery-1.0.2-orig/t/02-validate.t 2009-07-17 11:29:15.000000000 -0400
+++ CGI-Application-Plugin-ValidateQuery-1.0.2-patched/t/02-validate.t 2009-10-16 10:33:33.000000000 -0400
@@ -36,6 +36,8 @@ $t_obj->validate_query_config(
error_mode => 'fail_mode'
);
+my %before_q_vars = $t_obj->query->Vars;
+
my %return_hash;
eval {
%return_hash = $t_obj->validate_query({
@@ -50,9 +52,21 @@ eval {
});
};
is($@, '', "Successful validation");
-my %vars = $t_obj->query->Vars;
+my %after_q_vars = $t_obj->query->Vars;
+
+is_deeply(\%before_q_vars, \%after_q_vars, 'Query not clobbered?');
+
+# Don't use query->Vars to compare with %return_hash.
+# Below we ensure multivalued field shows up as hashref,
+# rather than as a null separated string.
+my %query_hash;
+for my $p ($t_obj->query->param) {
+ my @vals = $t_obj->query->param($p);
+ $query_hash{$p} = scalar @vals > 1 ? \@vals : $vals[0];
+}
+
+is_deeply(\%query_hash, \%return_hash, 'Proper return?');
-is_deeply(\%vars, \%return_hash, 'Proper return?');
eval {
$t_obj->validate_query({
@@ -117,5 +131,3 @@ $t_obj->validate_query({
is($t_obj->query()->param('one'), 410, 'Default set?');
-
-
diff -rupN CGI-Application-Plugin-ValidateQuery-1.0.2-orig/t/05-extra_fields_optional.t CGI-Application-Plugin-ValidateQuery-1.0.2-patched/t/05-extra_fields_optional.t
--- CGI-Application-Plugin-ValidateQuery-1.0.2-orig/t/05-extra_fields_optional.t 2009-07-17 11:29:15.000000000 -0400
+++ CGI-Application-Plugin-ValidateQuery-1.0.2-patched/t/05-extra_fields_optional.t 2009-10-16 10:35:29.000000000 -0400
@@ -13,7 +13,7 @@ use warnings;
use CGI;
my $t_obj = TestAppWithoutLogger->new(
QUERY => CGI->new(
- 'one=1&two=2&three=3&four=4'
+ 'one=1&two=2&three=3&four=4&five=5&five=e'
),
);
@@ -22,20 +22,24 @@ is($t_obj->query->param('one'), 1, 'Re
is($t_obj->query->param('two'), 2, 'Reality check: Query properly set?');
is($t_obj->query->param('three'), 3, 'Reality check: Query properly set?');
is($t_obj->query->param('four'), 4, 'Reality check: Query properly set?');
+my @value = $t_obj->query->param('five');
+my @test = (5,'e');
+is(@value, @test, 'Reality check: Query properly set?');
+
$t_obj->validate_query_config(
error_mode => 'fail_mode',
);
-my @before_p = sort $t_obj->query->param;
+my %before_q_vars = $t_obj->query->Vars;
eval {
my $output = $t_obj->validate_query({
one => { type=>SCALAR, optional=>0 },
extra_fields_optional => 1,
});
};
-my @after_p = sort $t_obj->query->param;
+my %after_q_vars = $t_obj->query->Vars;
-is_deeply(\@before_p, \@after_p, 'Query not clobbered?');
+is_deeply(\%before_q_vars, \%after_q_vars, 'Query not clobbered?');
unlike($@, qr/not listed in the validation options/, "Properly ignored rest of query?");