1 package CXGN
::Page
::WebForm
;
9 use CXGN
::Tools
::List qw
/distinct all/;
13 CXGN::Page::WebForm - a persistent HTML form
18 use base qw( CXGN::Page::WebForm );
19 __PACKAGE__->template( <<EOHTML );
20 Id:<input name="NAME_id" value="VALUE_id" />
21 Name:<input name="NAME_name" value="VALUE_name" />
26 my $form = MyWebForm->new;
27 my $page = CXGN::Page->new('Some page','Rob Buels');
28 $form->from_request( $page->get_all_encoded_arguments );
30 print "you submitted the data ",
31 '('.join(',',$form->data('id','name','something').")\n";
32 #remember, data() returns a list of (val,val,val,...), not a scalar
34 #prints whatever the value of w98e_id was in the POST
35 #we got, where w98e is some arbitrary piece of
36 #garbage this class uses to keep its parameters
39 $form->set_data( id => 42, name => 'rob' );
41 print '<form action="" method="post">',"\n",
43 '</form>'; #now print the auto-filled-in form
45 #will print something like
47 <form action="" method="post">
48 Id:<input name="w98e_id" value="42" />
49 Name:<input name="w98e_name" value="rob" />
52 #where w98e is an automatically generated identifier
53 #that signifies that the values belong to the MyWebForm
58 L<CXGN::Search::WWWQuery>
62 This is an object representing a web form, which encodes
63 and decodes its parameter names such that it always knows
64 which parameters belong to it. Use this as a base class
65 for making HTML forms that fill themselves in based on values
66 supplied from somewhere else.
68 =head1 PRIMARY FUNCTIONS
70 These are the primary functions provided by this class.
74 use base qw
/ Class::Data::Inheritable /;
76 use Class
::MethodMaker
77 [ new
=> [-init
=> 'new'],
83 Usage: my $form = MyWebForm->new;
84 Desc : make a new form object
86 Args : (optional) initial data, same format as set_data() below
87 Side Effects: calls the init() method in this class to set up
92 sub init
{ #init() is called by Class::MethodMaker's new() method
101 Note: this is a CLASS METHOD.
103 Usage: MyForm->template(<<EOHTML);
104 ID Number:<input type="text" name="NAME_id" value="VALUE_id" /><br />
105 Name:<input type="text" name="NAME_name" value="VALUE_name" />
107 Desc : set the html template to use for this web form
108 Ret : the template you set
109 Args : (optional) new template string to set for this class
110 Side Effects: sets a piece of class data holding this template
114 #make a _template() class method to hold the data
115 __PACKAGE__
->mk_classdata( '_template' );
117 #wrap the _template classdata in some error checking
121 $_[0] && $_[0] =~ /<form\s/
122 and croak
"Do not include <form> elements in your to_html template";
124 $class->_template(@_);
129 Usage: print $myform->to_html
130 Desc : fills in this class's HTML form template (set with template()
131 above) with the properly uniqified names, and the values we have
132 in this object, if any (e.g. from a previous from_request)
134 If no template is defined, it makes a default one with whatever
135 parameters and values are set in it, if any.
140 Subclass implementors might want to override this to generate
141 their HTML in a more advanced way.
147 @_ > 1 and croak
"to_html takes no arguments"; #check args
149 #get our class's template, or make a crappy default one
151 my $template = (ref $self)->template
153 map { my ($val) = $self->_data_index($_);
154 qq|<label
for="NAME_$_">$_:</label
>|
155 .qq|<input name
="VALUE_$_" value
="$val" />|
158 || __PACKAGE__
.': no template defined, and no data to use for generating default template, so this is an empty template. Maybe you should provide one.';
160 #make a tied hash for uniqifying names
161 tie
my %uniq, 'Tie::Function', sub { $self->uniqify_name(@_) };
162 #make a tied hash for looking up values in this object
163 tie
my %value, 'Tie::Function', sub { my $v = ($self->_data_index(@_))[0];
164 defined($v) ? encode_entities
($v) : ''
166 #plug the names and values into the template
167 $template =~ s/(?<=\W)NAME_(\w+)(?=\W)/$uniq{$1}/g;
168 $template =~ s/(?<=\W)VALUE_(\w+)(?=\W)/$value{$1}/g;
176 Usage: $from->from_request( { bleh => 1, isa_monkey => 'rob'} );
177 Desc: deserialize this query object from a an Apache request object
178 Args: ref to a hash of parameters (like that returned from
179 CXGN::Page->get_arguments() ) you can make your own with
182 my $r = Apache2::RequestUtil->request;
183 $r->content_type("text/html");
184 my %params=$r->method eq "POST" ? $r->content : $r->args;
186 $myform->from_request(\%params);
194 my ($self,$mungedparams) = @_;
195 my %params = $self->_pick_out_my_params($mungedparams);
196 $self->_data(%params);
201 Usage: print "got form data (id,name)= ("
202 .join(',',$form->data(qw/id name/))
204 Desc : get the values of one or more pieces of form data
205 Ret : list of corresponding values for the names you passed in
206 Args : list of names of the data you want
209 NOTE: both the input and the output of this function are _lists_
213 #the secret internal writable accessor is _data, generated
214 #by Class::MethodMaker above
216 shift->_data_index(@_);
221 Usage: my @stuff = $form->data_multiple('foolist');
222 Desc : When a parameter may have multiple values (such as a
223 multiple-select box) this returns the many values as a
224 list. Supply only one argument, the name of the parameter.
225 Ret : List of values for the named parameter
226 Args : The name of the parameter
233 my ($self, $param) = @_;
234 my ($thingy) = $self->data($param);
236 return (split /\0/, $thingy);
242 Usage: $form->set_data( id => 42, name => 'rob')
243 Desc : set data in this form
244 Ret : nothing meaningful
245 Args : hash-style list of values to set, like
246 (id => 42, name => 'rob')
247 Side Effects: sets object data
252 shift->_data_set(@_);
257 Usage: print 'yep' if $form_obj_1->same_data_as( $form_obj_2 );
258 Desc : object method, returns true if the given form object
259 contains the same data as this one.
260 Args : a WebForm object
261 Ret : true if the objects are the same, false otherwise
266 my ($self,$other) = @_;
268 # true of course if they are the same object
269 return 1 if $self == $other;
271 # check if they have the same number of data items set
272 return unless $self->_data_count == $other->_data_count;
274 # check if they have the same data item names set
275 my @keys = distinct
$self->_data_keys, $other->_data_keys;
277 return unless $self->_data_count == scalar @keys;
279 # now we know they have the same data item names,
280 # check that they have the same data values
282 $self->_data_index($_) eq $self->_data_index($_)
287 =head1 HELPER FUNCTIONS
289 These functions may be useful for developers who subclass this.
291 =head2 _pick_out_my_params
293 Desc: given a hash of names and values from a GET or POST request, pick
294 out the variables in the request that belong to us, that is,
295 that were generated by an object of the same class as this one.
296 Args: reference to a hash containing name => value pairs
297 Ret : hash of parameters that, based on the encoding of their names,
298 belong to this object, as:
299 ( unmunged name => value,
300 unmunged name => value,
306 sub _pick_out_my_params
{
308 my ($this,$mungedparams) = @_;
310 ref $mungedparams eq 'HASH'
311 or croak
'Argument to from_request must be a hash ref (got a '.(ref $mungedparams).')';
313 my %unmunged; #params that belong to us, unmunged
315 #find all the params that belong to us
316 while(my ($mungedname,$value) = each %$mungedparams) {
317 if( my $name = $this->de_uniqify_name($mungedname) ) {
318 $unmunged{$name} = $value;
327 Desc: method to munge the name of a form field such that
328 it will almost certainly not collide with other things in
329 the same GET or POST request
339 #generate this class's prefix used for uniqifying parameter names
340 our %_params_prefix_cache;
341 our $crc = Digest
::Crc32
->new;
344 $this = ref $this if ref $this;
345 $_params_prefix_cache{$this} ||= sprintf('w%x_',$crc->strcrc32($this) & 0xfff);
348 =head2 de_uniqify_name
350 Desc: method to convert form field names made with uniqify_name above
351 back into the name you actually want to use
353 Ret : unmunged name, or undef if the name passed was not munged in the correct way
355 Used in _pick_out_my_params().
359 sub de_uniqify_name
{
360 my ($this,$html) = @_;
361 my $prefix = $this->_prefix();
362 my ($ret) = $html =~ /^$prefix(.+)/;
368 Desc: convenience method, makes a hash in the calling package called
369 %pname that you can use instead of uniqify_name (see example)
373 __PACKAGE__->make_pname;
377 <form><input name="$pname{foo}" value="" /></form>
385 $class = ref $class if ref $class;
387 tie
%{$class.'::pname'}, 'Tie::Function' => sub { $class->uniqify_name(@_) };