Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Catalyst: Users

Where should constraints go

 

 

Catalyst users RSS feed   Index | Next | Previous | View Threaded


ian at iandocherty

Nov 3, 2006, 6:40 AM

Post #1 of 17 (718 views)
Permalink
Where should constraints go

Where should the various constraint values go in my MVC structure? For
example the Model defines the size of each field in (for example) a
username field in the User database table as being 16 characters max.

I am using FormValidator to validate the username field by calling a
validation routine in the Model-User as you can see in the code snippets
below.

In the example of the username, the constraints are in the length (no
more than 16 characters) and in the 'existing' to ensure that a username
is not chosen that already exists.

This seems to make sense to me since it is the Model that knows the
constraints of the database. If I were to do other (business logic) type
constraints then I would probably put in a business logic layer where
these constraints were defined.

The problem is in the View. To give a text error message that 'Must be
between 1 and 16 characters' is hard-coding a constraint directly in the
view which would need to be changed if the database schema changed.

I cannot think of a 'clean' way of getting these database constraints
from the Model into the View.

Anybody else tackled this issue?

Regards
Ian


The Database has a constraint.

CREATE TABLE user (
id int(11) NOT NULL auto_increment,
firstname varchar(32),
lastname varchar(32),
username varchar(16),
...

In my FormValidator I have something like.

constraint_methods => {
user_username => [.
{
name => 'length',
constraint =>
MyApp::Schema::User::validate_username_length(),
},
{
name => 'existing',
constraint =>
MyApp::Schema::User::validate_username_existing($c, $user),
},
],


The input form using TT is something like.

<tr>
<th align="right">Username</th>
<td align="left"><input type="text" size="44"
name="user_username" value="[% user.username %]"></td>
</td>
[% IF missing.user_username %]
<td align="left" class="error">Must not be blank</td>
[% ELSIF invalid.user_username.length %]
<td align="left" class="error">Must be between 1 and 16
characters</td>
[% ELSIF invalid.user_username.existing %]
<td align="left" class="error">Sorry, that username is already
taken</td>
[% END %]
</tr>






_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


fireartist at gmail

Nov 3, 2006, 7:01 AM

Post #2 of 17 (710 views)
Permalink
Re: Where should constraints go [In reply to]

On 03/11/06, Ian Docherty <ian [at] iandocherty> wrote:
> Where should the various constraint values go in my MVC structure? For
> example the Model defines the size of each field in (for example) a
> username field in the User database table as being 16 characters max.
>
> I am using FormValidator to validate the username field by calling a
> validation routine in the Model-User as you can see in the code snippets
> below.
>
> In the example of the username, the constraints are in the length (no
> more than 16 characters) and in the 'existing' to ensure that a username
> is not chosen that already exists.
>
> This seems to make sense to me since it is the Model that knows the
> constraints of the database. If I were to do other (business logic) type
> constraints then I would probably put in a business logic layer where
> these constraints were defined.
>
> The problem is in the View. To give a text error message that 'Must be
> between 1 and 16 characters' is hard-coding a constraint directly in the
> view which would need to be changed if the database schema changed.
>
> I cannot think of a 'clean' way of getting these database constraints
> from the Model into the View.
>
> Anybody else tackled this issue?

I made on very basic start [1] on being able to automatically create
constraints from the database column types. At the moment it only
supports mysql, and it's also probably very out-of-sync with the
current svn trunk - but I'd /really/ like to see it finished, and I
/really/ don't have any time to work on it, so if you want to take a
look and do something with it, that'd be great.
My primary goal was to get it working with HTML::Widget as
H-W-Constraint-DBIC [2], but there's no reason it couldn't be
integrated with any other validation package.

[1] http://dev.catalyst.perl.org/repos/bast/branches/DBIx-Class/columns_info_for
[2] http://dev.catalystframework.org/repos/Catalyst/trunk/HTML-Widget-Constraint-DBIC/

Carl

_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


moseley at hank

Nov 3, 2006, 7:23 AM

Post #3 of 17 (716 views)
Permalink
Re: Where should constraints go [In reply to]

On Fri, Nov 03, 2006 at 02:40:13PM +0000, Ian Docherty wrote:
> This seems to make sense to me since it is the Model that knows the
> constraints of the database. If I were to do other (business logic) type
> constraints then I would probably put in a business logic layer where
> these constraints were defined.

I do it in both places. If the username is unique then it's
constrained that way in the database.

I don't use FormValidator but I do have a form object that validates
parameters -- so it would also check if the username was unique (even
though it can't know for sure until it tries to do the insert). It
would then set an error message on that field "name is not unique in
the database", for example.

> The problem is in the View. To give a text error message that 'Must be
> between 1 and 16 characters' is hard-coding a constraint directly in the
> view which would need to be changed if the database schema changed.

I would think your form processing would detect that the username is,
say, grater than 16 chars and set the error message. Then your view
template would only need to display the error set in the form object
instead of being concerned with what the specific error message is.

I'm not sure where internationalization of the error message would
take place, though. I might be tempted to pass the language into the
form object.

I'm never clear where forms go in the MVC structure. In my App
directory I have:

$ls -1
Controller
Form
Menu
Model
View

--
Bill Moseley
moseley [at] hank


_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


ian at iandocherty

Nov 3, 2006, 7:33 AM

Post #4 of 17 (717 views)
Permalink
Re: Where should constraints go [In reply to]

Carl Franks wrote:
>
> I made on very basic start [1] on being able to automatically create
> constraints from the database column types. At the moment it only
> supports mysql, and it's also probably very out-of-sync with the
> current svn trunk - but I'd /really/ like to see it finished, and I
> /really/ don't have any time to work on it, so if you want to take a
> look and do something with it, that'd be great.
> My primary goal was to get it working with HTML::Widget as
> H-W-Constraint-DBIC [2], but there's no reason it couldn't be
> integrated with any other validation package.
>
> [1]
> http://dev.catalyst.perl.org/repos/bast/branches/DBIx-Class/columns_info_for
>
> [2]
> http://dev.catalystframework.org/repos/Catalyst/trunk/HTML-Widget-Constraint-DBIC/
>
>
> Carl
Carl
Creating the constraints is not really the problem. Your approach
certainly helps and one that any ORM should include. I can see that it
would take a fair amount of work to cover all bases. For example, if a
constraint was put on a DATE field such that it could not be later than
NOW and no earlier than NOW - 20 Days. (for example).

Putting these sort of constraints is the duty of either the database
level (where they naturally go anyway) or perhaps in the business logic
layer.

My problem is finding a clean way of getting these constraints out of
the Model and into the View so that I can generate meaningful error
messages without hard-coding them in the templates. By 'clean' I mean
not having to code the Controller to act as the middle-man and just pass
them from the Model to the View.

Perhaps I am expecting too much.


_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


fireartist at gmail

Nov 3, 2006, 8:15 AM

Post #5 of 17 (700 views)
Permalink
Re: Where should constraints go [In reply to]

On 03/11/06, Ian Docherty <ian [at] iandocherty> wrote:
> Carl Franks wrote:
> >
> > I made on very basic start [1] on being able to automatically create
> > constraints from the database column types. At the moment it only
> > supports mysql, and it's also probably very out-of-sync with the
> > current svn trunk - but I'd /really/ like to see it finished, and I
> > /really/ don't have any time to work on it, so if you want to take a
> > look and do something with it, that'd be great.
> > My primary goal was to get it working with HTML::Widget as
> > H-W-Constraint-DBIC [2], but there's no reason it couldn't be
> > integrated with any other validation package.
> >
> > [1]
> > http://dev.catalyst.perl.org/repos/bast/branches/DBIx-Class/columns_info_for
> >
> > [2]
> > http://dev.catalystframework.org/repos/Catalyst/trunk/HTML-Widget-Constraint-DBIC/
> >
> >
> > Carl
> Carl
> Creating the constraints is not really the problem. Your approach
> certainly helps and one that any ORM should include. I can see that it
> would take a fair amount of work to cover all bases.
>
> Putting these sort of constraints is the duty of either the database
> level (where they naturally go anyway) or perhaps in the business logic
> layer.
>
> My problem is finding a clean way of getting these constraints out of
> the Model and into the View so that I can generate meaningful error
> messages without hard-coding them in the templates. By 'clean' I mean
> not having to code the Controller to act as the middle-man and just pass
> them from the Model to the View.

The purpose of the "columns_info_for" branch code is to mark columns
with such flags as
'data_type', 'size', 'length_in_bytes',
or for integers... 'is_unsigned', 'range_min', 'range_max'

Then you just need to tell the validation/form package which DBIC
column corresponds to the CGI parameter, and the validation/form
package should be smart enough to check the input against the flags
set, and set an appropriate error message if it fails.

So if your 'username' column is varchar(16), DBIC would mark it
data_type => 'varchar',
size => 16,
and if the input is longer than that, then the validation package can
set the message "must be no longer than 16 characters".
The HTML::Widget equivalent would be:
$w->constraint( String => 'username' );
$w->constraint( Length => 'username' )->max( 16 )->message( 'must be...' );

If your 'age' column is the mysql column "unsigned tinyint", then DBIC
would mark it
data_type => 'tinyint',
is_unsigned => 1,
range_min => 0,
range_max => 256.
Again, the validation package can set appropriate error messages if
the input doesn't match those specs.
The HTML::Widget equivalent would be:
$w->constraint( Integer => 'username' )->message( 'must be an integer' );
$w->constraint( Range => 'username' )->min( 0 )->max( 256 )->message( '...' );
Which should be entirely possible to automate.

> For example, if a
> constraint was put on a DATE field such that it could not be later than
> NOW and no earlier than NOW - 20 Days. (for example).

I don't get your example.
Is this 'constraint' something that's defined in the database as a
Stored Procedure or Function?
If so, then no, I don't see any way of automatically getting that
specification into the View, unless you use a database that lets you
use native perl-code functions, and you can use the exact same code in
the View, and you use some sort of mechanism to ensure that the
database function stays in sync with the View.

Carl

_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


dbix-class at trout

Nov 3, 2006, 8:26 AM

Post #6 of 17 (707 views)
Permalink
Re: Where should constraints go [In reply to]

Ian Docherty wrote:
> My problem is finding a clean way of getting these constraints out of
> the Model and into the View so that I can generate meaningful error
> messages without hard-coding them in the templates. By 'clean' I mean
> not having to code the Controller to act as the middle-man and just pass
> them from the Model to the View.
>
> Perhaps I am expecting too much.

No, I understand entirely, and you aren't expecting too much at all - except
perhaps any expectation that this would already be fully implemented :)

We're doing this in Reaction using Moose to provide an introspectable
metamodel so the update action class reflects its constraints off the model
and then the form reflects its field types off the update action and the
fields just have the constraints "already there" when they're doing
validation. It's been hard work and there's a lot of hard work still to come
but so far it works bloody well.

--
Matt S Trout Offering custom development, consultancy and support
Technical Director contracts for Catalyst, DBIx::Class and BAST. Contact
Shadowcat Systems Ltd. mst (at) shadowcatsystems.co.uk for more information

+ Help us build a better perl ORM: http://dbix-class.shadowcatsystems.co.uk/ +

_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


siracusa at gmail

Nov 3, 2006, 8:50 AM

Post #7 of 17 (707 views)
Permalink
Re: Where should constraints go [In reply to]

Keep in mind that there are at least three possible levels of
constraints in a database-backed web app.

1. Constraints enforced by the database (e.g., maximum length for a
varchar column)

2. The constraints of your object model (e.g., alpha-numeric
characters only in usernames)

3. Application constraints (e.g., usernames that begin with "acme_"
may not be registered using the public web site)

That's all for one piece of information: a username.

Database constraints apply "everywhere."

Object model constraints also might apply everywhere, by you may want
to bend the rules for some special cases. (If an object model
constraint really does apply everywhere, it should probably be moved
to the database, if possible.)

Application constraints are almost certain to change (e.g., internal
admin tools usually have fewer such constraints than public end-user
tools).

If you try to smoosh up all three of these kinds of constraints into a
single definition, much pain awaits you :) My preferred distribution
of responsibilities is:

1. Database constraints: defined in the database, and also reflected
(as much as possible) in the ORM-based classes.

2. Object model constraints: defined either in the ORM-based classes
or in classes that wrap them (if such things exist).

3. Application constraints: defined in form/field objects, which may
inspect the ORM constraints and use them as a starting point.

-John

_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


rbroom+catalyst at rbroom

Nov 3, 2006, 9:02 AM

Post #8 of 17 (705 views)
Permalink
Re: Where should constraints go [In reply to]

From: "Ian Docherty" <ian [at] iandocherty>

> Putting these sort of constraints is the duty of either the database
> level (where they naturally go anyway) or perhaps in the business logic
> layer.

Right, constraints can come from both. I think the question is how to communicate those contraints up the line, ultimately to the view. Which is what you said below. :)


