[Catalyst-commits] r13876 - trunk/examples/CatalystAdvent/root/2010/pen

dhoss at dev.catalyst.perl.org dhoss at dev.catalyst.perl.org
Mon Dec 20 18:29:10 GMT 2010


Author: dhoss
Date: 2010-12-20 18:29:09 +0000 (Mon, 20 Dec 2010)
New Revision: 13876

Modified:
   trunk/examples/CatalystAdvent/root/2010/pen/fs-reflector-and-cat.pod
Log:
committing a draft

Modified: trunk/examples/CatalystAdvent/root/2010/pen/fs-reflector-and-cat.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2010/pen/fs-reflector-and-cat.pod	2010-12-20 17:35:16 UTC (rev 13875)
+++ trunk/examples/CatalystAdvent/root/2010/pen/fs-reflector-and-cat.pod	2010-12-20 18:29:09 UTC (rev 13876)
@@ -4,4 +4,225 @@
 
 =head2 Where Do I use this Magical Beast?
 
-Well, most of the time, I write my forms in standard, boring old HTML.  This works great, and I can use L<Data::Manager|http://search.cpan.org/dist/Data-Manager/> for my data validation quite easily, but what if I have a project I want done yesterday, that has GIGANTIC forms that I don't feel like going through and creating by hand?  This is a perfect scenario for  L<Form::Sensible::Reflector::DBIC|http://search.cpan.org/dist/Form-Sensible-Reflector-DBIC/>.
+Well, most of the time, I write my forms in standard, boring old HTML.  This works great, and I can use L<Data::Manager|http://search.cpan.org/dist/Data-Manager/> for my data validation quite easily, but what if I have a project I want done yesterday, that has GIGANTIC forms that I don't feel like going through and creating by hand?  This is a perfect scenario for  L<Form::Sensible::Reflector::DBIC|http://search.cpan.org/dist/Form-Sensible-Reflector-DBIC/>.  In short, if you want rapid prototyping that can actually stick around and be extensible for a while, this module's for you.
+
+=head2 What you Need
+
+=over 12
+
+=item A Catalyst Application
+
+That's what you're here for, right? :-)
+
+=item DBIx::Class
+
+My favorite ORM, but Form::Sensible::Reflector provides a base reflector class you could write a reflector for just about anything.
+This is what will be used specifically, as it gave me the best options data structure-wise from database<->forms.
+
+=item Form::Sensible::Reflector::DBIC
+
+This will be doing most of the work, at least generating the form.
+
+=back
+
+=head2 Getting Started
+
+Okay.  So we have a scenario where we have an existing database, an existing DBIx::Class schema, but we need a quick interface we can set up and customize very, very quickly.
+
+Let's start with our database schema (for convenience sake, we'll just use one table as an example):
+
+    package My::Form::Sensible::App::Schema::Result::Entry;
+
+    use base qw/DBIx::Class::Core/;
+
+    __PACKAGE__->load_components(qw/ InflateColumn::DateTime TimeStamp  /);
+    __PACKAGE__->table('entries');
+      
+    __PACKAGE__->add_columns(
+    entryid => {
+        data_type         => 'integer',
+        is_nullable       => 0,
+        is_auto_increment => 1,
+    },
+    title => {
+        data_type   => 'varchar',
+        size        => 150,
+        is_nullable => 0,
+    },
+    body => {
+        data_type   => "text",
+        is_nullable => 0,
+    },
+    author => {
+        data_type    => 'integer',
+        is_nullable  => 0,
+        render_hints => { field_type => "hidden" },
+    },
+    published => {
+        data_type    => 'bool',
+        is_nullable  => 0,
+        default      => 0,
+    },
+    created_at => {
+        data_type     => 'datetime',
+        is_nullable   => 1,
+        set_on_create => 1,
+    },
+    updated_at => {
+        data_type     => 'datetime',
+        is_nullable   => 1,
+        set_on_create => 1,
+        set_on_update => 1,
+    },
+    type => {
+        data_type   => 'enum',
+        is_nullable => 0,
+        is_enum     => 1,
+        extra       => { list => [qw/post page/] },
+    },
+    parent => {
+        data_type   => 'int',
+        is_nullable => 1,
+        default     => 0,
+    },
+    path => {
+        data_type   => 'varchar',
+        size        => '100',
+        is_nullable => 1,
+        default     => '1',
+    },
+    
+ );
+
+  __PACKAGE__->add_unique_constraint( [qw/ title /] );
+
+  __PACKAGE__->set_primary_key('entryid');
+
+  1;
+
+This is a typical, no frills DBIC schema representation of a table.  We need to add a few things to tell FS::Reflector::DBIC how to render things:
+
+   package  My::Form::Sensible::App::Schema::Result::Entry;
+
+   use base qw/DBIx::Class::Core/;
+
+   __PACKAGE__->load_components(qw/ InflateColumn::DateTime TimeStamp  /);
+   __PACKAGE__->table('entries');
+
+   __PACKAGE__->add_columns(
+    entryid => {
+        data_type         => 'integer',
+        is_nullable       => 0,
+        is_auto_increment => 1,
+    },
+    title => {
+        data_type   => 'varchar',
+        size        => 150,
+        is_nullable => 0,
+    },
+    display_title => {
+        data_type   => "varchar",
+        size        => 250,
+        is_nullable => 0,
+        render_hints => { field_type => "hidden" },
+    },
+    body => {
+        data_type   => "text",
+        is_nullable => 0,
+    },
+    author => {
+        data_type    => 'integer',
+        is_nullable  => 0,
+        render_hints => { field_type => "hidden" },
+    },
+    published => {
+        data_type    => 'bool',
+        is_nullable  => 0,
+        default      => 0,
+        render_hints => { on_label => "yes", off_label => "no", on_value => 1, off_value => 0 },
+    },
+    created_at => {
+        data_type     => 'datetime',
+        is_nullable   => 1,
+        set_on_create => 1,
+        render_hints  => { field_type => "hidden" },
+    },
+    updated_at => {
+        data_type     => 'datetime',
+        is_nullable   => 1,
+        set_on_create => 1,
+        set_on_update => 1,
+        render_hints  => { field_type => "hidden" },
+    },
+    type => {
+        data_type   => 'enum',
+        is_nullable => 0,
+        is_enum     => 1,
+        extra       => { list => [qw/post page/] },
+        render_hints =>
+          { options => [ { name => 'page', value => 'page' }, { name => 'post', value => 'post' } ] }
+       
+    },
+    parent => {
+        data_type   => 'int',
+        is_nullable => 1,
+        default     => 0,
+        render_hints => { field_type => "hidden" },
+    },
+    path => {
+        data_type   => 'varchar',
+        size        => '100',
+        is_nullable => 1,
+        default     => '1',
+        render_hints => { field_type => "hidden" },
+    },
+    
+ );
+
+ __PACKAGE__->add_unique_constraint( [qw/ title /] );
+
+ __PACKAGE__->set_primary_key('entryid');
+
+ 1;
+
+So, basically, if we don't want something showing up in our form, we mark it as hidden.  With things like an "enum", it's going to show up as a C<< <select> >> drop down, and we want to make sure we get the fields named correctly.
+
+So now, let's get a Catalyst controller up and going with our final reflector code:
+
+    ## this could be any action in your app, this exact one is just a for instance:
+    sub create : Chained('auth_base') PathPart('entry/new')  Args(0) {
+        my ( $self, $c ) = @_;
+
+        my $reflector = Form::Sensible::Reflector::DBIC->new;
+
+        my $form =
+          $reflector->reflect_from( $c->model('Database::Entry'), { form => { name => 'entry' } } );
+        my $renderer = Form::Sensible->get_renderer('HTML');
+        $c->stash( form => $renderer->render($form), form_object => $form, post_to => '/entry/new' );    # hate this
+
+    }
+
+
+The template to display this:
+
+    [% form.complete( post_to, 'POST') %]
+
+And that's really it.  Basically, I've tried to keep the SQL data types relatively intuitive.  If a column is supposed to take a textfield's worth of data, it's probably a textfield.  If it's got options, you get to decide what it should be.  At this point, things like C<enum> are C<< <select> >> fields. Form::Sensible is very flexible in allowing you to specify what you want to look like what, so post-creation, you can even munge the fields to look like what you want.
+
+That's really it folks.  Form::Sensible::Reflector::DBIC only does a few things: 
+
+=over 12
+
+=item Set up a bridge between Form::Sensible and DBIx::Class
+
+=item Allow you to have form definitions in one place, as opposed to two or three, like other systems might have you do.
+
+=item Quickly display your form without much fuss.
+
+=back
+
+Define your tables, tinker, display.  That's all.  I hate forms, let's make it painless :-)
+
+=head2 AUTHOR
+
+Devin Austin <dhoss at cpan.org>




More information about the Catalyst-commits mailing list