Jump to content

Is a forms class practical?


Stooney

Recommended Posts

Would it be practical to have a class meant specifically for serving forms?  I've been developing a local auction site (which is already live) which has tons of different forms for both the user, moderator, and admin. 

 

I have a couple options (that I know of) in order to keep the code clean.

-Separate files for each form which will be included as needed.  I'm not a fan of over a hundred different files for forms personally. 

 

-A forms class.  Each form would be a method inside the class which can take arguments for the purpose of auto-filling and anything else I would need to make the forms dynamic.  I could see it a problem having one giant class included on every page when I'm only going to use a few of the forms at a time though.  So maybe break it into smaller classes (Bidding forms, User Account forums, etc). 

 

The idea is I want the forms to be as dynamic and manageable as possible.  Multiple scripts may call the same form, so I need a central point where the form comes from in case I ever need to add fields and whatnot.  That way I don't have to edit the form in each script where it occurs.

 

Hope I was clear.  Looking for opinions and/or other ideas you have.  Maybe I'm just looking at this wrong and have missed some simple solution somehow.

 

Link to comment
Share on other sites

I have a form class and a form renderer class

 

Rather than extend the form for each form in the site, I just use the base object, here an example of creating a form:

 

function makeForm() {

setDefaultPost('gender',1);

$form = new Form ( );

$form->setTitle('Register');

 

// login details

 

$form->addFieldSet('Login Details');

$form->addTextBox ( "username" );

$form->addValidator ( "username", ExpertValidate::requireAlnumLengthBetween ( 6, 20 ) );

$form->addPassBox ( "password" );

$form->addValidator ( "password", ExpertValidate::requireAlnumLengthBetween ( 6, 20 ) );

 

// personal details

 

$form->addFieldSet('Personal Details');

 

$form->addTextBox ( "firstName" );

$form->addValidator ( "firstName", ExpertValidate::requireLettersLengthBetween ( 2, 50 ) );

$form->addTextBox ( "lastName" );

$form->addValidator ( "lastName", ExpertValidate::requireLettersLengthBetween ( 2, 50 ) );

 

$form->addSelection ( "gender", false, array ('1' => 'Male', '0' => 'Female' ), true );

$form->setRequired("gender");

 

$form->addDatePicker ( "birthDate","Date of Birth" );

$form->setRequired("birthDate");

 

 

 

$form->addTextBox ( "securityQuestion" );

$form->addValidator ( "securityQuestion", ExpertValidate::requireAlnumLengthBetween ( 1, 200 ) );

 

$form->addTextBox ( "securityAnswer" );

$form->addValidator ( "securityAnswer", ExpertValidate::requireAlnumLengthBetween ( 1, 100 ) );

 

// contact details

 

$form->addFieldSet('Contact Details');

 

$form->addTextBox ( "emailAddress" );

$form->addValidator ( "emailAddress", ExpertValidate::requireEmailAddress () );

 

$form->addTextBox ( "mobilePhone" );

$form->addValidator ( "mobilePhone", ExpertValidate::optionalAlnumLengthBetween ( 1, 100 ) );

$form->addTextBox ( "msnContact" );

$form->addValidator ( "msnContact", ExpertValidate::optionalEmailAddress () );

 

$form->addTextBox ( "yahooContact" );

$form->addValidator ( "yahooContact", ExpertValidate::optionalStringLengthBetween ( 1, 100 ) );

 

$form->addTextBox ( "skypeContact" );

$form->addValidator ( "skypeContact", ExpertValidate::optionalStringLengthBetween ( 1, 100 ) );

$form->addTextBox ( "aimContact" );

$form->addValidator ( "aimContact", ExpertValidate::optionalStringLengthBetween ( 1, 100 ) );

$form->addTextBox ( "icqContact" );

$form->addValidator ( "icqContact", ExpertValidate::optionalStringLengthBetween ( 1, 100 ) );

$form->addSelection ( "showEmail", false, array ('0' => 'No', '1' => 'Yes' ), true );

$form->setRequired("showEmail");

$form->addAdvice('showEmail','Choose if members of the site can view your email address');

 

 

$form->addFieldSet('Security Measure');

$form->addCaptcha('securityCode');

$form->addValidator('securityCode',new CaptchaValidator('securityCode'));

 

 

$form->addHidden ( "id" );

return $form;

}

