How to design an HTML Form class

That sounds like a great idea!

One more thing. Your tag class shouldn't be concerned with the over content. It's purpose is basically to handle tags, i.e. to alter and render a tag with it's attributes. If you want to render an entire set of tags then that's a different class all together.

I see what you mean. I'll have to think about this.

In any case I thought this was about forms? O.o

Well, that's where I started. What do they call it? Drift? :lol:

$oUsernameField->addAttribute('max-length', '5');

cool

What's wrong with this? I suppose I can extend the Tag class to create special purpose classes, which is what I was thinking of doing with radio, checkbox, and select.

In my opinion, once you create a generic object that replaces a natural collection of objects, you lose all the benefits of OOP.

For example you wouldn't have a single login form object, you split it down into its base components and create an object to recompile these if necessary.

You are already being forced into extending Tag to create the radio, select & checkbox elements, it just seems messy to me.

I think you missed my point a little with my example, I was wondering how you would target a specific form element in a programmic manner. As far as I can see, you cannot with your solution.

I didn't miss it, I was being cheeky. wink

We have a saying in Spanish: "Neither bald nor with two wigs." How many classes do you want to have? One for each tag? That seems like overkill. I started with a form builder but in fact it uses a lot of tags besides the data input tags. I find myself using div, fieldset, legend, label, br, a, and a few others in forms. According to W3C there are some 90 xhtml tags. Where do you cut off?

I find it easier to build my forms in HTML and implement them through templates than writing a set of classes instead. My forms (once developed) seldomly change so creating them on the fly through code seems like much work for little benefit for me. And there's always the case where the class does not cover the functionality I need. I had the case where I needed to create dependant drop down select lists - does your class also generate the javascript for managing the dependant option elements? Creating multipage forms through code was also difficult for me, wether you use sessions or "fake" multipage through javascript by hiding form elements.

I do use code though to generate all kinds of lists in forms when the list options are dynamically created - but these classes are more like HTML widgets and do not depend on each other.

So from my experience I never found it worth to develop a set of classes that deal with creating forms and form elements - but I still haven't seen it all so I might be complety wrong smile

Hi

I agree with frabron. Be careful about abstracting things like HTML, which have unlimited ways of combination. Those tag-classes are just plain wrappers for HTML, and then you might as well write HTML, its simpler, shorter and more readable too!

A form however, can be tought of as an object, because it has members (the input-tags) that you want to do lots of things with. One is validation: add a validator to a form element, and upon displaying the form, show the error messages under the element if there are any errors. Another is filtering: add filters to the form elements so that the data is filtered before you pass it on to your buisiness logic. And then there is form populating (setting the data) and redisplaying the data when validation failed.. and so on.

Take a look at Zend_Form: http://framework.zend.com/manual/en/zend.form.html

Another approach could be to create a form class, some element classes, some validation classes and a form-renderer which takes as input only the form-object. The renderer would loop through the elements and produce the HTML. The renderer is plug-able (given to the form class as a parameter) and therefore one can switch between different renderers.

What I have noticed is that whenever one tries to abstract someting complex like HTML or SQL, you always end up with either having to write just as much code or not being able to specify all the details. You end up loosing the details, and then whenever you want to do something slightly different, you must either do it "manually" or add functionality to your classes...

I'm not saying that you should not abstract anything, but certain things gets really complicated when you try to abstract it. At least create a backdoor for each abstraction so that you may do it manually if neccessary.

Happy coding!

frabron and oeyvind, I agree that you can go overboard and the trick is to find a happy mid-point. That mid-point will not be the same for everyone. If you write a form now and then you might as well hand code the thing. If you spend most of your time writing forms then automation is going to be a big help. The way I decide it's time to create some automation is when I say to myself: "Gee, I don't want to write that code again!" I use all sorts of things from BBEdit text factories to functions that validate email and classes that write selects, radio buttons and checkboxes, which are the more complex input devices. The more complex an object is, the more it benefits from OOP.

You might ask why create a class for something as simple as a line break (<br />). For the inheritance! Everything in HTML is a tag so you might as well start there. Then if someone invents a new tag you can use your generic Tag class for it.

There is another consideration, you can use the OOP code in your live application or you can use it as a "FormBuilder." It can do more for you than a template. I use something like that to write the articles for my personal website. I write the article as a heredoc string and the essay template converts it into a complete static page. It also producs the text and links for my index page. All I have to do is copy and past.

Just find your own happy medium! wink

"Gee, I don't want to write that code again!"

That's why I use templates smiley

But I didn't want to distract you from building your Form class or convince you to let it be - I was just posting my experiences as a side note, well knowing that content of my post wasn't much aid to your problems.

... or you can use it as a "FormBuilder." ...

This is really one case where such a class is useful - because you build your form more or less by some definition, wether by other users or some other rule (db, file etc.)
I never tried this tho since mapping the form fields from such a form to a database is beyond my capabilites blush

Not to worry, I'm having a lot of fun playing with this class. It's early on so I don't know where it will wind up but all the guys here have been very helpful to get me thinking in the right direction.

This is really one case where such a class is useful - because you build your form more or less by some definition, wether by other users or some other rule (db, file etc.)
I never tried this tho since mapping the form fields from such a form to a database is beyond my capabilites blush

It doesn't have to that complicated. You can use your browser as the rendering engine. If you copy my Tag class example from this thread and run it as a php script (after removing the invisible characters the forum software adds for spaces ), the browser's "source view" has the finished template. smiley

Or you can save the page as a source file.

I don't know about anyone else but I know I'd find:

<form action="/" method="get">
    <label for="username">Username</label>
        <input type="text" name="username" />
    <label for="password">Password</label>
        <input type="password" name="password" />
    <input type="submit" value="Login" />
</form>

Much, much better than:

<?php
Tag::Get('form')->addAttribute('action', '/')->addAttribute('method', 'get')->AddTags(
    Tag::Get('label')->addAttribute('for', 'username')->setBody('Username'),
        Tag::Get('input')->addAttribute('type', 'text')->addAttribute('name', 'username'),
    Tag::Get('label')->addAttribute('for', 'password')->setBody('Password'),
        Tag::Get('input')->addAttribute('type', 'password')->addAttribute('name', 'password'),
    Tag::Get('input')->addAttribute('type', 'submit')->addAttribute('value', 'Login')
)->Render();

XML-style text is much more efficient and readable than we could do with object-based programming.

Theoretically this kind of stuff is good to mess around with, but realistically it just doesn't have a point.

If all you are going to do is render html tags, of course, you might as well just write the tags themselves. I hope you don't think that is the purpose of this exercise. wink

Mostly I do web apps and the user interface is mostly HTML forms that have to be populated with data and the incoming data has to be validated and stored or otherwise processed. Eventually the Form class or whatever results from this exercise will do a lot of heavy lifting, not just drawing pretty tags. smile

Next weekend I'll get around to writing a few more classes that actually do some useful work. cool

My form class works in a similar fashion to the solution posted (passing attributes).

The logic of the form should not be handled in the display logic. Why is maxlength set there? Why is whether it's disabled or not set there? It makes no sense controlling the behaviour of the form in the display routine. Similarly, you need to be able to control the display of a form on a per-form level.

Advantages of the form class:

repopulating from $_POST if it failed validation:

//rebuild $form
foreach ($_POST as $key => $value) {
    $form->get('key')->setAttribute('value', $value);
}

//reshow the form

Add validation to the elements:

$phone->validation = '^[0-9]+';
$phone->validationWarning = 'Your phone number can only contain numbers';

as long as you rebuild the same form object to deal with the result, you have a much more flexible system.

The problem you will run into with such a form class is the display of the form. Unless you have a very generic looking form with simple label/element on each line you'll want to do some styling on it.

I solved this by placing forms in the my template class like so:

[myform]
<div>Name: [myform field="name"]</div>
<div>Address: [myform field="address"]</div>
<div>Description:</div>
<div style="width: 100&#37;">[myform field="description" style="height: 100px"]</div>
[/myform]

Doing it like this allows keeping the behaviour of the form and the display of it entirely separate, I pass the form object to my template class which does the relevant replacements based on form name. The template has control over a few of the attributes such as style, and can override some others providing they're not set on the object itself.

Without the template, displaying the forms in a non-generic way is impossible. This method allows ultimate flexibility for structure, display and separating the business logic from the display logic.

Ok, it's a little extra set up but when you're dealing with sites with hundreds of forms, this certainly makes life a lot easier.

build HTML form visual part in PHP is a bad idea. just build the form use HTML not PHP.

just think about "html form " without visual part, then you probably do not want to build HTML Form visual part in php anymore.

from web server point of view, HTML form is just a string of key,value pair, no button, no text field, no maxlenght, not any thing related to visual part of HTML form.

This is how I do it too.

That said, you may want to consider how HTML elements are usually handled as objects, namely via DOM methods. The DOM already has createElement(), setAttribute(), etc. So you're basically reinventing the wheel when you create an OOP library for this. Why not use a DOM implementation in PHP to build the form and dump the underlying X(HT)ML?

This is what I'm doing now. The problem is that with a complex form there is a lot of clutter. Interspaced with the formatting tags there is quite a bit of php that corresponds to the form input elements. TomB is suggesting a Template class but that too is more work and it can be done instead with a heredoc variable:

<?php
$form = <<<FORMFORM
<form action="{$form->action}" method="{$form-> method}">
  <fieldset>
  <legend>Data</legend>
    <label class="form1Names" for="$form->input1Name}">Your name: </label>
    <input type="{$form->input1Type}" id="$form->input1Name}" name="$form->input1Name}" value="$form->input1Value}" />
  </fieldset >
  <br />
  <fieldset >
  <legend>Action</legend>
    <button type="submit" name="submit" value="submit">Click me!</button>
  </fieldset >
</form>
FORMFORM;

echo $form;
?>

For each form element there are one or more layout tags! The form actually has more layout than elements! Instead of a template I prefer to have the form in a separate file and use an include. At this point I'm just experimenting and appreciating all the input.

If the form's layout is a variable, there is no reason for that variable not to be one of the form's properties. wink

from web server point of view, HTML form is just a string of key,value pair, no button, no text field, no maxlenght, not any thing related to visual part of HTML form.

From a php point of view the form is the associative array $POST or $GET and $_FILE

This is what I think of when I say "template", actually. I use include files written in HTML with PHP inline syntax for inserting variables. I do it to keep all the markup out of my class definitions. For example, a login method might look like this:

Session.php:

class Session {

...

public function loginForm() {
ob_start();
include('Session.loginForm.php');
return ob_get_clean();
}

...

}

Session.loginForm.php:

<form ... >
<input name="var1" value="<?=$this->var1; ?>" />
<input name="var2" value="<?=$this->var2; ?>" />
<input type="submit" value="Login" />
</form>

I think we are on the same age. TomB suggested a "real" template class.

I like to think of php as "cascading includes" smiley

Template systems are superfluous in PHP, since PHP has its own "template" syntax. Smarty tags aren't much easier to read than PHP template tags, so why bother?

Oh Dear God! Please Not Another Php Is A Template Language Smarty Is Redundant Argument Argument. It'll Never End!!! Nooooo!!! >.>

LMAO!

Who's arguing? I stated a simple fact. The fact that it's a fact makes any argument moot. So argue away, if that's your idea of a good time, but I won't participate. smiley