Re: [Catalyst] Where should constraints go
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@lists.rawmode.org Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.rawmode.org/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Where should constraints go
On 03/11/06, Ian Docherty [EMAIL PROTECTED] 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@lists.rawmode.org Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.rawmode.org/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Where should constraints go
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 Directorcontracts 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@lists.rawmode.org Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.rawmode.org/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Where should constraints go
From: Ian Docherty [EMAIL PROTECTED] 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@lists.rawmode.org Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.rawmode.org/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Where should constraints go
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@lists.rawmode.org Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.rawmode.org/ Dev site: http://dev.catalyst.perl.org/ ___ List: Catalyst@lists.rawmode.org Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.rawmode.org/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Where should constraints go
On 11/3/06, Ian Docherty [EMAIL PROTECTED] 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@lists.rawmode.org Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.rawmode.org/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Where should constraints go
On 11/3/06, Ian Docherty [EMAIL PROTECTED] 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=errorUsername 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@lists.rawmode.org Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.rawmode.org/ Dev site: http://dev.catalyst.perl.org/