The form always deals with the $_POST array and populates itself

 

Validators are used to validate input but also to display advice about inputs i.e. what input is expected

 

edit note: I just changed the form instance to a larger one that showed off a bit more of the functionality

Link to comment
Share on other sites

I hadn't thought of rendering forms.  I was thinking more like static forms.  Here's an idea of what I had in mind, keep in mind it's just an example and nothing literal.  Just a mere idea.

 

<?php
class Form(){
public var $url;     //Would be set in the construct.  It would be something like http://site.com

//simple function to show the login form with the username autofilled if a valid userid was passed (maybe from a cookie)
//No css is used so the page calling the form has full control over it's visuals.  Although if the form included certain elements (div, table, etc) they would be given an id 
public function login_form($userid=0, $page='login.php'){
	if($userid!=0){
		$userid=$dbc->sanitize($userid);
		$get_username=$dbc->query("SELECT username FROM userstable WHERE id='$userid'");
		if($dbc->numrows($get_username)==1){
			$fetch=$dbc->nq_fetch($get_username);
			$username=$fetch[0];
		}
		else{
			$username='';
		}
	}
	else{
		$username='';
	}
	?>
	<form action="<?php echo $url.$page; ?>" method="post">
	Username: <input type="text" name="username" value="<?php echo $username; ?>">
	Password: <input type="password" name="password">
	<input type="submit" value="Login">
	</form>
	<?php
}
}
?>

Link to comment
Share on other sites

You are trying to do too much I think.

 

What you have is some form html and some database access.

 

It seems like a step backwards, but seperating the two makes life a lot easier.

 

I have the form as you saw, once validated the post array is passed to object(s) which populate themself.

 

Those objects are then created or updated with a single method call, the sql is generated based on the objects and relevant tables.

 

I've included a typical form submit flow below:

 

function executeAddSubmit() {

 

$form = $this->makeListForm ();

if (! $form->validate ( $_POST )) {

echo $form->render ( false, URL_ROOT . 'Lists/AddSubmit/' );

return;

}

 

$list = new FlList ( );

$list->populateFromArray ( $_POST );

$list->setUserId ( $_SESSION ['user_id'] );

$created = $this->dao->create ( $list );

 

if ($created) {

header ( "Location: " . URL_ROOT . "Lists/Main/" );

} else {

echo 'Sorry, there was a problem adding your new list';

}

 

}

 

Link to comment
Share on other sites

This is the flow of a typical edit scenario:

 

function executeMain() {

$user = $this->dao->load($_SESSION['user_id']);

$user->sendToPostArray ();

$form = $this->makeForm ();

echo $form->render ( false,URL_ROOT . 'EditAccountDetails/submit/' );

}

Link to comment
Share on other sites

If you want guidelines on a form system, try looking at different frameworks or CMS's to see how they handle theirs.

Most form systems are similar to what able posted, with maybe a few differences.

Just google "php framework" or "php cms" and you should find the popular open source projects. From there you can just browse the code.

 

There's also Thacmus, a project I'm working on, which has a pretty basic form system in place. You can browse around the form system's source in /lib/field, and the files you'll want are main.php, common.php, and form.php.

Along with all that, I have a Form tutorial. It deals with a previous version, so some of the information isn't accurate (I need to update that soon), but the basic concept is explained there.

NOTE: The source is read from files on the server, so it isn't exactly a code repository. You'll probably want to download the source if you want to browse more than a couple files.

If the site is slow or down, just go to the SourceForge page.

[/shameless plug]

Link to comment
Share on other sites

To be honest dynamic form building isn't that great because you're relying on the PHP to structure your html. Whereas really you should be putting your html into a separate file and having it nicely built by a great xhtml designer (if you have 1).

