[Catalyst] Putting more in the View

Bill Moseley moseley at hank.org
Thu Feb 16 17:32:43 CET 2006


On Thu, Feb 16, 2006 at 11:19:08AM +0000, Ian Docherty wrote:
> 
> FormValidator will help me to make my form validation code cleaner. (I
> still need to research this more).

I know lots of people use FormValidator, but I got really tired
fighting with it.  Take a look at the other options available before
making a decision.  Specifically, take a look at Rose::HTML::Objects
and see if that fits with your thinking.

> I gather that you are doing the database insert and update (via ORM) in
> your Form class? I can't decide if this is good or bad. It hides some of
> the business logic in a class and it is not so easy to see the logic in
> the controller.

I don't agree.  The form object is an interface that knows how to
convert data from its internal format to a format used for user I/O
(which in my case with HTML forms is simply a hash).  Obviously,
validation has to be part of that process.  If a field is a date then
it should be a valid date.  If the field is a login name then it must
be unique (which means checking the database).  If it's a select then
it must be a valid value, and those valid values may (or may not)
have come from the database via relationships.

The controller's job, on the other hand, is to update, say, a user's
profile.  The controller doesn't really need to know what specific
fields to update -- it just needs to display the form, and then pass
the request parameters to the form and know if anything is updated.

Yes, it's hiding complexity.


> However I like the idea of simplifying the Controller. That is what I
> was aiming towards. What you do however is to hide much of the
> complexity in the Form class (which is no bad thing). However much of
> the complexity still remains.

But that complexity is the same for all my forms, so instead of
having it in all my controllers it's all in one place.

> One final request. It would help me greatly if I could see an example of
> your WS2::Form::Admin::Person class. I am still unsure how you have
> implemented it (as a Plugin for example, or how you have implemented the
> $c->form_posted method).

package WS2::Form::Admin::Person;
use strict;
use warnings;
use base 'Form::Model::CDBI';


sub object_class { 'DB::Person' }



sub profile {
    my ( $self ) = @_;
    my $profile = {

        required => {
            first_name      => 'Text',
            last_name       => 'Text',
            email           => 'Email',
            login           => 'Text',
            status          => 'Select',
            roles           => 'Multiple',
        },

        optional => {
            url             => 'Text',
            bio             => 'HtmlArea',

            phone           => 'Text',
            address1        => 'Text',
            address2        => 'Text',
            city            => 'Text',
            state           => 'Select',
            zip             => 'USZipcode',

            bill_office     => 'Text',
            bill_attention  => 'Text',
            bill_address1   => 'Text',
            bill_address2   => 'Text',
            bill_city       => 'Text',
            bill_state      => 'Select',
            bill_zip        => 'USZipcode',
            bill_phone      => 'Text',

            time_zone       => 'Select',

            password        => 'Password',
            password_chk    => 'Password',
            organizations   => 'Multiple',  # A person can belong to many organizations
        },

        dependency => [
            [qw/ password password_chk / ],
            [qw/ address1 city state zip /],
            [qw/ bill_address1 bill_city bill_state bill_zip /],
        ],

        # login must be unique in the database

        unique => [qw/ login /],

    };
}

sub init {
    my $self = shift;

    my $return = $self->SUPER::init(@_);


    # on a new person, require password
    unless ($self->item) {
        $self->field($_)->required(1) for qw/ password password_chk /;
    }

    return $return;
}



sub validate_password_chk {
    my ( $self, $field ) = @_;

    $field->add_error('Passwords do not match')
        unless $field->value eq $self->field('password')->value;

    $field->add_error('Password must be different from old password')
        if $field->value eq $self->field('old_password')->value;
}

sub cross_validate {
    my $self = shift;

    my $pf = $self->field('password');

    # Tell Model::CDBI to not update the password field unless
    # it's entered.

    $pf->noupdate(1) unless $pf->value;
}


1;


-- 
Bill Moseley
moseley at hank.org




More information about the Catalyst mailing list