> My problem is finding a clean way of getting these constraints out of
> the Model and into the View so that I can generate meaningful error
> messages without hard-coding them in the templates.

I don't have the communication from layer to layer all worked out, but an approach I've liked is to have errors (like constraint failures) communicated with standard message identifiers and know data. For instance, failing length of 'username' could propogate a message ID of ERR_USERNAME_LENGTH, and include data in a list: [1, 16]. From there, the view would be able to pull messaging based on language or other criteria and flesh it out with the data. In TT, maybe something like:

[% IF field.messages %]
[% FOR m = field.messages %]
[% sprintf( get_text(m.id), @{m.data} ) %]
[% END %]
[% END %]

The English message for ERR_USERNAME_LENGTH might be:

Must be between %u and %u characters



> Perhaps I am expecting too much.

I don't think so. I've seen this done pretty well, but am finding it to be a labor to get it all worked out under Catalyst.


btw, this general path isn't mine. I got it years ago, pre-catalyst, from another Cat-list person: Mark Blythe.


---
Rodney Broom


_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


ian at iandocherty

Nov 3, 2006, 10:35 AM

Post #9 of 17 (703 views)
Permalink
Re: Where should constraints go [In reply to]

Yes this pretty much agrees with my interpretation. It is not so much
the location of the constraint rules as how to propagate them to the
view (i.e the stash)

