Created
April 27, 2012 16:23
-
-
Save MadaraUchiha/2510553 to your computer and use it in GitHub Desktop.
Form class - Generate valid good looking forms with PHP.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Forms; | |
/** | |
* This file is supposed to give a good way of generating forms programmatically with PHP. | |
*/ | |
/* | |
* WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! | |
* ----------------------------------------------------------------------------------------------------------- | |
* None of the strings you see in the following classes are escaped/secured against any kind of | |
* SQL Injections, XSS attacks, or any other sort of attack for that matter! For your own safety | |
* Implement the necessary protections on any strings you use in these classes before entering them! | |
* ----------------------------------------------------------------------------------------------------------- | |
* WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! | |
* @package Classes | |
*/ | |
/** | |
* All containing nodes should implement this. | |
*/ | |
interface Contains_Nodes { | |
/** | |
* @abstract | |
* | |
* @param Node $node | |
* | |
* This method will add a node to the node list of the implementing object. | |
*/ | |
public function add(Node $node); | |
} | |
/** | |
* Base object for all Nodes. | |
*/ | |
class Node { | |
/** | |
* @var string $element Will hold the element name (or tag name) | |
*/ | |
public $element; | |
/** | |
* @var array $attribute_list Will hold all of the rest of the form's attributes such as ID, class and whatnot. | |
*/ | |
public $attribute_list = array(); | |
/** | |
* @var bool $self_contained Signifies whether the Node is self contained. Self contained nodes do not get a closing tag. | |
*/ | |
public $text; | |
public $self_contained = false; | |
const SELF_CONTAINED = true; | |
const NOT_SELF_CONTAINED = false; | |
const TAB = " "; | |
/** | |
* @param string $element | |
* @param string $text | |
* @param bool $self_contained | |
* @param array $attribute_list | |
* | |
* General constructor for nodes. Should be overridden regularly. | |
*/ | |
public function __construct($element, $text = "", $self_contained = false, array $attribute_list = array()) { | |
$this->element = $element; | |
$this->self_contained = $self_contained; | |
$this->text = $text; | |
$this->attribute_list = $attribute_list; | |
} | |
/** | |
* @return string | |
* | |
* General string generator for nodes. Should be overridden regularly. | |
*/ | |
public function __toString() { | |
//Open element | |
$result = "<{$this->element}"; | |
//Node list | |
$result .= $this->string_attribute_list(); | |
//Close element | |
$result .= ">"; | |
if (!$this->self_contained && !empty($this->text)) { | |
$result .= $this->text; | |
} | |
if (!$this->self_contained) { | |
$result .= "</{$this->element}>"; | |
} | |
return $result; | |
} | |
/** | |
* @return string | |
*/ | |
public function string_attribute_list() { | |
$result = ""; | |
if (!empty($this->attribute_list)) { | |
foreach ($this->attribute_list as $attr => $value) { | |
$result .= " {$attr}=\"{$value}\""; | |
} | |
} | |
return $result; | |
} | |
} | |
/** | |
* The Form object, will describe a single form. | |
* After constructing it is done, it should format into a cool, simple, valid, readable, HTML code. | |
*/ | |
class Form extends Node implements Contains_Nodes { | |
public $element = "form"; | |
public $self_contained = false; | |
/** | |
* @var Node[] $node_list This will hold all of the nodes in the form. Including fields and inputs. | |
*/ | |
public $node_list; | |
/** | |
* @var string $action Will hold the action for the form. This is a required field. | |
*/ | |
public $action; | |
/** | |
* @var string $method Will hold the form submission method for the form. Defaults to POST. | |
*/ | |
public $method = Form::METHOD_POST; | |
const METHOD_POST = 'POST'; | |
const METHOD_GET = 'GET'; | |
/** | |
* @param string $action Page to which the form submits. | |
* @param string $method POST or GET, will throw an exception otherwise. | |
* @param array $attribute_list Miscellaneous attributes for the form element. | |
*/ | |
public function __construct($action, $method = self::METHOD_POST, array $attribute_list = array()) { | |
$this->action = $action; | |
$this->method = $method; | |
$this->attribute_list = $attribute_list; | |
if (($method != self::METHOD_GET) && ($method != self::METHOD_POST)) { | |
throw new \Exception("Form method must be either POST or GET"); | |
} | |
} | |
/** | |
* @param Node $node Node to add. | |
* | |
* @return Form to not break the chain | |
*/ | |
public function add(Node $node) { | |
$this->node_list[] = $node; | |
return $this; | |
} | |
/** | |
* @return string Format and stringify the form. | |
*/ | |
public function __toString() { | |
//Open tag, usually <form ...> | |
$result = "<{$this->element} action=\"{$this->action}\" method=\"{$this->method}\""; | |
//Attribute list | |
$result .= $this->string_attribute_list(); | |
//Close opening tag | |
$result .= ">"; | |
//Loop through the nodes | |
foreach ($this->node_list as $node) { | |
$result .= "\n" . self::TAB . str_replace("\n", "\n" . self::TAB, $node->__toString()); | |
//The replace is to keep the code indented and formatted properly. | |
} | |
//Close form element | |
$result .= "\n</{$this->element}>"; | |
return $result; | |
} | |
} | |
/** | |
* Class to describe a single input node. | |
*/ | |
class Input extends Node { | |
public $element = "input"; | |
public $self_contained = true; | |
public $type; | |
public $label; | |
public $name; | |
public $default_value; | |
public $label_before_input = true; | |
/** | |
* @param string $type | |
* @param string $name | |
* @param Label $label | |
* @param string $default_value | |
* @param array $attribute_list | |
* | |
* Constructor for input node. | |
*/ | |
public function __construct($type, $name, Label $label, $default_value = "", array $attribute_list = array()) { | |
$this->type = $type; | |
$this->name = $name; | |
$this->label = $label; | |
$this->default_value = $default_value; | |
$this->attribute_list = $attribute_list; | |
} | |
/** | |
* @return string Formatted input HTML. | |
*/ | |
public function __toString() { | |
//Label element open (usually "<label" | |
$result = "<{$this->label->element}"; | |
//Begin attribute list | |
$result .= $this->label->string_attribute_list(); | |
//Close opening tag | |
$result .= ">"; | |
//If we want label before the input... | |
if ($this->label_before_input) { | |
$result .= "\n" . self::TAB . $this->label->text; | |
} | |
//Begin input element usually "<input ..." | |
$result .= "\n" . self::TAB . "<{$this->element} type=\"{$this->type}\" name=\"{$this->name}\""; | |
//Default value | |
if (!empty($this->default_value)) { | |
$result .= " value=\"{$this->default_value}\""; | |
} | |
//Attribute list | |
$result .= $this->string_attribute_list(); | |
//Close input element | |
$result .= ">"; | |
//If we want label after input | |
if (!$this->label_before_input) { | |
$result .= "\n" . self::TAB . $this->label->text; | |
} | |
//Close label element (usually "</label>" | |
$result .= "\n</{$this->label->element}>"; | |
/* | |
* FINAL RESULT should look like: | |
* <label [label-attributes]> | |
* [text-if-before] | |
* <input type=[type] name=[name] value=[value] [input-attributes] | |
* [text-if-after] | |
* </label> | |
*/ | |
return $result; | |
} | |
} | |
/** | |
* Class to describe a single label node. | |
* Labels should be contained inside of inputs on a 1:1 relationship. | |
*/ | |
class Label extends Node { | |
public $element = "label"; | |
/** | |
* @param string $text | |
* @param array $attribute_list | |
*/ | |
public function __construct($text, array $attribute_list = array()) { | |
$this->text = $text; | |
$this->attribute_list = $attribute_list; | |
} | |
/** | |
* @return string Returns label text only. Labels can only be part of inputs. | |
*/ | |
public function __toString() { | |
return $this->text; | |
} | |
} | |
/** | |
* Class to describe a single fieldset node. | |
* | |
* @implements Contains_Nodes | |
*/ | |
class Fieldset extends Node implements Contains_Nodes { | |
public $element = "fieldset"; | |
/** | |
* @var Node[] | |
*/ | |
public $node_list; | |
public $legend; | |
/** | |
* @param $legend | |
* | |
* Construct a fieldset element | |
*/ | |
public function __construct($legend) { | |
$this->legend = $legend; | |
} | |
/** | |
* @param Node $node | |
* | |
* @return Fieldset to not break the chain | |
* | |
* Add a node to the fieldset. | |
*/ | |
public function add(Node $node) { | |
$this->node_list[] = $node; | |
return $this; | |
} | |
/** | |
* @return string Generate a formatted node list of the fieldset. | |
*/ | |
public function __toString() { | |
//Open element (usually <fieldset) | |
$result = "<{$this->element}"; | |
//Attribute list | |
$this->string_attribute_list(); | |
//Close opening tag | |
$result .= ">"; | |
//Legend text | |
$result .= "\n" . self::TAB . "<legend>{$this->legend}</legend>"; | |
//Loop through node list | |
foreach ($this->node_list as $node) { | |
$result .= "\n" . self::TAB . str_replace("\n", "\n" . self::TAB, $node->__toString()); | |
//The replace is to keep the code indented and formatted properly. | |
} | |
//Close fieldset tag | |
$result .= "\n</{$this->element}>"; | |
return $result; | |
} | |
} | |
class Button extends Node { | |
public $element = "button"; | |
public function __construct($text, array $attribute_list = array()) { | |
parent::__construct($this->element,$text, Node::NOT_SELF_CONTAINED, $attribute_list); | |
} | |
} | |
class Submit extends Button { | |
public $type = "submit"; | |
public function __construct($text = "Submit", array $attribute_list = array()) { | |
$attribute_list["type"] = $this->type; | |
parent::__construct($text, $attribute_list); | |
} | |
} | |
/* | |
* Testing begins! | |
*/ | |
$form = new Form("index.php", Form::METHOD_GET); | |
$field = new Fieldset("Fieldset"); | |
$field->add(new Input("text", "name", new Label("Input inside of Fieldset"))); | |
$form | |
->add( | |
new Input( | |
"text", //Type | |
"test", //Name | |
new Label("Testing Input", array("class" => "label")), //Label | |
"Woot", //Default value | |
array("id" => "test") //Attribute List | |
) | |
) | |
->add(new Node("hr", "", Node::SELF_CONTAINED)) | |
->add(new Submit("Go")); | |
echo $form . "\n\n"; | |
echo "<pre>"; | |
echo print_r($form); | |
echo "</pre>"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment