Class::CGI::DateTime - Fetch DateTime objects directly from your forms.


Class-CGI-DateTime documentation Contained in the Class-CGI-DateTime distribution.

Index


Code Index:

NAME

Top

Class::CGI::DateTime - Fetch DateTime objects directly from your forms.

VERSION

Top

Version 0.02

SYNOPSIS

Top

  use Class::CGI
    handlers => {
        date       => 'Class::CGI::DateTime',
        order_date => 'Class::CGI::DateTime',
    };
  my $cgi        = Class::CGI->new;
  my $date       = $cgi->param('date');
  my $order_date = $cgi->param('order_date');

  if ( my %errors = $cgi->errors ) { ... }

DESCRIPTION

Top

A common problem with Web programming is handling dates correctly. This Class::CGI handler attempts to do that for you in a standard way by allowing you to have separate day, month and year dropdowns but request a "date" parameter and get the correct object back, safely validated and untainted.

Multiple dates may be used in a single form and you can even specify hours, minutes, timezones, and so on.

Basic Usage

If you have a form with <select> boxes named day, month and year, you can fetch these into a DateTime object with this:

  use Class::CGI
    handlers => {
        date => 'Class::CGI::DateTime',
    };
  my $cgi        = Class::CGI->new;
  my $date       = $cgi->param('date');

The value of each parameter should correspond to allowed values for that parameter to the DateTime constructor.

Multiple dates in a form

If you need more than one date object embedded in a form, additional date objects may be specified by prefixing the form parameter names with a unique identifier followed by a dot ("."). For example, to fetch a date and an order date, you can do the following:

  use Class::CGI
    handlers => {
        date       => 'Class::CGI::DateTime',
        order_date => 'Class::CGI::DateTime',
    };
  my $cgi        = Class::CGI->new;
  my $date       = $cgi->param('date');
  my $order_date = $cgi->param('order_date');

The date parameter will be created from the day, month and year parameters in the Class::CGI object. The order_date.date parameter will be created from the order_date.day, order_date.month and order_date.year parameters.

Different parameters

 $cgi->args( date => { params => [qw/ day hour minute /] } );

You cannot change the parameter names (e.g., no changing "day" to "jour" or something like that), but you can specify additional parameters which the DateTime constructor expects. Each parameter's value must correspond to the allowed values for the DateTime object. You do this by setting the requested parameters in Class::CGI's args() method. The key is the date parameter you wish to specify the arguments for and the value should be a hashref with a key of "params" and a value being an array reference specifying the names of the parameters desired.

For example, if your HTML form has day, month, year and timezone, you might do this:

  use Class::CGI
    handlers => {
        date => 'Class::CGI::DateTime',
    };
  my $cgi        = Class::CGI->new;
  $cgi->args( 
     date => { params => [qw/ day month year time_zone /] }
  );
  my $date       = $cgi->param('date');

The allowed parameter names, as specified from the DateTime documentation, are:

* year
* month
* day
* hour
* minute
* second
* nanosecond
* time_zone

Error handling

As usual, any errors reported by Class::CGI::DateTime will be in the Class::CGI errors() method. However, the validation errors reported by the DateTime object are generally aimed at programmers, not users of your software. Thus, you'll want to provide more user friendly error messages. For example:

  if ( my %error_for = $cgi->errors ) {
      if ( exists $error_for{order_date} ) {
          $error_for{order_date} = "You must enter a valid order date";
      }
  }

If a date is required, it's easy to handle this:

  use Class::CGI
    handlers => {
        date       => 'Class::CGI::DateTime',
        order_date => 'Class::CGI::DateTime',
    };
  my $cgi        = Class::CGI->new;
  $cgi->required( qw/date order_date/ );
  my $date       = $cgi->param('date');
  my $order_date = $cgi->param('order_date');

Class::CGI::DateTime will not create a date object if any of the required components (day, month, year and so on) are missing. Further, a descriptive error message will be set.

Also note that at the present time, Class::CGI::DateTime only ensures that we can create a valid DateTime object. Application-specific validation (such as ensuring the date is in the future) belongs in your application and should be handled there.

AUTHOR

Top

Curtis "Ovid" Poe, <ovid@cpan.org>

BUGS

Top

Please report any bugs or feature requests to bug-class-cgi-datetime@rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Class-CGI-DateTime. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SEE ALSO

Top

* DateTime - A date and time object

ACKNOWLEDGEMENTS

Top

Adam Kennedy (Alias): for suggesting a better interface.

COPYRIGHT & LICENSE

Top


Class-CGI-DateTime documentation Contained in the Class-CGI-DateTime distribution.
package Class::CGI::DateTime;

use base 'Class::CGI::Handler';

use warnings;
use strict;
use DateTime;

our $VERSION = '0.02';

sub handle {
    my $self  = shift;
    my $cgi   = $self->cgi;
    my $param = $self->param;

    my @params = $self->components;

    # original param name and param value
    my %args = map { /([[:word:]]+)$/; $1, $cgi->raw_param($_) } @params;

    # untaint them puppies
    while ( my ( $arg, $value ) = each %args ) {
        if ( 'time_zone' eq $arg ) {
            $value =~ /^(floating|local|\+[[:digit:]]+|[[:word:]]+\/[[:word:]]+)$/;
            $args{$arg} = $1;
        }
        else {
            $value =~ /^(\d+)$/;
            $args{$arg} = $1;
        }
    }
    my $datetime;
 
    eval { $datetime = DateTime->new(%args) };

    if (my $error = $@) {
        $cgi->add_error( $param, 'You must supply a valid date' );
    }
    return $datetime;
}

sub components {
    my $self  = shift;
    my $cgi   = $self->cgi;
    my $param = $self->param;

    my $requested_params = $cgi->args($param);
    my @params = $requested_params 
      ? @{ $requested_params->{params} }
      : qw(day month year);

    if ( 'date' ne $param ) {
        @params = map {"$param.$_"} @params;
    }
    return @params;
}

sub has_param {
    my $self = shift;
    return $self->has_virtual_param( $self->param, $self->components );
}

1;