[Catalyst] help with Catalyst::Plugin::Form::Processor

Bill Moseley moseley at hank.org
Thu Dec 6 19:28:30 GMT 2007


On Thu, Dec 06, 2007 at 10:22:09AM -0800, Michael Higgins wrote:
> On Thu, 6 Dec 2007 10:16:05 -0800
> Michael Higgins <linux at evolone.org> wrote:
> > Thanks a lot for your replies. Yes I did set up and use the example
> > application. The problem is, I can't make any sense out of the
> > templates, which seem to do all the work. :(
> > 
> > I can make simple templates, no process, block or wrapper. So, I'm
> > trying to iterate, somehow, in some rational order, even sorted would
> > be fine, to expose all the fields in my form.
> > 
> > No wrapper, no Template magic, just the fields I've set up in the same
> > order each time. With labels, or any other key information, would be
> > nice...
> > 
> > So, what is the simplest example of returning the form object fields
> > in a form in TT?

It's a framework and no scaffolding. ;)

I'm sure you know this, but forms are objects that are a collection of
fields.

Fields are a given type that know how to validate their input,
localize error messages, and move the valid input into an internal
representation (e.g. a date string into a DateTime object).  Fields
also know how to go the other direction -- from a DateTime object to
one or a collection of fields.  (Although, I think RHTMLO handles that
much better.)

The form knows how to validate each field and preform other logic
related to the given form (is a full address entered if the billing
address is checked?).

If the form inherits from a "model" class then the form also knows how
to populate possible options for a given field (select lists, radio
groups), and how to move the data between the form and the database.

Basically, it just a way to map and validate the data path between an
internal representation and an external one in single units called
forms.  The markup is, well, just an encoding layer.  The same form
would be used for non-html, like JSON, XMLRPC, cron jobs, etc.


> Manually set up the form:
> 
> <form name="boldata" action="[% Catalyst.uri_for('/banpdfs/Create_bol')
> %]" method="post"> <fieldset>
>         <legend>Data</legend>
> 
> 
> Manually set up the order of fields:
> 
> [% SET fieldlist = ['sh_name','cn_name'] %]

You could also do this if you don't care about order:

    FOR field in form.fields;

> That reference my labels:
> 
> [% FOREACH labk IN fieldlist %]
> 
> I can expose the form field, finally:
> 
> [% SET f = form.field(labk) %]
> 
> <p><label for="[% f.name %]">[% labels.$labk %]</label><input type="[%
> f.type %]" name="[% f.name %]" id="[% f.name %]" value="[% f.value %]">
> </p>

And a field can have labels, too.



> What can I do with C::P::Form::Processor (aside from trying to hook
> this to my DBIC classes) to make this more... 'elegant'? ;-)

Well, I'm not sure what is your type of elegance, but what I like is:

1) I generate a form class that contains everything need to define and
validate a form.

2) Once the form is defined adding this to a very thin controller to
create and update, say, a user:

    sub edit : Local {
        my ( $self, $c, $user_id ) = @_;

        return unless $c->update_from_form( $user_id );

        $c->post_redirect( 'view', 'User Updated' );
    }

3) Creating a simple template that doesn't contain much markup but
gives the template author the freedom to customize the form but still
be consistent with all the other forms in the application.

The "form_wrapper" takes care of the <form> and action (we know the
action from $c->action) and displaying a list of any fields that might
have failed validation.

The "field()" macro displays a field's markup, including any error
messages, and possibly tips.  I put my fields in a <div> so the entire
field, label, javascript errors, etc. can be highlighted.

Sorry, that does mean you have to spend time once coding up a template
to handle the wrapper and field() macro, but I like it because I don't
want to type that stuff over and over again in the individual
templates.  And if I hard code a field as a text field and then later
want it to be a drop down or radio select I don't have to change
anything except the form.

[%
    # Form to edit a user

    page.title = form.item
        ? 'Create a new user'
        : 'Update user: ' _ form.item.full_name;


    WRAPPER form_wrapper;
        PROCESS user_data;
    END;
%]

[% BLOCK user_data %]
    <fieldset>
        <legend>User Data</legend>

        [%
            field('First name', 'first_name' );
            field('Last name', 'last_name' );

            field('Your US zip code', 'zip', 'Make one up!' );
            field('Your email', 'email' );
            field('Username', 'username' );

            '<p class="help">
                Select from our approved list of passwords.
            </p>';

            field( 'Password', 'password', 'Change your password' );
            field( 'Retype password', 'password_chk' );

            field('Your age', 'age',
                'This is only for targeted advertising' );

            field('Check to publish your personal info on the Internet', 'share' );

        %]
    </fieldset>
[% END %]

Of course, "user_data" can be in a separate file and used by multiple
fields that require user data.

Not sure if that qualifies for elegant or not.



-- 
Bill Moseley
moseley at hank.org




More information about the Catalyst mailing list