5

Has anyone successfully used something like DBIx::Class::WebForm or CatalystX-CRUD to automagically build a self-validating webform from a database table?

I'm imagining a module that reads a database table schema, reads the constraints for each column, and generates some abstract representation of a webform, with fields for error messages, etc. I'm using Catalyst and Plack with a big existing codebase.

I don't want to code up an HTML webform, nor any validation logic. I'm aiming to write as little code as possible, in the style of Ruby on Rails. Which Perl module is best for this?

UPDATE: I've solved the webform side with HTML::FormFu, but it's still clunky mapping the form inputs onto the database, e.g. date_start and date_end both relate to the 'created' column, and comment should match using 'LIKE %foo%', etc. Where's the 'DBICFu'?

UPDATE: This is for a web application, the webform should not look like a database table. I'm not looking for a database management tool.

Will Sheppard
  • 3,272
  • 2
  • 31
  • 41

3 Answers3

2

I've used HTML::FormHandler to generate forms for me in this fashion. It needs some tweaking, but it does 90% of the work for you. Separately DBIx::Class offers a similar tool.

Richard Huxton
  • 21,516
  • 3
  • 39
  • 51
2

You can use use HTML::FormHandler::Moose and HTML::FormHandler::Model::DBIC and get some nice forms.

As a simple example:

The form definition:

package MyStats::Form::Datetime ;

use HTML::FormHandler::Moose ;
extends 'HTML::FormHandler::Model::DBIC' ;

use Date::Calc qw(Today_and_Now) ;

has_field 'datetimeid' => ( label     => 'ID' ) ;
has_field 'datetime'   => ( type      => 'Text',
                            apply     => [ { transform => \&transform_dt } ] ,
                            deflation => \&deflation_dt ,
                            required  => 1 ) ;
has_field 'submit'     => ( type => 'Submit' ,
                            value => 'Speichern' ) ;
# These are the fields of the table datetime

sub transform_dt {
  my ( $dt ) = @_ ;

  my @d = ( $dt =~ m/(\d{1,2})\.(\d{1,2})\.(\d{4})\s+(\d{1,2}):(\d{1,2})/ ) ;
  return sprintf( '%04d-%02d-%02d %02d:%02d:00' , @d[2,1,0,3,4] ) ;
}

sub deflation_dt {
  my ( $dt ) = @_ ;

  my @d = ( $dt =~ m/(\d{4})-(\d{2})-(\d{2})\s+(\d{1,2}):(\d{1,2})/ ) ;
  if( ! @d ) {
    @d = Today_and_Now() ;
  }
  return sprintf( '%02d.%02d.%04d %02d:%02d:00' , @d[2,1,0,3,4] ) ;
}

1 ;

And the usage in a controller:

package MyStats::Controller::Datetime ;
use Moose ;
use namespace::autoclean ;

BEGIN { extends 'Catalyst::Controller' ; }

use MyStats::Form::Datetime ;

has 'form' => ( isa     => 'MyStats::Form::Datetime' ,
                is      => 'rw' ,
                lazy    => 1 ,
                default => \&new_datetime_form ) ;

sub new_datetime_form {
  MyStats::Form::Datetime->new( css_class => 'datetimeform' ,
                                name => 'datetimeform' ) ;
}

...

sub add :Local :Args(0) {
  my ( $self , $ctx ) = @_ ;

  my $data = $ctx->model( 'MyStatsDB::Datetime' )->new_result( {} ) ;
  $ctx->stash( template => 'datetime/add.tt2' ,
               form     => $self->form ) ;
  $ctx->bread_crumb( { name => 'Datum/Zeit eingeben' ,
                       location => '/datetime/add' } ) ;

  $ctx->req->param( 'datetimeid' , undef ) if $ctx->req->param( 'datetimeid' ) ;
  return unless $self->form->process( item   => $data ,
                                      params => $ctx->req->params ) ;
  $ctx->flash( message => 'Neuer Datensatz ' . $data->datetimeid .
                          ' angelegt.' ,
               id_add  => $data->datetimeid ) ;
  $ctx->res->redirect( $ctx->uri_for( '/datetime' ) ) ;
}

...

__PACKAGE__->meta->make_immutable ;

1 ;

Works good.

dgw
  • 13,418
  • 11
  • 56
  • 54
  • Thanks, but I was hoping to not have to specify {{datetimeid}} and {{datetime}} myself, but just point it at a database table and have it read the fields itself. And also turn varchar(32) into a text input field with length 32, etc. – Will Sheppard Mar 01 '12 at 16:56
  • @WillSheppard I'm not sure if something like this exists, but one could write something to generate the `HTML::FormHandler::Moose` files. – dgw Mar 01 '12 at 18:36
2

There are a number of crud options on the Catalyst wiki.

It sounds like AutoCrud would fit your needs.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335