http://www.perlmonks.org?node_id=541983

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

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, &lt;ovid@cpan.org&gt;


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.