Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options

Comment on

( #3333=superdoc: print w/replies, xml ) Need Help??

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;


Class::CGI - Fetch objects from your CGI object


Version 0.01


    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


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.




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

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.


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.



  use Class::CGI;
  my $cust_cgi = Class::CGI->new;
    customer => 'Class::CGI::Customer',
  my $order_cgi = Class::CGI->new($other_params);
    order    => 'Class::CGI::Order',
  my $customer = $cust_cgi->param('customer');
  my $order    = $order_cgi->param('order');
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.


 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 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)";

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' );


This module should be considered alpha code. It probably has bugs. Comments and suggestions welcome.


Curtis ``Ovid'' Poe, &lt;;


Please report any bugs or feature requests to, or through the web interface at I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.



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.


New address of my CGI Course.

In reply to RFC: Class::CGI by Ovid

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?

    What's my password?
    Create A New User
    and all is quiet...

    How do I use this? | Other CB clients
    Other Users?
    Others surveying the Monastery: (6)
    As of 2017-11-22 21:47 GMT
    Find Nodes?
      Voting Booth?
      In order to be able to say "I know Perl", you must have:

      Results (327 votes). Check out past polls.