What happens when your design team want to have another field? Do you teach them how PHP works along with all your objects? Or do you say, "here you go mr. designer, this is the html file you want to change".

I think it's easier to just give html straight to the relevant person(s) and leave the backend processing to deal with the user input. Just my 2 pence really.

 

note: my method conforms to a MVC structure marginally better.

 

Link to comment
Share on other sites

It's true that it isn't great in all circumstances, just with almost every other convention that may be used.

However, dynamic forms can be more of a convenience if you have a large volume of generic forms which may handle large amounts of data. In that case it might be a little difficult for your XHTML designer - they have to make sure that if the form maybe used for 'revision' (editing), it would need to be auto-filled. Adding to that, say you have a combo box with large amounts of dynamic data - would a static html file be the best solution?

The XHTML designer would have to either learn PHP to insert the data - doubt he'll want to learn how to sanitize and all that - or a templating system that you would use - which could be a good or bad idea, just depending on what it is (maybe Smarty could do it much better).

Plus, it should be a relatively simple cut-and-paste effort to add new generic fields to a form. If you want a new text field with the name "bob", just type out "$form->addText('bob')" or for another implementation add "new FieldText('bob')" to the field array. If you're working on a team, you should be able to work together. Use the XHTML designer's knowledge to make the generic HTML output for your form, and leave it to yourself or your PHP coder(s) to work that into the form system.

 

On the other side, there are times where custom-designed forms are a good idea. The form system you have in place should have an open, clear-cut way to split processing from form rendering just in case. MVC would be a good option, and so would a simple division between processing and output (though it could be more error prone :( ).

Link to comment
Share on other sites

Absolutely, i'm not saying that the form should be a static page ;)

Merely, just not relying on the PHP to create the html.

 

Let me see if I can provide an example:

 

User_Auth (command)

<?php

class Auth_User extends Command {

public function execute(Request $request){
	$user = $request->getProperty('username');
	$pass = $request->getProperty('password');

	// Do auth stuff, connect to DB and do look-up.

	// If valid
	if($auth){
		$this->forward('members.php');
	} else {
		$template = new Template('login.html');
		$template->set('username',$user);
		$this->reload($template);
	}
}

public function reload($template){
	$template->render();
}

public function forward($page){
	header("Location:".$page);
}

}

?>

 

login.html

<html>
<head><title>Login</title></head>
<body>
<form method="POST" action="authenticate.php">
	<fieldset>
		<input type="text" name="username" value="<?=$username?>" />
		<input type="text" name="password" />
	</fieldset>
</form>
</body>
</html>

 

Probably not the best laid out example and there are few gaps (i.e. what is Template and how does it work?)

But here i've attempted to demonstrate that you have a controller (command) that deals with the Request (i.e. user input) processes it through the authentication mechanism (db lookup) and then depending on true/false forwards it onto the members.php (perhaps another command?, so of like chain of responsibility) or alternatively intialises a  template object, sets the username variable inside it, and then runs the process/render method by reloading the same page with the username field populated.

 

Definitely simplified of any error checking, and a lot of initialisation (i.e. how to get the command working in the first place, using a front controller, and the forwarding methodology), however hopefully you get the gist.

Link to comment
Share on other sites

I disagree entirely with the notion that having php output html breaks mvc/model2.

 

It is simply that some of the php is in the view layer (seperate form model from form renderer).

 

As to having the designer add additional form fields... I get to skip this, where is the data from the field kept? With my work 9/10 its in the db, so the extra field has to be added to the db, the business object and controller is regened to add the new field - and a few lines to the form abstraction is added, rather than then having to wait for the designer to edit the form.

Link to comment
Share on other sites

If you're generating html using PHP in your controller (i.e. echo, print, etc) you're not conforming to an MVC model at all...

 

How does my method imply that MVC only works with web apps? By combining layers of your application (controller/view) you're distorting the structure, whereas segregation should occur. The controller layer should bring together the view (be it html, or a java gui) and the model, process information sent to it (user input), alter the model accordingly and pass the altered model to the view (in java this needn't be done, with observer/observable available).

 

In the example of form building the controller is suddenly rendering the form html instead of the html page having the structure and the form object inserting the parameters in the correct places. At least this is the impression i'm getting. Without seeing the internals the form object I cannot be 100% that this is the method you're using (so i could always have the wrong end of the stick).

 

I hope i'm distinguishing the differences well enough.

 

I guess at the end of the day it all comes down to preference on method...

Link to comment
Share on other sites

Personally I developed a forms class and love it! I dont have to worry about the rendering, display etc.

 

One thing you may look into well is that for each free text field I require a minimum (or blank) / maximum length.

 

Instead of me writing custom code to validates the data isn't greater then maximum length, it dynamically checks it based on the name.

 

So all I do is create a form element, and the basic validation is there (required, length, data) etc. This helps take out the mundaine recoding of elements and adds basic protection to the form. Then if additional validation is needed, it is added.

Link to comment
Share on other sites

@aschk:

 

I never mentioned the controller. You can just call the form rendering class from the view.

 

How does my method imply that MVC only works with web apps?

 

You said

[...] dynamic form building isn't that great because you're relying on the PHP to structure your html. Whereas really you should be putting your html into a separate file [...]

and then you said
note: my method conforms to a MVC structure marginally better.

 

So paraphrasing your post, you're saying that the form class isn't good because it uses PHP to generate the HTML instead of manually typing the HTML. Therefore did your message imply that the model-view-controller pattern only applies to web applications.

Link to comment
Share on other sites

I think what it will come down to is just having both a Form management class and static files with forms and using either depending on specific needs.  Doesn't seem necessary to run small basic forms through a class (would take more work) but the class will be nice for larger forms with dynamic fields. 

 

As far as handling the submitted form I will probably just have other functions/classes handle that.  So if the user was using a form to update profile info, it'll be handled by the users class, not the forms class.  The forms class will just be there for generating/organizing forms (for now at least).

Link to comment
Share on other sites

My forms class is nothing more then a basic logic security restricter, and display.

 

I have sub-classes that inherit this super class.

 

IE class registration extends Form

 

the registration class holds the specific validation needs, as well as the code generating the display form. If i want to edit the form i simply need to open up my registration class, not the forms class. For me this works greate on tiny contact forms up to full blown user management forms.

Link to comment
Share on other sites

I made a forms class once....  It was for a specified layout which I don't expect to change soon....  The layout was static, but the elements could be done on the fly of course.  (Templates basically)

 

example:

 

function AddSelect($name, $options, $value, $label = '', $multiline = false, $id = '', $pad = false, $step = false, $buff = true) {
	$add = '';

	if(!empty($id)) $id = ' id="' . $id . '"';
	if($buff) {
		$cnt = $this->GenerateSelect($name, $id, $options, $value, $pad, $step);
	}
	else {
		$cnt = self::GenerateSelect($name, $id, $options, $value, $pad, $step);
	}

	if($multiline != false) {
		$add = <<<HERE

	<tr>
		<td colspan="2" class="form_select_multilabel">{$label}</td>
	</tr>
HERE;
		$add .= <<<HERE

	<tr>
		<td colspan="2" class="form_select_mutlioptions">
			{$cnt}
		</td>
	</tr>
HERE;
	}
	else {
		$add .= <<<HERE

	<tr>
		<td class="form_select_singlelabel">{$label}</td>
		<td class="form_select_singleoptions">
			{$cnt}
		</td>
	</tr>
HERE;
	}

	if($buff == true) {
		$this->html .= $add . PHP_EOL;
		return true;
	}
	return $add;
}

 

That's an example of the function I used the most.  It was convenient to be able to not have to code the php to make the <option value=""></option> everytime I needed a dynamic select...

 

I personally think a form class would be more useful in some situations than others.  In my case it was useful, but I've done somethings before where I can't imagine being tied to that layout.

Link to comment
Share on other sites

  • 4 weeks later...
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.