Jump to content

Form handling in MVC (validating / error reporting)


Wuhtzu

Recommended Posts

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 :)

 

 

 

 

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

 

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

...  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....

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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,

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

 

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.