add files
|
1 |
package Mojo::Parameters; |
2 |
use Mojo::Base -base; |
|
3 |
use overload |
|
4 |
'@{}' => sub { shift->params }, |
|
5 |
bool => sub {1}, |
|
6 |
'""' => sub { shift->to_string }, |
|
7 |
fallback => 1; |
|
8 | ||
9 |
use Mojo::Util qw(decode encode url_escape url_unescape); |
|
10 | ||
11 |
has charset => 'UTF-8'; |
|
12 | ||
13 |
sub new { shift->SUPER::new->parse(@_) } |
|
14 | ||
15 |
sub append { |
|
16 |
my ($self, @pairs) = @_; |
|
17 | ||
18 |
my $params = $self->params; |
|
19 |
for (my $i = 0; $i < @pairs; $i += 2) { |
|
20 |
my $key = $pairs[$i] // ''; |
|
21 |
my $value = $pairs[$i + 1] // ''; |
|
22 | ||
23 |
# Single value |
|
24 |
if (ref $value ne 'ARRAY') { push @$params, $key => $value } |
|
25 | ||
26 |
# Multiple values |
|
27 |
else { push @$params, $key => (defined $_ ? "$_" : '') for @$value } |
|
28 |
} |
|
29 | ||
30 |
return $self; |
|
31 |
} |
|
32 | ||
33 |
sub clone { |
|
34 |
my $self = shift; |
|
35 | ||
36 |
my $clone = $self->new->charset($self->charset); |
|
37 |
if (defined $self->{string}) { $clone->{string} = $self->{string} } |
|
38 |
else { $clone->params([@{$self->params}]) } |
|
39 | ||
40 |
return $clone; |
|
41 |
} |
|
42 | ||
43 |
sub merge { |
|
44 |
my $self = shift; |
|
45 |
push @{$self->params}, @{$_->params} for @_; |
|
46 |
return $self; |
|
47 |
} |
|
48 | ||
49 |
sub param { |
|
50 |
my ($self, $name) = (shift, shift); |
|
51 | ||
52 |
# List names |
|
53 |
return sort keys %{$self->to_hash} unless $name; |
|
54 | ||
55 |
# Replace values |
|
56 |
$self->remove($name) if defined $_[0]; |
|
57 |
$self->append($name, $_) for @_; |
|
58 | ||
59 |
# List values |
|
60 |
my @values; |
|
61 |
my $params = $self->params; |
|
62 |
for (my $i = 0; $i < @$params; $i += 2) { |
|
63 |
push @values, $params->[$i + 1] if $params->[$i] eq $name; |
|
64 |
} |
|
65 | ||
66 |
return wantarray ? @values : $values[0]; |
|
67 |
} |
|
68 | ||
69 |
sub params { |
|
70 |
my $self = shift; |
|
71 | ||
72 |
# Replace parameters |
|
73 |
if (@_) { |
|
74 |
$self->{params} = shift; |
|
75 |
delete $self->{string}; |
|
76 |
return $self; |
|
77 |
} |
|
78 | ||
79 |
# Parse string |
|
80 |
if (defined(my $str = delete $self->{string})) { |
|
81 |
my $params = $self->{params} = []; |
|
82 |
return $params unless length $str; |
|
83 | ||
84 |
# W3C suggests to also accept ";" as a separator |
|
85 |
my $charset = $self->charset; |
|
86 |
for my $pair (split /&|;/, $str) { |
|
87 |
next unless $pair =~ /^([^=]+)(?:=(.*))?$/; |
|
88 |
my $name = $1; |
|
89 |
my $value = $2 // ''; |
|
90 | ||
91 |
# Replace "+" with whitespace, unescape and decode |
|
92 |
s/\+/ /g for $name, $value; |
|
93 |
$name = url_unescape $name; |
|
94 |
$name = decode($charset, $name) // $name if $charset; |
|
95 |
$value = url_unescape $value; |
|
96 |
$value = decode($charset, $value) // $value if $charset; |
|
97 | ||
98 |
push @$params, $name, $value; |
|
99 |
} |
|
100 |
} |
|
101 | ||
102 |
return $self->{params} ||= []; |
|
103 |
} |
|
104 | ||
105 |
sub parse { |
|
106 |
my $self = shift; |
|
107 | ||
108 |
# Pairs |
|
109 |
if (@_ > 1) { $self->append(@_) } |
|
110 | ||
111 |
# String |
|
112 |
else { $self->{string} = $_[0] } |
|
113 | ||
114 |
return $self; |
|
115 |
} |
|
116 | ||
117 |
sub remove { |
|
118 |
my $self = shift; |
|
119 |
my $name = shift // ''; |
|
120 | ||
121 |
my $params = $self->params; |
|
122 |
for (my $i = 0; $i < @$params;) { |
|
123 |
if ($params->[$i] eq $name) { splice @$params, $i, 2 } |
|
124 |
else { $i += 2 } |
|
125 |
} |
|
126 | ||
127 |
return $self->params($params); |
|
128 |
} |
|
129 | ||
130 |
sub to_hash { |
|
131 |
my $self = shift; |
|
132 | ||
133 |
my $params = $self->params; |
|
134 |
my %hash; |
|
135 |
for (my $i = 0; $i < @$params; $i += 2) { |
|
136 |
my ($name, $value) = @{$params}[$i, $i + 1]; |
|
137 | ||
138 |
# Array |
|
139 |
if (exists $hash{$name}) { |
|
140 |
$hash{$name} = [$hash{$name}] unless ref $hash{$name} eq 'ARRAY'; |
|
141 |
push @{$hash{$name}}, $value; |
|
142 |
} |
|
143 | ||
144 |
# String |
|
145 |
else { $hash{$name} = $value } |
|
146 |
} |
|
147 | ||
148 |
return \%hash; |
|
149 |
} |
|
150 | ||
151 |
sub to_string { |
|
152 |
my $self = shift; |
|
153 | ||
154 |
# String |
|
155 |
my $charset = $self->charset; |
|
156 |
if (defined(my $str = $self->{string})) { |
|
157 |
$str = encode $charset, $str if $charset; |
|
158 |
return url_escape $str, '^A-Za-z0-9\-._~!$&\'()*+,;=%:@/?'; |
|
159 |
} |
|
160 | ||
161 |
# Build pairs |
|
162 |
my $params = $self->params; |
|
163 |
return '' unless @$params; |
|
164 |
my @pairs; |
|
165 |
for (my $i = 0; $i < @$params; $i += 2) { |
|
166 |
my ($name, $value) = @{$params}[$i, $i + 1]; |
|
167 | ||
168 |
# Escape and replace whitespace with "+" |
|
169 |
$name = encode $charset, $name if $charset; |
|
170 |
$name = url_escape $name, '^A-Za-z0-9\-._~!$\'()*,:@/?'; |
|
171 |
$value = encode $charset, $value if $charset; |
|
172 |
$value = url_escape $value, '^A-Za-z0-9\-._~!$\'()*,:@/?'; |
|
173 |
s/\%20/\+/g for $name, $value; |
|
174 | ||
175 |
push @pairs, "$name=$value"; |
|
176 |
} |
|
177 | ||
178 |
return join '&', @pairs; |
|
179 |
} |
|
180 | ||
181 |
1; |
|
182 | ||
183 |
=encoding utf8 |
|
184 | ||
185 |
=head1 NAME |
|
186 | ||
187 |
Mojo::Parameters - Parameters |
|
188 | ||
189 |
=head1 SYNOPSIS |
|
190 | ||
191 |
use Mojo::Parameters; |
|
192 | ||
193 |
# Parse |
|
194 |
my $params = Mojo::Parameters->new('foo=bar&baz=23'); |
|
195 |
say $params->param('baz'); |
|
196 | ||
197 |
# Build |
|
198 |
my $params = Mojo::Parameters->new(foo => 'bar', baz => 23); |
|
199 |
push @$params, i => '♥ mojolicious'; |
|
200 |
say "$params"; |
|
201 | ||
202 |
=head1 DESCRIPTION |
|
203 | ||
204 |
L<Mojo::Parameters> is a container for form parameters used by L<Mojo::URL>. |
|
205 | ||
206 |
=head1 ATTRIBUTES |
|
207 | ||
208 |
L<Mojo::Parameters> implements the following attributes. |
|
209 | ||
210 |
=head2 charset |
|
211 | ||
212 |
my $charset = $params->charset; |
|
213 |
$params = $params->charset('UTF-8'); |
|
214 | ||
215 |
Charset used for encoding and decoding parameters, defaults to C<UTF-8>. |
|
216 | ||
217 |
# Disable encoding and decoding |
|
218 |
$params->charset(undef); |
|
219 | ||
220 |
=head1 METHODS |
|
221 | ||
222 |
L<Mojo::Parameters> inherits all methods from L<Mojo::Base> and implements the |
|
223 |
following new ones. |
|
224 | ||
225 |
=head2 new |
|
226 | ||
227 |
my $params = Mojo::Parameters->new; |
|
228 |
my $params = Mojo::Parameters->new('foo=b%3Bar&baz=23'); |
|
229 |
my $params = Mojo::Parameters->new(foo => 'b;ar'); |
|
230 |
my $params = Mojo::Parameters->new(foo => ['ba;r', 'b;az']); |
|
231 |
my $params = Mojo::Parameters->new(foo => ['ba;r', 'b;az'], bar => 23); |
|
232 | ||
233 |
Construct a new L<Mojo::Parameters> object and L</"parse"> parameters if |
|
234 |
necessary. |
|
235 | ||
236 |
=head2 append |
|
237 | ||
238 |
$params = $params->append(foo => 'ba;r'); |
|
239 |
$params = $params->append(foo => ['ba;r', 'b;az']); |
|
240 |
$params = $params->append(foo => ['ba;r', 'b;az'], bar => 23); |
|
241 | ||
242 |
Append parameters. Note that this method will normalize the parameters. |
|
243 | ||
244 |
# "foo=bar&foo=baz" |
|
245 |
Mojo::Parameters->new('foo=bar')->append(foo => 'baz'); |
|
246 | ||
247 |
# "foo=bar&foo=baz&foo=yada" |
|
248 |
Mojo::Parameters->new('foo=bar')->append(foo => ['baz', 'yada']); |
|
249 | ||
250 |
# "foo=bar&foo=baz&foo=yada&bar=23" |
|
251 |
Mojo::Parameters->new('foo=bar')->append(foo => ['baz', 'yada'], bar => 23); |
|
252 | ||
253 |
=head2 clone |
|
254 | ||
255 |
my $params2 = $params->clone; |
|
256 | ||
257 |
Clone parameters. |
|
258 | ||
259 |
=head2 merge |
|
260 | ||
261 |
$params = $params->merge(Mojo::Parameters->new(foo => 'b;ar', baz => 23)); |
|
262 | ||
263 |
Merge L<Mojo::Parameters> objects. Note that this method will normalize the |
|
264 |
parameters. |
|
265 | ||
266 |
=head2 param |
|
267 | ||
268 |
my @names = $params->param; |
|
269 |
my $foo = $params->param('foo'); |
|
270 |
my @foo = $params->param('foo'); |
|
271 |
my $foo = $params->param(foo => 'ba;r'); |
|
272 |
my @foo = $params->param(foo => qw(ba;r ba;z)); |
|
273 | ||
274 |
Check and replace parameter value. Be aware that if you request a parameter by |
|
275 |
name in scalar context, you will receive only the I<first> value for that |
|
276 |
parameter, if there are multiple values for that name. In list context you |
|
277 |
will receive I<all> of the values for that name. Note that this method will |
|
278 |
normalize the parameters. |
|
279 | ||
280 |
=head2 params |
|
281 | ||
282 |
my $array = $params->params; |
|
283 |
$params = $params->params([foo => 'b;ar', baz => 23]); |
|
284 | ||
285 |
Parsed parameters. Note that this method will normalize the parameters. |
|
286 | ||
287 |
=head2 parse |
|
288 | ||
289 |
$params = $params->parse('foo=b%3Bar&baz=23'); |
|
290 | ||
291 |
Parse parameters. |
|
292 | ||
293 |
=head2 remove |
|
294 | ||
295 |
$params = $params->remove('foo'); |
|
296 | ||
297 |
Remove parameters. Note that this method will normalize the parameters. |
|
298 | ||
299 |
# "bar=yada" |
|
300 |
Mojo::Parameters->new('foo=bar&foo=baz&bar=yada')->remove('foo'); |
|
301 | ||
302 |
=head2 to_hash |
|
303 | ||
304 |
my $hash = $params->to_hash; |
|
305 | ||
306 |
Turn parameters into a hash reference. Note that this method will normalize |
|
307 |
the parameters. |
|
308 | ||
309 |
# "baz" |
|
310 |
Mojo::Parameters->new('foo=bar&foo=baz')->to_hash->{foo}[1]; |
|
311 | ||
312 |
=head2 to_string |
|
313 | ||
314 |
my $str = $params->to_string; |
|
315 |
my $str = "$params"; |
|
316 | ||
317 |
Turn parameters into a string. |
|
318 | ||
319 |
=head1 PARAMETERS |
|
320 | ||
321 |
Direct array reference access to the parsed parameters is also possible. Note |
|
322 |
that this will normalize the parameters. |
|
323 | ||
324 |
say $params->[0]; |
|
325 |
say for @$params; |
|
326 | ||
327 |
=head1 SEE ALSO |
|
328 | ||
329 |
L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>. |
|
330 | ||
331 |
=cut |