John Siracusa wrote:
> Keep in mind that there are at least three possible levels of
> constraints in a database-backed web app.
>
> 1. Constraints enforced by the database (e.g., maximum length for a
> varchar column)
>
> 2. The constraints of your object model (e.g., alpha-numeric
> characters only in usernames)
>
> 3. Application constraints (e.g., usernames that begin with "acme_"
> may not be registered using the public web site)
>
> That's all for one piece of information: a username.
>
> Database constraints apply "everywhere."
>
> Object model constraints also might apply everywhere, by you may want
> to bend the rules for some special cases. (If an object model
> constraint really does apply everywhere, it should probably be moved
> to the database, if possible.)
>
> Application constraints are almost certain to change (e.g., internal
> admin tools usually have fewer such constraints than public end-user
> tools).
>
> If you try to smoosh up all three of these kinds of constraints into a
> single definition, much pain awaits you :) My preferred distribution
> of responsibilities is:
>
> 1. Database constraints: defined in the database, and also reflected
> (as much as possible) in the ORM-based classes.
>
> 2. Object model constraints: defined either in the ORM-based classes
> or in classes that wrap them (if such things exist).
>
> 3. Application constraints: defined in form/field objects, which may
> inspect the ORM constraints and use them as a starting point.
>
> -John
>
> _______________________________________________
> List: Catalyst [at] lists
> Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
> Searchable archive:
> http://www.mail-archive.com/catalyst [at] lists/
> Dev site: http://dev.catalyst.perl.org/
>
>


