Wuhtzu Posted January 5, 2008 Share Posted January 5, 2008 Hey What is the best way to go around form handling in the MVC design pattern? With form handling i mean validating the input, display messages to the user and save data. Especially the displaying messages to the user I find tricky to get my head around. If some of the inputted data fails validation I need to display an error message to the user and if the data passes validation I need to display a success message. Since you don't want any control structures in your view, how do you go about displaying messages to the user? You could of course have multiple views to cover a single form, but that wouldn't be very neat. Should one write a form handler which takes care of the validation and message displaying so it is stashed away from the view - sort of what CakePHP does with it's html-helpers? I would really appreciate some inputs from you guys Thanks Wuhtzu Quote Link to comment Share on other sites More sharing options...
Aeglos Posted January 6, 2008 Share Posted January 6, 2008 You don't need separate views for the same form. In my home made framework I solved that issue with the following aproach: My validator class stores all error messages in an internal array. When a form is posted, I run validation methods on all the posted input and then retrieve the error list. If the error list is empty, I display an error view and the form again. If not, I process the form. Code wise it's something like this (very simplified theoric example) some_controller.php <?php public function insert_comments() { if ($_POST['submit']) { //Validate $this->validator->isUsername($_POST['username']); $this->validator->isText($_POST['text']); $this->e = $this->validator->getErrors(); if (empty($this->e)) { $this->form_process(); //MySQL insert, update or whatever. } else { //Error display $this->template->loadTemplate('errors'); $this->template->populateTemplate($this->e); $this->template->showTemplate(); //Normal form display $this->template->loadTemplate('comments'); $this->template->showTemplate(); } else { //Normal form display $this->template->loadTemplate('comments'); $this->template->showTemplate(); } } ?> So, the form normaly looks like this: -------------------- Comments: Username: [_______] Text: __________________ | | | | |_________________| [submit] --------------------- But, if there are errors, they are presented with: The following errors were encountered: * Error 1 * Error 2 * Error 3 -------------------- Comments: Username: [_______] Text: __________________ | | | | |_________________| [submit] --------------------- The error mini template is just a div with an ordered list inside. Easily skinable through CSS to stand out from the rest, and is universal for the whole site. The technique is also extensible so that the form with errors contains the submited (albeit faulty) input for accesibility's sake with a simple $this->populateTemplate($_POST); after the error template. Also, having control structures in your views is not bad. My views are full of foreachs and ifs, as do codeigniter views. Otherwise it's difficult to implement dynamic size tables or lists. In the end, use the method that suits you best. Try a couple of alternatives and see what works for you. I'm sure there will be more ways to solve this posted by the more knowledgeable members, and will be far more efficient and elegant than mine. Regards. Quote Link to comment Share on other sites More sharing options...
448191 Posted January 6, 2008 Share Posted January 6, 2008 I prefer something less hardcoded: <form id="contact" action="/Mail/Send" method="post" feedback="1" success="EMAIL_SENT"> <input name="name" type="text" value="" length="50" description="Uw naam"> <rule minlength="1" failure="FIELD_REQUIRED" /> <rule maxlength="255" failure="NAME_TOO_LONG" /> </input> <input name="email" type="text" length="50" description="Uw email"> <rule minlength="1" failure="EMAIL_REQUIRED" /> <rule pregmatch="/[A-Z0-9._%-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}/i" failure="EMAIL_INVALID" /> <rule maxlength="255" failure="EMAIL_TOO_LONG" /> </input> <input name="desc" type="text" value="(Leeg)" required="1" length="50" description="Beschrijving" > <rule maxlength="255" failure="MAIL_DESC_TOO_LONG" /> </input> <input name="message" type="textarea" required="1" length="500" description="Bericht" > <rule minlength="1" failure="MAIL_MSG_REQUIRED" /> <rule maxlength="2048" failure="MAIL_MSG_TOO_LONG" /> </input> <input name="submit" type="submit" value="Verstuur" /> </form> This XML is pretty painless to convert to XHTML, either the old fashioned way or with with XSLT. It's also easy to validate, and allows to map validation failure of constraints to messages (in a different configuration file). It's also fairly easy to map a rule to a validation method. In the example above, you probably prefer a standard email validation method, even though it's less configurable than using regex. Quote Link to comment Share on other sites More sharing options...
Liquid Fire Posted January 6, 2008 Share Posted January 6, 2008 I personally don't think the framework should have form validation because different people do it different ways. Some people like to do it server with php/asp/whatever, I personally don't like this way. Other people, like me, like to handle form validation with javascript so we don't have to reload the page with the errors, and I provide a javascript plugin to do that work inside my home made framework, you still have to implement inside the form view file. Quote Link to comment Share on other sites More sharing options...
redbullmarky Posted January 6, 2008 Share Posted January 6, 2008 ... Other people, like me, like to handle form validation with javascript so we don't have to reload the page with the errors, and I provide a javascript plugin to do that work inside my home made framework, you still have to implement inside the form view file. so that when i turn javascript off, i can submit your form and register with dodgy details and all sorts? thing is, if you have a nice class to do your validation, then you could always build in the functionality to generate the JS anyway. eg: <?php $validator = new Validator(); $validator->addString('name', *conditions*); $validator->addNum('age', *conditions*); if ($_POST) { $valid = $validator->validate($_POST); } $js = $validator->buildJS(); // js now contains the JS for your view sure, it's only one way of doing it and depends where you're coming from. best to try avoid relying on JS to handle the main validation, tho.... Quote Link to comment Share on other sites More sharing options...
448191 Posted January 6, 2008 Share Posted January 6, 2008 I personally don't think the framework should have form validation because different people do it different ways. Some people like to do it server with php/asp/whatever, I personally don't like this way. Other people, like me, like to handle form validation with javascript so we don't have to reload the page with the errors, and I provide a javascript plugin to do that work inside my home made framework, you still have to implement inside the form view file. Form validation with JavaScript only? Pardon me for being blunt, but that's just plain stupid. Quote Link to comment Share on other sites More sharing options...
Liquid Fire Posted January 6, 2008 Share Posted January 6, 2008 I guess your right that a framework "should" have a forum validation process but for my personal needs, it is not a high requirement. Quote Link to comment Share on other sites More sharing options...
dbo Posted January 6, 2008 Share Posted January 6, 2008 I prefer something less hardcoded: <form id="contact" action="/Mail/Send" method="post" feedback="1" success="EMAIL_SENT"> <input name="name" type="text" value="" length="50" description="Uw naam"> <rule minlength="1" failure="FIELD_REQUIRED" /> <rule maxlength="255" failure="NAME_TOO_LONG" /> </input> <input name="email" type="text" length="50" description="Uw email"> <rule minlength="1" failure="EMAIL_REQUIRED" /> <rule pregmatch="/[A-Z0-9._%-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}/i" failure="EMAIL_INVALID" /> <rule maxlength="255" failure="EMAIL_TOO_LONG" /> </input> <input name="desc" type="text" value="(Leeg)" required="1" length="50" description="Beschrijving" > <rule maxlength="255" failure="MAIL_DESC_TOO_LONG" /> </input> <input name="message" type="textarea" required="1" length="500" description="Bericht" > <rule minlength="1" failure="MAIL_MSG_REQUIRED" /> <rule maxlength="2048" failure="MAIL_MSG_TOO_LONG" /> </input> <input name="submit" type="submit" value="Verstuur" /> </form> This XML is pretty painless to convert to XHTML, either the old fashioned way or with with XSLT. It's also easy to validate, and allows to map validation failure of constraints to messages (in a different configuration file). It's also fairly easy to map a rule to a validation method. In the example above, you probably prefer a standard email validation method, even though it's less configurable than using regex. Excuse my ignorance on this. Doing it your way the validation rules don't get rendered in the HTML do they? I would guess not, I'm just not familiar with this. If they do get rendered in the HTML someone could modify the rules (or eliminate them completely) and post the form. Quote Link to comment Share on other sites More sharing options...
448191 Posted January 6, 2008 Share Posted January 6, 2008 This is an XML configuration file. It's used in 2 stages: first to render a visual representation, then to validate input and map to a feedback message. Both stages take place on the server. So no, the validation rules do not get rendered. Although they could be used to add client-side validation with JavaScript. Quote Link to comment Share on other sites More sharing options...
n3p3 Posted January 6, 2008 Share Posted January 6, 2008 448191, Could you please give an algorithm for the use of this xml configuration file with MVC. I trying to figure it out but I guess I can't.. First, for the visual representation, we need to parse this xml and generate a form in html. How we can integrate the rendered form to "view"? Then, I think we need a validate class. But if there is a failure how we can show the error messages? Thanks, Quote Link to comment Share on other sites More sharing options...
dbo Posted January 6, 2008 Share Posted January 6, 2008 Ahh cool. I do a dumbed down version of that then. I wrote a class that will validate a form based on rules in an XML file, but I separate out the design piece from it. Currently my class just handles the form validation and prefilling forms (on errors), but could pretty easily be expanded to include client side validation. Quote Link to comment Share on other sites More sharing options...
448191 Posted January 7, 2008 Share Posted January 7, 2008 Ahh cool. I do a dumbed down version of that then. I wrote a class that will validate a form based on rules in an XML file, but I separate out the design piece from it. Currently my class just handles the form validation and prefilling forms (on errors), but could pretty easily be expanded to include client side validation. This works pretty much the same. It still needs a template or XSL stylesheet for the visual representation. The XML just defines the properties, such as name, type, default value, charlength and label. Sorry if "visual representation" had you confused about that. 448191, Could you please give an algorithm for the use of this xml configuration file with MVC. I trying to figure it out but I guess I can't.. First, for the visual representation, we need to parse this xml and generate a form in html. How we can integrate the rendered form to "view"? Then, I think we need a validate class. But if there is a failure how we can show the error messages? Thanks, This is a bit much to casually demonstrate. Basically you create Form objects, with member elements, which in turn have member rules. Something basic like this would work: public function makeFromNode($node){ $formObject = new Backbone_Form_Object( $node->getAttribute('id'), $node->getAttribute('action'), $node->hasAttribute('method')? $node->getAttribute('method') : 'post', $input->hasAttribute('success')? $input->getAttribute('success') : null, $input->hasAttribute('failure')? $input->getAttribute('failure') : null ); foreach($node->getElementsByTagName('input') as $input){ $element = $formObject->addElement(new Backbone_Form_Element( $input->getAttribute('name'), $input->getAttribute('type'), $input->hasAttribute('value')? $input->getAttribute('value') : null, $input->hasAttribute('description')? $input->getAttribute('description') : null )); foreach($input->getElementsByTagName('rule') as $ruleNode){ $element->addRule(new Backbone_Form_Validator_Rule( $input->hasAttribute('maxlen')? $input->getAttribute('maxlen') : null, $input->hasAttribute('minlen')? $input->getAttribute('minlen') : null, $input->hasAttribute('pregmatch')? $input->getAttribute('pregmatch') : null, $input->hasAttribute('success')? $input->getAttribute('success') : null, $input->hasAttribute('failure')? $input->getAttribute('failure') : null )); } } return $formObject; } You pass the input to the Form object, something like $form->setInput($request->getPost()); Then you can validate. Internally, the form object delegates this reponsibilty to a form validator class. This simply traverses the elements and rules. Each element has a property to indicate if it has been successfully validated. When using Template View, you hust use a View Helper to render the form. Each element potentially has a property holding a message id. Depending on the validation status of the element, the View Helper fetches a message id, or none. The View Helper knows how to lookup this message and display it. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.