[Catalyst] Putting more in the View

Ian Docherty icd at ecisecurity.com
Wed Feb 15 21:38:01 CET 2006


Hi

I have spend 5 weeks or more now on my first Catalyst application and 
feel that I am coming to grips with it now and am questioning some of my 
previous (bad) practices in light of what I am learning.

I note however that in all the examples of Catalyst I have seen, most of 
the work takes place in the controller. The Model is pretty sparce and 
there is nothing in the View (other than the Template).

This is my reasoning why this is wrong.

Take the example of a user administration set of pages. I implemented 
this with the following URIs

/user/list     To display a paged list of users and search facility.
/user/display/33    To display user id 33
/user/edit    To create a new user (just a blank form)
/user/edit/33   To edit existing user id 33
/user/save   The form submit action for a new user
/user/save/33    The form submit action for user id 33 edit

Now for the list and display functions I either pass an array of 
CDBI::Users or a single CDBI::User object. The Template then extracts 
the relevent fields (username, firstname, lastname date of birth etc.) 
directly from the user object ('aint. TT brilliant?)

The problem is with the edit -> save workflow.

If I pass a user object to the /user/edit/33 Template it is easy enough 
to pre-populate the form fields with the existing values in the same way 
as I do with the /user/display/33 URI.

In the 'traditional' manner, the /user/save/33 Controller would take the 
request->params and validate them. If valid the relevent user record 
would be updated and that would be the end of it. If invalid however we 
need to display an error message and re-populate the form with the 
additions or modifications made by the user so they can correct them. In 
other words sticky-forms.

This is where I have my first problem. I can't now pass the user object 
back to the Template, I need to pass the request->params to the 
template. I can either try to build up a CDBI::User object from the 
request->params and pass that to the Template (which does not work since 
CDBI cannot create a new object without writing it to the database. I 
understand that DBIC can do this but I have not yet gone down this 
route.). Or I can refrain from passing in a CDBI::User object to the 
Template in the first place but instead pass in all the parts of the 
user object separately to the stash.

I hope you are following this. Sorry for the long post but I am getting 
to the important bit now...

These are the relevent bits of code.

1. Decompose a User object into separate stash variables.
2. Put the stash variables into the form (this is done with TT).
3. Do simple validation when the form is submitted, e.g. ensure that 
mandatory fields are filled in.
4. Do simple manipulation of data, e.g. remove leading and trailing 
whitespace, convert checkboxes into true/false values, date formats etc.
5. Do database validation. e.g. is this username already taken
6. Compose a User object from the input data from (4) if the validation 
succeeds.
7. If validation fails, take the raw request->params (prior to (4)) and 
re-populate the form.

In my previous experience, and in many of the examples I have seen, 
steps 1,3,4,6 and 7 (and often 5 as well) takes place in the controller....

My reasoning is that 1,2,3,4 and 7 rightfully belong in the View not the 
Controller. 5 and 6 should be in the Controller/Model.

To this end I have developed my Catalyst application along these lines.

I have a Myapp::V::User->objectDecompose method that takes the User 
object passed to it from the URI /user/edit/33 code and puts the bits 
that the view needs into the Template. (Step 1)

I have MyApp::V::User->validate which takes the request->params and 
validates them (Step 3 and 4) and, on the assumption that the validation 
might fail, also implements the sticky-form (Step 7).

This leaves my controller fairly clean and easier to implement with all 
the messy validation and data transfer taking place in the View where in 
my opinion is should be.

I welcome any comments on this approach.

Regards
Ian















More information about the Catalyst mailing list