Skip to content

Instantly share code, notes, and snippets.

@dg
Created June 7, 2012 21:10
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save dg/2891542 to your computer and use it in GitHub Desktop.
Nette Framework Forms, year 2006
<?php
// history of Nette Framework Forms, year 2006
class NHtml
{
static protected $empty = array('img'=>1,'hr'=>1,'br'=>1,'input'=>1,'meta'=>1,'area'=>1,'base'=>1,'col'=>1,'link'=>1,'param'=>1);
static public function tag($tag, $attrs=NULL, $content=NULL)
{
self::openTag($tag, $attrs);
if (!isset(self::$empty[$tag])) {
echo $content, '</', $tag, '>';
}
}
static public function openTag($tag, $attrs=NULL)
{
echo '<', $tag;
if (is_array($attrs)) {
foreach ($attrs as $k => $v)
if ($v !== NULL) echo ' ', $k, '="', htmlSpecialChars((string) $v), '"';
}
echo isset(self::$empty[$tag]) ? ' />' : '>';
}
static public function closeTag($tag)
{
echo '</' . $tag . '>';
}
}
abstract class NFormControl
{
protected $name;
protected $label;
protected $attrs;
protected $value;
protected $required;
protected $rules = array();
protected $errors = array();
public function __construct($name, $label)
{
$this->name = $name;
$this->label = $label;
$this->attrs['name'] = $this->name;
$this->attrs['id'] = 'frm-' . $this->name;
}
abstract public function setValue($value);
public function getValue()
{
return $this->value;
}
public function setAttribute($name, $value)
{
$this->attrs[$name] = $value;
}
public function setDisabled($value=TRUE)
{
$attrs['disabled'] = $value ? 'disabled' : NULL;
}
abstract public function renderControl();
public function renderLabel()
{
NHtml::tag(
'label',
array('for' => $this->attrs['id']),
htmlSpecialChars($this->label)
);
}
public function addRule($message, $type, $arg)
{
$this->rules[] = array($message, $type, $arg);
}
protected function checkOnServer($type, $arg)
{}
protected function checkOnClient($type, $arg)
{}
public function validate()
{
$this->errors = array();
foreach ($this->rules as $rule)
{
list($message, $type, $arg) = $rule;
if (!$this->checkOnServer($type, $arg))
$this->errors[] = vsprintf($message, $arg);
}
return empty($this->errors);
}
public function isValid()
{
return empty($this->errors);
}
public function getErrors()
{
return $this->errors;
}
public function validationScript()
{
if (!$this->rules) return;
echo "var el = f.$this->name;\n";
foreach ($this->rules as $rule)
{
list($message, $type, $arg) = $rule;
$cond = $this->checkOnClient($type, $arg);
if ($cond) {
$message = addslashes(vsprintf($message, $arg));
echo " { el.focus(); alert('$message'); return false; }\n";
}
}
}
}
class NFormTextControl extends NFormControl
{
public function __construct($name, $label, $size, $password)
{
parent::__construct($name, $label);
$this->attrs['size'] = $size;
$this->attrs['type'] = $password ? 'password' : 'text';
}
public function setValue($value)
{
$this->value = trim($value);
}
public function renderControl()
{
$this->attrs['value'] = (string) $this->value;
NHtml::tag('input', $this->attrs);
}
public function setReadonly($value=TRUE)
{
$attrs['readonly'] = $value ? 'readonly' : NULL;
}
public function addRule($message, $type, $arg)
{
switch ($type) {
case 'required':
$this->required = TRUE;
break;
case 'length':
$this->attrs['maxlength'] = $arg[1];
break;
}
parent::addRule($message, $type, $arg);
}
protected function checkOnServer($type, $arg)
{
$val = $this->value;
switch ($type) {
case 'required':
return strlen($val) > 1;
case 'length':
return (strlen($val) >= $arg[0] && strlen($val) <= $arg[1]);
case 'email':
return preg_match('/^|[^@]+@[^.@]+\..+/', $val);
case 'regexp':
return preg_match($arg, $val);
case 'numeric':
return is_numeric($val);
case 'range':
return is_numeric($val) && $val >= $arg[0] && $val <= $arg[1];
}
return parent::checkOnServer($type, $arg);
}
protected function checkOnClient($type, $arg)
{
// trim
echo "var val = el.value.replace(/^\\s+/, '').replace(/\\s+\$/, '');\n";
switch ($type) {
case 'required':
echo "if (val=='')";
return TRUE;
case 'length':
echo "if (val.length<", (int) $arg[0], " || val.length>", (int) $arg[1], ")";
return TRUE;
case 'email':
echo 'if (!val.test(/^|[^@]+@[^.@]+\..+/))';
return TRUE;
case 'regexp':
echo "if (!val.test($arg))";
return TRUE;
case 'numeric':
echo "if (!val.test(/^-?[0-9]*[.,]?[0-9]+$/))";
return TRUE;
case 'range':
echo "if (parseFloat(val)<", (int) $arg[0], " || parseFloat(val)>", (int) $arg[1], ")";
return TRUE;
}
return parent::checkOnClient($type, $arg);
}
}
class NFormTextAreaControl extends NFormTextControl
{
public function __construct($name, $label, $cols, $rows)
{
NFormControl::__construct($name, $label);
$this->attrs['cols'] = $cols;
$this->attrs['rows'] = $rows;
}
public function renderControl()
{
NHtml::tag('textarea', $this->attrs, htmlSpecialChars((string) $this->value));
}
}
class NFormFileControl extends NFormControl
{
public function setValue($value)
{
// must be array
$this->value = $value;
}
public function renderControl()
{
$this->attrs['type'] = 'file';
NHtml::tag('input', $this->attrs);
}
public function moveUploadedFile($path)
{
return move_uploaded_file($this->value['tmp_name'], $path);
}
protected function checkOnServer($type, $arg)
{
switch ($type) {
case 'required':
// TODO
case 'maxfilesize':
// TODO!
case 'mimetype':
// TODO!
}
return parent::checkOnServer($type, $arg);
}
}
class NFormHiddenControl extends NFormControl
{
public function setValue($value)
{
$this->value = (string) $value;
}
public function setDisabled($value=TRUE)
{}
public function renderControl()
{
$this->attrs['value'] = (string) $this->value;
$this->attrs['type'] = 'hidden';
NHtml::tag('input', $this->attrs);
}
public function renderLabel()
{}
}
class NFormButtonControl extends NFormControl
{
public function __construct($name, $label, $type)
{
parent::__construct($name, $label);
$this->attrs['type'] = $type;
}
public function setValue($value)
{}
public function renderControl()
{
$this->attrs['value'] = $this->label;
NHtml::tag('input', $this->attrs);
}
public function renderLabel()
{}
}
class NFormCheckboxControl extends NFormControl
{
public function setValue($value)
{
$this->value = (bool) $value;
}
public function renderControl()
{
NHtml::openTag('label', array('for' => $this->attrs['id']));
$this->attrs['type'] = 'checkbox';
$this->attrs['checked'] = $this->value ? 'checked' : NULL;
NHtml::tag('input', $this->attrs);
echo htmlSpecialChars($this->label);
NHtml::closeTag('label');
}
public function renderLabel()
{}
}
class NFormRadioControl extends NFormControl
{
protected $items;
public function __construct($name, $label, $items)
{
parent::__construct($name, $label);
$this->items = $items;
}
public function setValue($value)
{
$this->value = isset($this->items[$value]) ? $value : NULL;
}
public function renderControl()
{
$attrs = $this->attrs;
$id = $attrs['id'] . '-';
$attrs['type'] = 'radio';
foreach ($this->items as $key => $value) {
$attrs['id'] = $id . $key;
$attrs['value'] = $key;
$attrs['checked'] = $this->value == $key ? 'checked' : NULL;
NHtml::openTag('label', array('for' => $attrs['id']));
NHtml::tag('input', $attrs);
echo htmlSpecialChars($value);
NHtml::closeTag('label');
NHtml::tag('br');
}
}
protected function checkOnServer($type, $arg)
{
switch ($type) {
case 'required':
return $this->value !== NULL;
}
return parent::checkOnServer($type, $arg);
}
}
class NFormSelectControl extends NFormControl
{
protected $items;
protected $keys;
public function __construct($name, $label, $items, $size, $multiple)
{
parent::__construct($name, $label);
$this->attrs['size'] = $size;
$this->attrs['multiple'] = $multiple ? 'multiple' : NULL;
if ($multiple) $this->attrs['name'] .= '[]';
$this->items = $items;
$this->keys = array();
foreach ($items as $key => $item) {
if (is_array($item))
foreach ($item as $key => $foo) $this->keys[$key] = TRUE;
else
$this->keys[$key] = TRUE;
}
}
public function setValue($value)
{
$this->value = array();
foreach ((array) $value as $val) {
if (isset($this->keys[$val])) $this->value[] = $val;
}
}
public function renderControl()
{
NHtml::openTag('select', $this->attrs);
$attrs = array();
$selected = array_flip($this->value);
foreach ($this->items as $key => $value) {
$group = is_array($value);
if ($group)
NHtml::openTag('optgroup', array('label' => $key));
else
$value = array($key => $value);
foreach ($value as $key2 => $value2) {
$attrs['value'] = $key2;
$attrs['selected'] = isset($selected[$key2]) ? 'selected' : NULL;
NHtml::tag('option', $attrs, htmlSpecialChars($value2));
}
if ($group) NHtml::closeTag('optgroup');
}
NHtml::closeTag('select');
}
protected function checkOnServer($type, $arg)
{
switch ($type) {
case 'required':
return !empty($this->value);
}
return parent::checkOnServer($type, $arg);
}
}
class NForm
{
const POST = 'post';
const GET = 'get';
protected $name;
protected $attrs;
protected $controls = array();
protected $hasFile = FALSE;
protected $hasRules = FALSE;
protected $submitValues;
protected $submitted;
public function __construct($name='', $method = self::POST)
{
$this->name = $name;
$this->attrs['method'] = $method;
$this->attrs['action'] = $_SERVER['PHP_SELF'];
if ($method == self::GET) $values = $_GET;
else $values = $_POST + $_FILES;
$this->submitted = isset($values['_f']) && ($values['_f'] === $name);
if ($this->submitted) $this->submitValues = $values;
}
public function setAction($action)
{
$this->attrs['action'] = $action;
}
protected function add($name, $control)
{
if (isset($this->controls[$name])) {
throw new Exception("Control '$name' exists yet.");
}
$this->controls[$name] = $control;
if (isset($this->submitValues[$name]))
$control->setValue($this->submitValues[$name]);
}
public function addText($name, $label, $size=NULL)
{
return $this->add($name, new NFormTextControl($name, $label, $size, FALSE));
}
public function addPassword($name, $label, $size=NULL)
{
return $this->add($name, new NFormTextControl($name, $label, $size, TRUE));
}
public function addTextArea($name, $label, $cols, $rows)
{
return $this->add($name, new NFormTextAreaControl($name, $label, $cols, $rows));
}
public function addFile($name, $label)
{
$this->hasFile = TRUE;
return $this->add($name, new NFormFileControl($name, $label));
}
public function addHidden($name)
{
return $this->add($name, new NFormHiddenControl($name, NULL));
}
public function addCheckbox($name, $label)
{
return $this->add($name, new NFormCheckboxControl($name, $label));
}
public function addRadio($name, $label, $items)
{
return $this->add($name, new NFormRadioControl($name, $label, $items));
}
public function addSelect($name, $label, $items, $size=NULL, $multiple=FALSE)
{
return $this->add($name, new NFormSelectControl($name, $label, $items, $size, $multiple));
}
public function addSubmit($name, $label)
{
if (isset($this->submitValues[$name]))
$this->submitted = $name;
return $this->add($name, new NFormButtonControl($name, $label, 'submit'));
}
public function addButton($name, $label)
{
return $this->add($name, new NFormButtonControl($name, $label, 'button'));
}
public function addImage($name, $src, $alt)
{
if (isset($this->submitValues[$name . '_x']))
$this->submitted = $name;
$c = new NFormButtonControl($name, NULL, 'image');
$c->setAttribute('src', $src);
$c->setAttribute('alt', $alt);
return $this->add($name, $c);
}
public function getControl($name)
{
return $this->controls[$name];
}
public function setDefaults($values)
{
foreach ($values as $name => $value)
if (isset($this->controls[$name]))
$this->controls[$name]->setValue($value);
}
public function getValues()
{
$values = array();
foreach ($this->controls as $name => $control)
$values[$name] = $control->getValue();
return $values;
}
public function addRule($name, $message, $type, $arg=NULL)
{
$this->hasRules = TRUE;
$this->controls[$name]->addRule($message, $type, $arg);
}
public function validate()
{
$this->errors = array();
foreach ($this->controls as $control)
if (!$control->validate())
{
$this->errors = array_merge($this->errors, $control->getErrors());
}
return empty($this->errors);
}
public function getErrors()
{
return $this->errors;
}
public function isSubmitted($name=NULL)
{
return $name === NULL
? (bool) $this->submitted
: $this->submitted === $name;
}
public function renderBegin()
{
$this->attrs['onsubmit'] = $this->hasRules ? "return validate$this->name(this)" : NULL;
$this->attrs['enctype'] = $this->hasFile ? 'multipart/form-data' : NULL;
NHtml::openTag('form', $this->attrs);
echo "\n<div>";
NHtml::tag('input', array(
'type' => 'hidden',
'name' => '_f',
'value' => $this->name,
));
echo "</div>\n";
}
public function renderControl($name)
{
$this->controls[$name]->renderControl();
}
public function renderLabel($name)
{
$this->controls[$name]->renderLabel();
}
public function renderForm()
{
$this->renderBegin();
if ($this->isSubmitted()) {
if (!$this->validate()) {
echo "<ul style=\"color:red\">\n";
foreach ($this->getErrors() as $error)
echo "\t<li>", htmlSpecialChars($error), "</li>\n";
echo "</ul>\n\n";
}
}
echo "\n<table>\n";
foreach ($this->controls as $control) {
echo "<tr>\n\t<th>";
$control->renderLabel();
echo "</th>\n\t<td>";
$control->renderControl();
echo "</td>\n</tr>\n\n";
}
echo "</table>\n";
echo "</form>\n";
echo "<script type=\"text/javascript\">\n";
echo "/* <![CDATA[ */\n";
echo "function validate$this->name(f) {\n";
foreach ($this->controls as $control)
$control->validationScript();
echo " return true\n";
echo "}\n";
echo "/* ]]> */\n";
echo "</script>\n";
}
}
$countries = array(
'Europe' => array(
'CZ' => 'Czech Republic',
'SK' => 'Slovakia',
),
'US' => 'United States',
);
$sex = array(
'm' => 'male',
'f' => 'female',
);
$form = new NForm('login');
$form->addText('name', 'Name:', 10);
$form->addPassword('password', 'Password:', 10);
$form->addCheckbox('accept', 'I agree');
$form->addFile('avatar', 'Avatar:');
$form->addHidden('userid');
$form->addSelect('country', 'Country:', $countries);
$form->addRadio('sex', 'Gender:', $sex);
$form->addTextArea('note', 'Note:', 30, 5);
$form->addSubmit('submit', 'Send');
$form->addImage('submit2', 'image.gif', 'alternative text');
$form->addRule('name', 'Enter your name', 'required');
$form->addRule('name', 'The password must have at least 3 characters', 'length', array(3, 20));
$default = array(
'accept' => TRUE,
'userid' => 12345,
'country' => 'CZ',
'sex' => 'm',
'note' => 'Nette Forms!',
);
if ($form->isSubmitted()) {
echo 'Submitted';
} else {
$form->setDefaults($default);
}
$form->renderForm();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment