It would work for display and entry, but how would you load existing values into it? When it's posted, you still need an entirely separate PHP script to deal with the posted data.
| SitePoint Sponsor |




It would work for display and entry, but how would you load existing values into it? When it's posted, you still need an entirely separate PHP script to deal with the posted data.
Just a question...why not suggest the original poster simply use DOMDocument to build his output, save the result to string and display that? Try the following and see if you can adjust it to your needs.
PHP Code:
<?php
final class HTMLForm extends DOMDocument
{
public function __construct($method, $action)
{
parent::__construct("1.0", "utf-8");
$this->loadXML("<form></form>");
$this->documentElement->setAttribute('method', $method);
$this->documentElement->setAttribute('action', $action);
}
public function addButton()
{
$btn = $this->createElement('input');
$btn->setAttribute('type', 'button');
$this->documentElement->appendChild($btn);
return $btn;
}
public function render()
{
echo $this->saveXML($this->documentElement);
}
}
$form = new HTMLForm("post", "forms.php");
$button = $form->addButton();
$button->setAttribute('value', 'Hello world!');
$form->render();
?>
@serenarules, why is your class "final"? What purpose does that serve other then making it un-extend-able?
LOL! It's just an example. I just got into writing the the "finals" for an unrelated app today, so my muscle memory took over.



Indeed, why not! Thanks. I played around a bit with it.
PHP Code:<?php
final class HTMLForm extends DOMDocument
{
public function __construct($method, $action)
{
parent::__construct("1.0", "utf-8");
$this->loadXML("<form></form>");
$this->documentElement->setAttribute('method', $method);
$this->documentElement->setAttribute('action', $action);
}
public function addButton()
{
$btn = $this->createElement('input');
$btn->setAttribute('type', 'button');
$this->documentElement->appendChild($btn);
return $btn;
}
public function addButton1($attributes=array())
{
$btn = $this->createElement('input');
foreach($attributes AS $name => $value) {
$btn->setAttribute($name, $value);
}
$this->documentElement->appendChild($btn);
return $btn;
}
public function addTag($tag)
{
$tag = $this->createElement($tag);
$this->documentElement->appendChild($tag);
return $tag;
}
public function render()
{
echo $this->saveXML($this->documentElement);
}
}
$form = new HTMLForm("post", "forms.php");
$button = $form->addButton();
$button->setAttribute('value', 'Hello world!');
$br = $form->addTag('br');
$but = array();
$but['id'] = "b01";
$but['type'] = "button";
$but['name'] = "myButton";
$but['value'] = "Click me!";
$button1 = $form->addButton1($but);
$button1->setAttribute('style', 'color:red;');
$form->render();
?>
Denny Schlesinger
web services
The one catchpa is that, however you design a dom based engine, you need to call appendChild to attach the new element BEFORE you call setAttribute on it, otherwise, you tempt the wrath of the exception gods.




The DOM method has severe drawbacks with extendability.
In my form class I have elements for Date Picker, Colour Picker, Gmail style File Upload, Spell checked text boxes using HTML richedits. Each of these consists of more than on element. This is possible using objects but will start to become ugly if using the above DOM method.



I've been working on this Form class and I thought I'd share what I have so far. At this point I have two classes, a base Tag class and an Input class that extends the Tag class. I expect that I'll create child classes for the various input devices such as radio buttons, checkboxes, and select. These child classes will get a lot more functionality such as error checking. At this point I don't see a need to create classes for tags that don't send input to the server.
BTW, func_num_args() and func_get_arg() are really useful when you have an indeterminate number of arguments. Here are my two classes:
Using this code:PHP Code:class Tag {
protected $tag;
protected $attributes = array();
protected $content = array();
protected $xhtml;
public function __construct($tag, $xhtml = FALSE) {
$this->tag = $tag;
$this->xhtml = $xhtml;
}
public function setAttribute($name, $value) {
$this->attributes[] = array($name, $value);
}
public function setContent() {
$i = 0;
while ($i < func_num_args()) {
$this->content[] = func_get_arg($i++);
}
}
public function render() {
$result = "<{$this->tag}";
if (is_array($this->attributes)) {
foreach ($this->attributes AS $pair) {
$result .= " {$pair[0]}='{$pair[1]}'";
}
}
$result .= ">\n";
foreach($this->content AS $content) {
$isContent = TRUE;
if (is_object ($content)) {
$result .= $content->render();
} else {
if ($content != '') {
$result .= "{$content} \n";
} else {
$isContent = FALSE;
}
}
}
if ($isContent) {
$result .= "</{$this->tag}>\n";
}
return $result;
}
}
class Input extends Tag {
public function __construct($type, $name = '', $value = '') {
$this->tag = 'input';
$this->attributes[] = array('type', $type);
$this->attributes[] = array('name', $name);
$this->attributes[] = array('value', $value);
}
}
I generated the following form:PHP Code:$br = new Tag('br');
$month = new Input('text', 'month', $_POST['month']);
$month->setAttribute('size', '2');
$day = new Input('text', 'day', $_POST['day']);
$day->setAttribute('size', '2');
$year = new Input('text', 'year', $_POST['year']);
$year->setAttribute('size', '4');
$submit = new Input('submit', 'submit', 'Submit');
$reset = new Input('reset', '', 'Reset');
$legend = new Tag('legend');
$legend->setContent('Action');
$fieldset = new Tag('fieldset');
$fieldset->setAttribute('style', 'width:300px;');
$fieldset->setContent($legend, $month, $day, $year, $br, $submit, $reset);
$form = new Tag('form');
$form->setAttribute('action', $_SERVER['PHP_SELF']);
$form->setAttribute('method', 'post');
$form->setContent($fieldset);
echo $form->render();
Code HTML4Strict:<form action='/testing/tag.php' method='post'> <fieldset style='width:300px;'> <legend> Action </legend> <input type='text' name='month' value='' size='2'> <input type='text' name='day' value='' size='2'> <input type='text' name='year' value='' size='4'> <br> <input type='submit' name='submit' value='Submit'> <input type='reset' name='' value='Reset'> </fieldset> </form>
Denny Schlesinger
web services
Something that may not seems obvious is the need to distinguish required, invalid and feedback for invalid fields. Also, not just output every form element but build a unordered list. A form class that automates everything, but doesn't offer those functions is worth as much as a paper weight in my opinion. Normally I just hard code forms because I find using objects to represent each and every tag is tedious and It rarely has a advantage.
However, if your set on doing this I would recommend not cramming everything into one class. Have separate classes for separate elements.
Also, perhaps leave the logic to build the form outside of the tag classes. Instead create a separate class or set of classes to handle the responsibility of managing multiple tags and building the physical representation of the form.PHP Code:class Tag {
}
class InputTag extends Tag {
}
class SelectTag extends Tag {
}
class OptionTag extends Tag {
}
I've attempted to build something like this multiple times and each and every time its really more work then what its worth. There are just so many different exceptions and circumstances that it would be very difficult to automate them all. I don't think create classes to represent each tag is the answer though because its much easier just to write the mark-up. At least that is general what I find.
In the end, HTML is easy to write - it was made for that reason. Making a program to automate writing it isn't going to be useful because you'll end up writing more code in the PHP side than you would possibly need on the HTML side.
For example, look at all that code you've got for creating the form, and the little code that's actually output from it. Not really worth it...
Jake Arkinstall
"Sometimes you don't need to reinvent the wheel;
Sometimes its enough to make that wheel more rounded"-Molona


all that code you've got for creating the form, and the little code that's actually output from it. Not really worth it...
Good point. But laziness is mother of efficiency![]()
Last edited by Mastodont; Apr 5, 2009 at 05:39.
This something I've been exploring recently. Leave the mark-up in the view where it belongs, but create a object that is responsible for the data and configuration of the form based on the field name. $f would be instance of a class that implements the IFormConfig interface.
PHP Code:<?php
interface IFormConfig {
public function current($name);
public function required(); // :boolean
public function valid(); // :boolean
public function invalid(); // :boolean
public function feedback($echo=true); // :string
public function value($echo=true); // :string
public function type($echo=true); // :string
public function max($echo=true); // :string
}
?>
<?php $f->current('pwd'); ?>
<label for="user-pwd"><?php echo $f->required()?'*':''; ?>Password:</label>
<input type="<?php $f->type(); ?>" name="<?php $f->name(); ?>" value="<?php $f->value(); ?>" id="user-pwd" class="<?php $f->invalid()?'invalid':''; ?>">
<?php $f->current('email'); ?>
<label for="user-email"><?php echo $f->required()?'*':''; ?>Email:</label>
<input type="<?php $f->type(); ?>" name="<?php $f->name(); ?>" value="<?php $f->value(); ?>" id="user-email" class="<?php $f->invalid()?'invalid':''; ?>">
Something along these lines. Allow your view to do its job and controller to do its but allow them the ability to communicate between each other indirectly through another object.
PHP Code:<?php
interface IForm {
public function current($name);
public function addRequired($name);
public function addInvalid($name);
public function addValid($name);
public function addFeedback($name,$feedback);
public function addValue($name,$value);
public function addMax($name,$max);
public function addType($name,$type);
public function addName($name,$formName);
public function required(); // :boolean
public function valid(); // :boolean
public function invalid(); // :boolean
public function feedback($echo=true); // :string
public function value($echo=true); // :string
public function type($echo=true); // :string
public function max($echo=true); // :string
public function name($echo=true); // :string
}
class Form implements IForm {
protected $valid;
protected $invalid;
protected $required;
protected $feedback;
protected $type;
protected $value;
protected $name;
public function __construct() {
$this->_init();
$this->field = '';
}
protected function _init() {
$this->valid = array();
$this->invalid = array();
$this->required = array();
$this->feedback = array();
$this->type = array();
$this->value = array();
$this->name = array();
}
public function current($field) {
$this->field = $field;
}
public function addValid($name) {
$this->valid[] = $name;
}
public function addInvalid($name) {
$this->invalid[] = $name;
}
public function addRequired($name) {
$this->required[] = $required;
}
public function addFeedback($name,$feedback) {
$this->feedback[$name] = $feedback;
}
public function addType($name,$type) {
$this->type[$name] = $type;
}
public function addValue($name,$value) {
$this->value[$name] = $value;
}
public function addMax($name,$max) {
$this->max[$name] = $max;
}
public function addName($name,$formName) {
$this->name[$name] = $formName;
}
public function required() {
return in_array($this->field,$this->required);
}
public function invalid() {
return in_array($this->field,$this->invalid);
}
public function valid() {
return in_array($this->field,$this->valid);
}
public function feedback($echo=true) {
$feedback = array_key_exists($this->field,$this->feedback)?$this->feedback[$this->field]:'';
if($echo===true) {
echo $feedback;
}
return $feedback;
}
public function value($echo=true) {
$value = array_key_exists($this->field,$this->value)?$this->value[$this->field]:'';
if($echo===true) {
echo $value;
}
return $value;
}
public function type($echo=true) {
$type = array_key_exists($this->field,$this->type)?$this->type[$this->field]:'';
if($echo===true) {
echo $type;
}
return $type;
}
public function max($echo=true) {
$max = array_key_exists($this->field,$this->max)?$this->max[$this->field]:'';
if($echo===true) {
echo $max;
}
return $max;
}
public function name($echo=true) {
$name = array_key_exists($this->field,$this->name)?$this->name[$this->field]:$this->field;
if($echo===true) {
echo $name;
}
return $name;
}
}
$f = new Form();
$f->addName('user-name','user[user_name]');
$f->addName('pwd','user[pwd]');
$f->addName('email','user[email]');
$f->addName('first-name','user[first_name]');
$f->addName('last-name','user[last_name]');
$f->addName('submit','submit');
$f->addName('reset','reset');
$f->addType('user-name','text');
$f->addType('pwd','password');
$f->addType('email','text');
$f->addType('first-name','text');
$f->addType('last-name','text');
$f->addType('submit','submit');
$f->addType('reset','reset');
$f->addMax('user-name','15');
$f->addMax('pwd','10');
$f->addMax('email','100');
$f->addMax('first-name','20');
$f->addMax('last-name','20');
$f->addValue('submit','Submit Form');
$f->addValue('reset','Reset Form');
$f->addValue('action',$_SERVER['PHP_SELF']);
?>
<?php $f->current('action'); ?>
<form method="post" action="<?php $f->value(); ?>">
<fieldset>
<ol>
<li>
<?php $f->current('user-name'); ?>
<label for="user-name"><?php echo $f->required()?'*':''; ?>Name:</label>
<input type="<?php $f->type(); ?>" name="<?php $f->name(); ?>" value="<?php $f->value(); ?>" class="<?php echo $f->invalid()?'invalid':''; ?>" id="user-name">
<?php echo $f->feedback(false)?'<p>'.$f->feedback(false).'</p>':''; ?>
</li>
<li>
<?php $f->current('pwd'); ?>
<label for="pwd"><?php echo $f->required()?'*':''; ?>Password:</label>
<input type="<?php $f->type(); ?>" name="<?php $f->name(); ?>" value="<?php $f->value(); ?>" class="<?php echo $f->invalid()?'invalid':''; ?>" id="pwd">
<?php echo $f->feedback(false)?'<p>'.$f->feedback(false).'</p>':''; ?>
</li>
<li>
<?php $f->current('email'); ?>
<label for="email"><?php echo $f->required()?'*':''; ?>Email:</label>
<input type="<?php $f->type(); ?>" name="<?php $f->name(); ?>" value="<?php $f->value(); ?>" class="<?php echo $f->invalid()?'invalid':''; ?>" id="email">
<?php echo $f->feedback(false)?'<p>'.$f->feedback(false).'</p>':''; ?>
</li>
<li>
<?php $f->current('first-name'); ?>
<label for="first-name"><?php echo $f->required()?'*':''; ?>First Name:</label>
<input type="<?php $f->type(); ?>" name="<?php $f->name(); ?>" value="<?php $f->value(); ?>" class="<?php echo $f->invalid()?'invalid':''; ?>" id="first-name">
<?php echo $f->feedback(false)?'<p>'.$f->feedback(false).'</p>':''; ?>
</li>
<li>
<?php $f->current('last-name'); ?>
<label for="last-name"><?php echo $f->required()?'*':''; ?>Last name:</label>
<input type="<?php $f->type(); ?>" name="<?php $f->name(); ?>" value="<?php $f->value(); ?>" class="<?php echo $f->invalid()?'invalid':''; ?>" id="last-name">
<?php echo $f->feedback(false)?'<p>'.$f->feedback(false).'</p>':''; ?>
</li>
</ol>
</fieldset>
<fieldset>
<ol>
<li>
<?php $f->current('reset'); ?>
<input type="<?php $f->type(); ?>" name="<?php $f->name(); ?>" value="<?php $f->value(); ?>">
</li>
<li>
<?php $f->current('submit'); ?>
<input type="<?php $f->type(); ?>" name="<?php $f->name(); ?>" value="<?php $f->value(); ?>">
</li>
</ol>
</fieldset>
</form>HTML Code:<form method="post" action="/tags.php"> <fieldset> <ol> <li> <label for="user-name">Name:</label> <input type="text" name="user[user_name]" value="" class="" id="user-name"> </li> <li> <label for="pwd">Password:</label> <input type="password" name="user[pwd]" value="" class="" id="pwd"> </li> <li> <label for="email">Email:</label> <input type="text" name="user[email]" value="" class="" id="email"> </li> <li> <label for="first-name">First Name:</label> <input type="text" name="user[first_name]" value="" class="" id="first-name"> </li> <li> <label for="last-name">Last name:</label> <input type="text" name="user[last_name]" value="" class="" id="last-name"> </li> </ol> </fieldset> <fieldset> <ol> <li> <input type="reset" name="reset" value="Reset Form"> </li> <li> <input type="submit" name="submit" value="Submit Form"> </li> </ol> </fieldset> </form>



Nobody loves my code...
Guys, thanks for the feedback. I'm afraid I have not yet made my case. The reason we areis because you guys are looking at the problem top down (what does this form do?) while I'm looking at it from the bottom up (what does this tag do?). The way I see it there are tags that do things and should be objects and there are tags that just lie there and should be strings (literals or variables). In the code I've written you can freely mix objects and strings. Suppose you wanted to write an unordered list as HTML, it would look like this:
Now you can use $ul as the content of a tag, say a div:PHP Code:$ul = <<<LISTLIST
<ul id="latestlinks">
<li><a href="search.php?do=getnew">Latest Forum Posts</a></li>
<li><a href="search.php?do=noreplies">Unanswered Threads</a></li>
<li><a href="/marketplace/">Latest Marketplace Listings</a></li>
<li><a href="/contests/">Latest Design Contests</a></li>
</ul>
LISTLIST;
You can generate $ul or anything else any which way you want, just feed it to my Tag class as the final step to rendering the page. You could have included the div with the list into your body tag:PHP Code:$div = new Tag('div');
$div->setContent($ul);
echo $div->render();
All of a sudden all you need to build web pages is the Tag->render() function. You build the components in any way you want, writing it as straight html or generating it with some other code. At the end of the day, an html page is just a bunch of nested tags.PHP Code:$body = new Tag('body');
$div->setContent($menuBar, $logo, '<br>', $br, $div, $anotherDiv, $somethingElse, '<hr>', $footer);
echo $body->render();
Forms are not the only active tags. Say you have rows in a table with alternating backgrounds, a live object. You can extend the Tag class with an AltRow class that does that functionality for you. Or say you have the need to show random images, you could extend the Tag class with a RandomImg class.
Anyway, I'm excited!![]()
Denny Schlesinger
web services
Some people misunderstood me. I didn't mean to create the HTML using the DOM, it should already be made thanks to the XML file. What I meant by using the DOM is pulling out a select few values, name and value, and validation type data. The Form object would not need to be concerned with build the form it just needs the values to have something to process when the form is returned. XSLT would take the XML and output the HTML.
It seems just that though that is mixing presentation with logic and there is little benefit. Especially, if you work alongside a designers who need to be able to understand and manipulate the html. Very few designers would be able to manipulate that type of logic.
In the context of the back-end I would consider the HTML presentational. The view is responsible for the visual aspects of the application. The HTML is generally always considered to be part of the view thus it is the presentational when programming server side. If HTML was data then it would go in model. However, we all that the model is responsible for gathering the data and the view is responsible for displaying that data.
Errrm...I said XML not HTML. And yes XML is data and would go in the model, if you feel so inclined.
I was referring to captainccs implementation not yours to clear things up. What he is doing it presentational what you were doing not so much.Originally Posted by oddz
You should affix names or quotes to whom you are replying too, oddz.![]()
Not really on the hook if it works well for you then by all means use it. I'm just saying from my experience it rarely seems worth while to glorify HTML like that.
Bookmarks