_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


brian.kirkbride at deeperbydesign

Nov 3, 2006, 10:37 AM

Post #10 of 17 (718 views)
Permalink
Re: Where should constraints go [In reply to]

Rodney Broom wrote:
> I don't have the communication from layer to layer all worked out, but an
> approach I've liked is to have errors (like constraint failures) communicated
> with standard message identifiers and know data. For instance, failing length
> of 'username' could propogate a message ID of ERR_USERNAME_LENGTH, and
> include data in a list: [1, 16]. From there, the view would be able to pull
> messaging based on language or other criteria and flesh it out with the data.
> In TT, maybe something like:
>
> [% IF field.messages %] [% FOR m = field.messages %] [% sprintf(
> get_text(m.id), @{m.data} ) %] [% END %] [% END %]
>
> The English message for ERR_USERNAME_LENGTH might be:
>
> Must be between %u and %u characters
>


This is the approach I have taken in the past, although I hadn't included any
metadata (ie [1,16]) with the error_id. This fits into separation of business
and presentation logic nicely because the model is free to return an error that
has some semantic meaning "PASSWORD_TOO_SHORT", but the view is free to say
"Enter a longer password you submoron, you!" if need be.

For my Catalyst apps, I can either do something like:

[% c.format_error(error_id) %]

or

[% error_messages.$error_id %]

or even

[% error_messages.${lang}.${error_id} %]

to map the model-specified error to a presentable string for the view. I prefer
the first, but it does clutter the Application Context namespace somewhat.

Best,
Brian Kirkbride

_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


ian at iandocherty

Nov 3, 2006, 10:54 AM

Post #11 of 17 (709 views)
Permalink
Re: Where should constraints go [In reply to]

Brian Kirkbride wrote:
...
> This is the approach I have taken in the past, although I hadn't
> included any metadata (ie [1,16]) with the error_id. This fits into
> separation of business and presentation logic nicely because the model
> is free to return an error that has some semantic meaning
> "PASSWORD_TOO_SHORT", but the view is free to say "Enter a longer
> password you submoron, you!" if need be.
>
> For my Catalyst apps, I can either do something like:
>
> [% c.format_error(error_id) %]
>
> or
>
> [% error_messages.$error_id %]
>
> or even
>
> [% error_messages.${lang}.${error_id} %]
>
> to map the model-specified error to a presentable string for the
> view. I prefer the first, but it does clutter the Application Context
> namespace somewhat.
>
> Best,
> Brian Kirkbride

This is pretty much what I do via the FormValidator. I convert the
'missing' or the 'invalid' messages that it produces into the flags

[% missing.user_username %]
and
[% invalid.user_username.length %]
which then result in the error messages being produced.

I still need to give some thought to internationalisation, but that is
another question. :)

_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


siracusa at mindspring

Nov 3, 2006, 11:07 AM

Post #12 of 17 (717 views)
Permalink
Re: Where should constraints go [In reply to]

On 11/3/06, Ian Docherty <ian [at] iandocherty> wrote:
> Yes this pretty much agrees with my interpretation. It is not so much
> the location of the constraint rules as how to propagate them to the
> view (i.e the stash)

Do you mean for the purposes of client-side validation? Or do you
just mean how to display the (server-generated) error messages in the
view?

If you mean the latter, the way I do it is to pass in a form object as
a single parameter (usually named "form"). The form object itself has
a list of (possibly localized) error messages, as does each field
object contained in the form object. All of these messages are
generated (by a $form->validate() call) before the form object is
passed to the template.

In the template, there's a place for form-wide errors to appear (if
any) plus a place near each field for field-specific errors to appear.
IMO, all required data should already exist before anything is passed
to a template. The template should just decide where things should
go, possibly with minor massaging for visual purposes.

-John

_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


ian at iandocherty

Nov 3, 2006, 11:16 AM

Post #13 of 17 (710 views)
Permalink
Re: Where should constraints go [In reply to]

Matt S Trout wrote:
> Ian Docherty wrote:
>> My problem is finding a clean way of getting these constraints out of
>> the Model and into the View so that I can generate meaningful error
>> messages without hard-coding them in the templates. By 'clean' I mean
>> not having to code the Controller to act as the middle-man and just
>> pass them from the Model to the View.
>>
>> Perhaps I am expecting too much.
>
> No, I understand entirely, and you aren't expecting too much at all -
> except perhaps any expectation that this would already be fully
> implemented :)
>
> We're doing this in Reaction using Moose to provide an introspectable
> metamodel so the update action class reflects its constraints off the
> model and then the form reflects its field types off the update action
> and the fields just have the constraints "already there" when they're
> doing validation. It's been hard work and there's a lot of hard work
> still to come but so far it works bloody well.
>
How the hell do you find the time to work on Catalyst and on Reaction at
the same time!!!

One thing occurs to me. What I want to do is to get parameters from the
Model (or the Business layer) into the View via the stash. So for a User
object I want be able to do something like.

<td align="left" class="error">Username must be between [%
schema.user.username.min %] and [% schema.user.username.max %]
characters</td>

The only problem now is how to get this information from the DBIC data
in a DRY manner.

My model namespace is not in Catalyst as in:-

MyApp::Model::DBIC::User

but is in
MyApp::Schema::User

so that I can use it outside my Catalyst application (for example in
cron jobs) so I don't have a mechanism to do something like.

$c->forward->('MyApp::Model::DBIC::User/constraints')

Where 'constraints' would populate the stash with all the constraints
for the User table.

The only option I can see is to do a call everywhere that I need
constraints as follows.

$c->stash->{schema}{user} = MyApp::Model::DBIC::User::Constraints();

And in there do the following.

sub Constraints {
return {
username => {
min => 0,
max => 16,
},
firstname => {
min => 0,
max => 32,
},
};
}

Carl Franks has proposed a method using 'columns_info_for' which I will
have to give some more thought to and this may remove my worry that by
doing the above I am not doing it in a DRY manner.



_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


siracusa at gmail

Nov 3, 2006, 11:46 AM

Post #14 of 17 (718 views)
Permalink
Re: Where should constraints go [In reply to]

On 11/3/06, Ian Docherty <ian [at] iandocherty> wrote:
> One thing occurs to me. What I want to do is to get parameters from the
> Model (or the Business layer) into the View via the stash. So for a User
> object I want be able to do something like.
>
> <td align="left" class="error">Username must be between [%
> schema.user.username.min %] and [% schema.user.username.max %]
> characters</td>

Warning! Localization alert! :) Like I said before, I don't think
you really want to be passing things to the view at that granularity.
It makes for some vary hairy form templates--one for each locale, to
boot.

If you whip up all this stuff *before* passing it off to the template,
you get templates like this (shown using Mason with a
"designer-friendly" syntax for the form/fields which just translates
deterministically into the corresponding method calls at runtime):

<% '/messages.mc', %ARGS %>

<% 'START_FORM' |fm %>

<table>

<tr>
<td class="label"><% 'USERNAME:LABEL' |f %></td>
<td class="field"><% 'USERNAME:FIELD' |f %></td>
</tr>

<tr>
<td class="label"><% 'PASSWORD:LABEL' |f %></td>
<td class="field"><% 'PASSWORD:FIELD' |f %></td>
</tr>

<tr>
<td colspan="2"><% 'LOGIN_BUTTON:FIELD' |f %></td>
</tr>

</table>

<% 'END_FORM' |fm %>

That's one form template for all supported languages, complete with
extremely granular, localized error messages. (e.g., "The username
'whatever' is already taken. Please choose another.") The form-wide
messages go in the message box produced (or not, if no messages) at
the top by messages.mc. The per-field errors are returned by the
"USERNAME:FIELD" calls and go under each field.

Even ignoring localization, you will save much sanity by constructing
all this stuff "perl-side" before passing it off to a template.

-John

_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


dbix-class at trout

Nov 3, 2006, 11:56 AM

Post #15 of 17 (715 views)
Permalink
Re: Where should constraints go [In reply to]

Ian Docherty wrote:
> This is pretty much what I do via the FormValidator. I convert the
> 'missing' or the 'invalid' messages that it produces into the flags
>
> [% missing.user_username %]
> and
> [% invalid.user_username.length %]
> which then result in the error messages being produced.
>
> I still need to give some thought to internationalisation, but that is
> another question. :)

Since C::P::I18N relies on stuff that expects a dictionary per thing, I've
rather enjoyed

$c->localize("Created [_quant,...]", $created);

and similar for use in Reaction

--
Matt S Trout Offering custom development, consultancy and support
Technical Director contracts for Catalyst, DBIx::Class and BAST. Contact
Shadowcat Systems Ltd. mst (at) shadowcatsystems.co.uk for more information

+ Help us build a better perl ORM: http://dbix-class.shadowcatsystems.co.uk/ +

_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


laurent.dami at justice

Nov 5, 2006, 11:13 PM

Post #16 of 17 (655 views)
Permalink
RE: Where should constraints go [In reply to]

> De : Ian Docherty [mailto:ian [at] iandocherty]
> Envoyé : vendredi, 3. novembre 2006 15:40

> Where should the various constraint values go in my MVC
> structure? For example the Model defines the size of each
> field in (for example) a username field in the User database
> table as being 16 characters max.
>
> ...
>
> I cannot think of a 'clean' way of getting these database
> constraints from the Model into the View.
>
> Anybody else tackled this issue?
>


Hi Ian,

I am currently looking at this issue for a big intranet application where we have many business rules to validate. As you say, rules interfere both with models and views,
and it would be nice to avoid duplicating the information.

Now where should rules live ? Deriving rules from the database, as Carl suggested in this thread, is an excellent start, but it is not enough : there might be many things that a database cannot express, like regular expressions, contextual dependencies, or your example of date boundaries depending on the current date. On the other hand, form validation packages are often too much focused on the view and also fail to express the complex rules just mentioned.

The general problem is that the range of possible rules is very wide : some rules are quite simple, and for those we would like a short declarative language to express them, while other rules definitely need some computing power that goes beyond a declarative language.

So I tried to address this in Data::Domain, which was published on CPAN just 2 weeks ago. This module is designed for providing a compact way to express complex constraints about structured data (including lazy constraints that may inspect the surrounding context). It then generates a structured set of error messages that can be fed to the view, either server-side through Template Toolkit, or client-side through Ajax methods. Messages are either auto-generated or can be redefined by client code (for example for internalization). The general scenario is that you get structured data by piping the parameters of your HTML form through CGI::Expand; then you validate the whole tree, and get back a tree of error messages that can be mapped back to the form fields.

You may also want to have a look at Declare::Constraints::Simple, which addresses the same problem and has some similarities in design.

Best regards, L. Dami

_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


ian at iandocherty

Nov 6, 2006, 12:17 AM

Post #17 of 17 (659 views)
Permalink
Re: Where should constraints go [In reply to]

Laurent
Thank you for that information. I will certainly look at Data::Domain in
some detail. I don't know if I will move over to it since I have already
invested a lot of time and effort into using Data::FormValidator but I
will certainly look at it for my next project. :)

Regards
Ian C. Docherty (Icydee)
> Hi Ian,
>
> I am currently looking at this issue for a big intranet application where we have many business rules to validate. As you say, rules interfere both with models and views,
> and it would be nice to avoid duplicating the information.
>
> Now where should rules live ? Deriving rules from the database, as Carl suggested in this thread, is an excellent start, but it is not enough : there might be many things that a database cannot express, like regular expressions, contextual dependencies, or your example of date boundaries depending on the current date. On the other hand, form validation packages are often too much focused on the view and also fail to express the complex rules just mentioned.
>
> The general problem is that the range of possible rules is very wide : some rules are quite simple, and for those we would like a short declarative language to express them, while other rules definitely need some computing power that goes beyond a declarative language.
>
> So I tried to address this in Data::Domain, which was published on CPAN just 2 weeks ago. This module is designed for providing a compact way to express complex constraints about structured data (including lazy constraints that may inspect the surrounding context). It then generates a structured set of error messages that can be fed to the view, either server-side through Template Toolkit, or client-side through Ajax methods. Messages are either auto-generated or can be redefined by client code (for example for internalization). The general scenario is that you get structured data by piping the parameters of your HTML form through CGI::Expand; then you validate the whole tree, and get back a tree of error messages that can be mapped back to the form fields.
>
> You may also want to have a look at Declare::Constraints::Simple, which addresses the same problem and has some similarities in design.
>
> Best regards, L. Dami
>


_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/

Catalyst users RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.