This module is not yet on the CPAN. You may download it from my downloads section.
When writing web-based code, I see an awful lot of stuff like this:
use My::Customer; use CGI; my $cgi = CGI->new; my $cust_id = $cgi->param('customer_id'); error_page("Bad customer id") unless $cust_id && $cust_id =~ /^\d_/; my $email = $cgi->param('email'); # validate email my $cust = My::Customer->load_from_id($cust_id); $cust->email($email); $cust->save;
This gets repeated in many classes throughout the site. To solve this, I wrote Class::CGI. Before I upload it to the CPAN, it would be nice to get comments from folks about it. Let me know what you like, dislike, and so on. If you have other features you think it should support, please let me know.
The above code could become something like this:
use Class::CGI handlers => { customer => 'Class::CGI::Customer' }; my $cgi = Class::CGI->new; my $cust = $cgi->param('customer'); my $email = $cgi->param('email'); # validate email $cust->email($email); $cust->save;
- NAME
- VERSION
- SYNOPSIS
- DESCRIPTION
- EXPORT
- BASIC USE
- LOADING THE HANDLERS
- METHODS
- WRITING HANDLERS
- TODO
- AUTHOR
- BUGS
- ACKNOWLEDGEMENTS
- COPYRIGHT & LICENSE
NAME
Class::CGI - Fetch objects from your CGI object
VERSION
Version 0.01
SYNOPSIS
use Class::CGI handlers => { customer_id => 'Class::CGI::Customer' };
my $cgi = Class::CGI->new; my $customer = $cgi->param('customer_id'); my $name = $customer->name; my $email = $cgi->param('email'); # behaves like normal
DESCRIPTION
For small CGI scripts, it's common to get a parameter, untaint it, pass it to an object constructor and get the object back. This module would allow one to to build Class::CGI handler classes which take the parameter value, automatically perform those steps and just return the object. Much grunt work goes away and you can get back to merely pretending to work.
Because this module is a subclass of CGI::Simple, all of CGI::Simple's methods and behaviors should be available. We do not subclass off of CGI because CGI::Simple is faster and it's assumed that if we're going the full OO route that we are already using templates. This decision may be revisited in the future.
EXPORT
None.
BASIC USE
The simplest method of using Class::CGI is to simply specify each form parameter's handler class in the import list:
use Class::CGI handlers => { customer => 'Class::CGI::Customer', sales => 'Sales::Loader' };
my $cgi = Class::CGI->new; my $customer = $cgi->param('customer'); my $email = $cgi->param('email'); # validate email $customer->email($email); $customer->save;
Note that there is no naming requirement for the handler classes and any form parameter which does not have a handler class behaves just like a normal form parameter. Each handler class is expected to have a constructor named new which takes the raw form value and returns an object corresponding to that value. All untainting and validation is expected to be dealt with by the handler. See WRITING HANDLERS.
If you need different handlers for the same form parameter names (this is common in persistent environments) you may omit the import list and use the handlers method.
LOADING THE HANDLERS
When the handlers are specified, either via the import list or the handlers() method, we verify that the handler exists and croak() if it is not. However, we do not load the handler until the parameter for that handler is fetched. This allows us to not load unused handlers but still have a semblance of safety that the handlers actually exist.
METHODS
handlers
use Class::CGI; my $cust_cgi = Class::CGI->new; $cust_cgi->handlers( customer => 'Class::CGI::Customer', ); my $order_cgi = Class::CGI->new($other_params); $order_cgi->handlers( order => 'Class::CGI::Order', ); my $customer = $cust_cgi->param('customer'); my $order = $order_cgi->param('order'); $order->customer($customer); Sometimes we get our CGI parameters from different sources. This commonly happens in a persistent environment where the class handlers for one form may not be appropriate for another form. When this occurs, you may set the handler classes on an instance of the C<Class::CGI> object. This overrides global class handlers set in the import list:
use Class::CGI handlers => { customer => "Some::Customer::Handler" }; my $cgi = Class::CGI->new; $cgi->handlers( customer => "Some::Other::Customer::Handler" );
In the above example, the $cgi object will not use the Some::Customer::Handler class.
param
use Class::CGI handlers => { customer => 'Class::CGI::Customer' };
my $cgi = Class::CGI->new; my $customer = $cgi->param('customer'); # returns an object, if found my $email = $cgi->param('email'); # returns the raw value my @sports = $cgi->param('sports'); # behaves like you would expect
If a handler is defined for a particular parameter, the param() calls the new() method for that handler, passing the parameter's value. Returns the value returned by new(). In the example above, for ``customer'', the return value is essentially:
return Class::CGI::Customer->new( $self->SUPER::param('customer') );
WRITING HANDLERS
Writing a handler is a fairly straightforward affair. Let's assume that our form has a parameter named ``customer'' and this parameter should point to a customer ID. The ID is assumed to be a positive integer value. For this example, we assume that our customer class is named My::Customer and we load a customer object with the load_from_id() method. The handler might look like this:
package Class::CGI::Customer; use strict; use warnings; use My::Customer; sub new { my ($class, $id) = @_; unless ( $id && $id =~ /^\d+$/ ) { die "Invalid id ($id) for $class"; } return My::Customer->load_from_id($id) || die "Could not find customer for ($id)"; } 1;
Pretty simple, eh?
Using this in your code is as simple as:
use Class::CGI handlers => { customer => 'Class::CGI::Customer', };
If Class::CGI is being used in a persistent environment and other forms might have a param named customer but this param should not become a My::Customer object, then set the handler on the instance instead:
use Class::CGI; my $cgi = Class::CGI->new; $cgi->handlers( customer => 'Class::CGI::Customer' );
TODO
This module should be considered alpha code. It probably has bugs. Comments and suggestions welcome.
AUTHOR
Curtis ``Ovid'' Poe, <ovid@cpan.org>
BUGS
Please report any bugs or feature requests to bug-class-cgi@rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
ACKNOWLEDGEMENTS
COPYRIGHT & LICENSE
Copyright 2006 Curtis ``Ovid'' Poe, all rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Cheers,
Ovid
New address of my CGI Course.