1package URI::QueryParam;
2
3use strict;
4
5sub URI::_query::query_param {
6    my $self = shift;
7    my @old = $self->query_form;
8
9    if (@_ == 0) {
10	# get keys
11	my %seen;
12	my @keys;
13	for (my $i = 0; $i < @old; $i += 2) {
14	    push(@keys, $old[$i]) unless $seen{$old[$i]}++;
15	}
16	return @keys;
17    }
18
19    my $key = shift;
20    my @i;
21
22    for (my $i = 0; $i < @old; $i += 2) {
23	push(@i, $i) if $old[$i] eq $key;
24    }
25
26    if (@_) {
27	my @new = @old;
28	my @new_i = @i;
29	my @vals = map { ref($_) eq 'ARRAY' ? @$_ : $_ } @_;
30	#print "VALS:@vals [@i]\n";
31	while (@new_i > @vals) {
32	    #print "REMOVE $new_i[-1]\n";
33	    splice(@new, pop(@new_i), 2);
34	}
35	while (@vals > @new_i) {
36	    my $i = @new_i ? $new_i[-1] + 2 : @new;
37	    #print "SPLICE $i\n";
38	    splice(@new, $i, 0, $key => pop(@vals));
39	}
40	for (@vals) {
41	    #print "SET $new_i[0]\n";
42	    $new[shift(@new_i)+1] = $_;
43	}
44
45	$self->query_form(\@new);
46    }
47
48    return wantarray ? @old[map $_+1, @i] : @i ? $old[$i[0]+1] : undef;
49}
50
51sub URI::_query::query_param_append {
52    my $self = shift;
53    my $key = shift;
54    $self->query_form($self->query_form, $key => \@_);  # XXX
55    return;
56}
57
58sub URI::_query::query_param_delete {
59    my $self = shift;
60    my $key = shift;
61    my @old = $self->query_form;
62    my @vals;
63
64    for (my $i = @old - 2; $i >= 0; $i -= 2) {
65	next if $old[$i] ne $key;
66	push(@vals, (splice(@old, $i, 2))[1]);
67    }
68    $self->query_form(\@old) if @vals;
69    return wantarray ? reverse @vals : $vals[-1];
70}
71
72sub URI::_query::query_form_hash {
73    my $self = shift;
74    my @old = $self->query_form;
75    if (@_) {
76	$self->query_form(@_ == 1 ? %{shift(@_)} : @_);
77    }
78    my %hash;
79    while (my($k, $v) = splice(@old, 0, 2)) {
80	if (exists $hash{$k}) {
81	    for ($hash{$k}) {
82		$_ = [$_] unless ref($_) eq "ARRAY";
83		push(@$_, $v);
84	    }
85	}
86	else {
87	    $hash{$k} = $v;
88	}
89    }
90    return \%hash;
91}
92
931;
94
95__END__
96
97=head1 NAME
98
99URI::QueryParam - Additional query methods for URIs
100
101=head1 SYNOPSIS
102
103  use URI;
104  use URI::QueryParam;
105
106  $u = URI->new("", "http");
107  $u->query_param(foo => 1, 2, 3);
108  print $u->query;    # prints foo=1&foo=2&foo=3
109
110  for my $key ($u->query_param) {
111      print "$key: ", join(", ", $u->query_param($key)), "\n";
112  }
113
114=head1 DESCRIPTION
115
116Loading the C<URI::QueryParam> module adds some extra methods to
117URIs that support query methods.  These methods provide an alternative
118interface to the $u->query_form data.
119
120The query_param_* methods have deliberately been made identical to the
121interface of the corresponding C<CGI.pm> methods.
122
123The following additional methods are made available:
124
125=over
126
127=item @keys = $u->query_param
128
129=item @values = $u->query_param( $key )
130
131=item $first_value = $u->query_param( $key )
132
133=item $u->query_param( $key, $value,... )
134
135If $u->query_param is called with no arguments, it returns all the
136distinct parameter keys of the URI.  In a scalar context it returns the
137number of distinct keys.
138
139When a $key argument is given, the method returns the parameter values with the
140given key.  In a scalar context, only the first parameter value is
141returned.
142
143If additional arguments are given, they are used to update successive
144parameters with the given key.  If any of the values provided are
145array references, then the array is dereferenced to get the actual
146values.
147
148=item $u->query_param_append($key, $value,...)
149
150Adds new parameters with the given
151key without touching any old parameters with the same key.  It
152can be explained as a more efficient version of:
153
154   $u->query_param($key,
155                   $u->query_param($key),
156                   $value,...);
157
158One difference is that this expression would return the old values
159of $key, whereas the query_param_append() method does not.
160
161=item @values = $u->query_param_delete($key)
162
163=item $first_value = $u->query_param_delete($key)
164
165Deletes all key/value pairs with the given key.
166The old values are returned.  In a scalar context, only the first value
167is returned.
168
169Using the query_param_delete() method is slightly more efficient than
170the equivalent:
171
172   $u->query_param($key, []);
173
174=item $hashref = $u->query_form_hash
175
176=item $u->query_form_hash( \%new_form )
177
178Returns a reference to a hash that represents the
179query form's key/value pairs.  If a key occurs multiple times, then the hash
180value becomes an array reference.
181
182Note that sequence information is lost.  This means that:
183
184   $u->query_form_hash($u->query_form_hash)
185
186is not necessarily a no-op, as it may reorder the key/value pairs.
187The values returned by the query_param() method should stay the same
188though.
189
190=back
191
192=head1 SEE ALSO
193
194L<URI>, L<CGI>
195
196=head1 COPYRIGHT
197
198Copyright 2002 Gisle Aas.
199
200=cut
201