<?php
/**
* Moc10 Library
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.TXT.
* It is also available through the world-wide-web at this URL:
* http://www.moc10phplibrary.com/LICENSE.TXT
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to hide@address.com so we can send you a copy immediately.
*
* @category Moc10
* @package Moc10_Form
* @author Nick Sagona, III <hide@address.com>
* @copyright Copyright (c) 2009-2011 Moc 10 Media, LLC. (http://www.moc10media.com)
* @license http://www.moc10phplibrary.com/LICENSE.TXT New BSD License
*/
/**
* Moc10_Form_Element
*
* @category Moc10
* @package Moc10_Form
* @author Nick Sagona, III <hide@address.com>
* @copyright Copyright (c) 2009-2011 Moc 10 Media, LLC. (http://www.moc10media.com)
* @license http://www.moc10phplibrary.com/LICENSE.TXT New BSD License
* @version 1.9.7
*/
class Moc10_Form_Element extends Moc10_Dom_Child
{
/**
* Form element value(s)
* @var string|array
*/
public $value = null;
/**
* Form element marked value(s)
* @var string|array
*/
public $marked = null;
/**
* Form element label
* @var string
*/
public $label = null;
/**
* Form element required property
* @var boolean
*/
public $required = false;
/**
* Form element validators
* @var array
*/
public $validators = array();
/**
* Form element errors
* @var array
*/
public $errors = array();
/**
* Form element allowed types
* @var array
*/
protected $_allowed_types = array('button', 'checkbox', 'file', 'hidden', 'image', 'password', 'radio', 'reset', 'select', 'submit', 'text', 'textarea');
/**
* Form element allowed validators
* @var array
*/
protected $_allowed_validators = array('AlphaNum', 'Alpha', 'Between', 'Email', 'Equal', 'GreaterThan', 'Length', 'LengthBet', 'LengthGT', 'LengthLT', 'LessThan', 'NotEmpty', 'NotEqual', 'Num', 'RegEx');
/**
* Language object
* @var Moc10_Language
*/
protected $_lang = null;
/**
* Constructor
*
* Instantiate the form element object
*
* @param string $type
* @param string $name
* @param string $value
* @param string|array $marked
* @param string $indent
* @throws Exception
* @return void
*/
public function __construct($type, $name, $value = null, $marked = null, $indent = null)
{
$this->_lang = new Moc10_Language();
// Check the element type, else set the properties.
if (!in_array($type, $this->_allowed_types)) {
throw new Exception($this->_lang->__('Error: That input type is not allowed.'));
} else {
// Create the element based on the type passed.
switch ($type) {
// Textarea element
case 'textarea':
parent::__construct('textarea', null, null, false, $indent);
$this->setAttributes(array('name' => $name, 'id' => $name));
$this->_nodeValue = $value;
$this->value = $value;
break;
// Select element
case 'select':
parent::__construct('select', null, null, false, $indent);
$this->setAttributes(array('name' => $name, 'id' => $name));
// Create the child option elements.
foreach ($value as $k => $v) {
$opt = new Moc10_Dom_Child('option', null, null, false, ($indent . ' '));
$opt->setAttributes('value', $k);
// Determine if the current option element is selected.
if ($v == $this->marked) {
$opt->setAttributes('selected', 'selected');
}
$opt->setValue($v);
$this->addChildren($opt);
}
$this->value = $value;
break;
// Radio element(s)
case 'radio':
parent::__construct('fieldset', null, null, false, $indent);
$this->setAttributes('class', 'radioBtnArea');
// Create the radio elements and related span elements.
$i = null;
foreach ($value as $k => $v) {
$rad = new Moc10_Dom_Child('input', null, null, false, ($indent . ' '));
$rad->setAttributes(array('type' => $type, 'class' => 'radioBtn', 'name' => $name, 'id' => ($name . $i), 'value' => $k));
// Determine if the current radio element is checked.
if ($v == $this->marked) {
$rad->setAttributes('checked', 'checked');
}
$span = new Moc10_Dom_Child('span', null, null, false, ($indent . ' '));
$span->setAttributes('class', 'radioPad');
$span->setValue($v);
$this->addChildren(array($rad, $span));
$i++;
}
$this->value = $value;
break;
// Checkbox element(s)
case 'checkbox':
parent::__construct('fieldset', null, null, false, $indent);
$this->setAttributes('class', 'checkBoxArea');
// Create the checkbox elements and related span elements.
$i = null;
foreach ($value as $k => $v) {
$chk = new Moc10_Dom_Child('input', null, null, false, ($indent . ' '));
$chk->setAttributes(array('type' => $type, 'class' => 'checkBox', 'name' => ($name . '[]'), 'id' => ($name . $i), 'value' => $k));
// Determine if the current radio element is checked.
if (in_array($v, $this->marked)) {
$chk->setAttributes('checked', 'checked');
}
$span = new Moc10_Dom_Child('span', null, null, false, ($indent . ' '));
$span->setAttributes('class', 'checkPad');
$span->setValue($v);
$this->addChildren(array($chk, $span));
$i++;
}
$this->value = $value;
break;
// Input element
default:
parent::__construct('input', null, null, false, $indent);
$this->setAttributes(array('type' => $type, 'name' => $name, 'id' => $name));
if (!is_array($value)) {
$this->setAttributes('value', $value);
}
$this->value = $value;
}
}
// If a certain value is marked (selected or checked), set the property here.
if (!is_null($marked)) {
$this->marked = $marked;
}
}
/**
* Set the label of the form element object.
*
* @param string $l
* @return void
*/
public function setLabel($l)
{
$this->label = $l;
}
/**
* Set whether the form element object is required.
*
* @param boolean $r
* @throws Exception
* @return void
*/
public function setRequired($r)
{
if (!is_bool($r)) {
throw new Exception($this->_lang->__('Error: The required flag must be a boolean value.'));
} else {
$this->required = $r;
}
}
/**
* Add a validator the form element object.
*
* @param string $type
* @param boolean $condition
* @param string $value
* @param string $msg
* @throws Exception
* @return void
*/
public function addValidator($type, $condition = true, $value = null, $msg = null)
{
// Check the validator type and condition, else set the properties.
if (!in_array($type, $this->_allowed_validators)) {
throw new Exception($this->_lang->__('Error: That type validator is not allowed.'));
} else if (!is_bool($condition)) {
throw new Exception($this->_lang->__('Error: The condition must be a boolean.'));
} else {
$this->validators[] = array('type' => $type,
'condition' => $condition,
'value' => $value,
'msg' => $msg);
}
}
/**
* Validate the form element object.
*
* @return boolean
*/
public function validate()
{
// Check if the element is required.
if ($this->required == true) {
$curElemValue = (is_array($this->value)) ? $this->marked : $this->value;
if (empty($curElemValue)) {
$this->errors['Required'] = $this->_lang->__('This field is required.');
} else {
unset($this->errors['Required']);
}
}
// Check the element's validators.
if (isset($this->validators[0])) {
foreach ($this->validators as $value) {
$curElemValue = (is_array($this->value)) ? $this->marked : $this->value;
switch ($value['type']) {
// Alphanumeric pattern.
case 'AlphaNum':
if (!empty($curElemValue)) {
if (preg_match('/^\w+$/', $curElemValue) == $value['condition']) {
unset($this->errors['AlphaNum']);
} else {
if (!is_null($value['msg'])) {
$this->errors['AlphaNum'] = $value['msg'];
} else {
$this->errors['AlphaNum'] = $this->_lang->__('This field value must %1 contain alphanumeric characters.', (($value['condition'] == true) ? $this->_lang->__('only') : $this->_lang->__('not')));
}
}
}
break;
// Alpha-only pattern.
case 'Alpha':
if (!empty($curElemValue)) {
if (preg_match('/^[a-zA-Z]+$/', $curElemValue) == $value['condition']) {
unset($this->errors['Alpha']);
} else {
if (!is_null($value['msg'])) {
$this->errors['Alpha'] = $value['msg'];
} else {
$this->errors['Alpha'] = $this->_lang->__('This field value must %1 contain characters of the alphabet.', (($value['condition'] == true) ? $this->_lang->__('only') : $this->_lang->__('not')));
}
}
}
break;
// Between two values.
case 'Between':
if (!empty($curElemValue)) {
$numAry = explode('|', $value['value']);
if ((($curElemValue > $numAry[0]) && ($curElemValue < $numAry[1])) == $value['condition']) {
unset($this->errors['Between']);
} else {
if (!is_null($value['msg'])) {
$this->errors['Between'] = $value['msg'];
} else {
$this->errors['Between'] = $this->_lang->__('This field value is %1 between %2 and %3.', array((($value['condition'] == true) ? 'not' : ''), $numAry[0], $numAry[1]));
}
}
}
break;
// E-mail pattern.
case 'Email':
if (!empty($curElemValue)) {
if (preg_match('/[a-zA-Z0-9\.\-\_+%]+@[a-zA-Z0-9\-\_\.]+\.[a-zA-Z]{2,4}/', $curElemValue) == $value['condition']) {
unset($this->errors['Email']);
} else {
if (!is_null($value['msg'])) {
$this->errors['Email'] = $value['msg'];
} else {
$this->errors['Email'] = $this->_lang->__('This field value format is %1 a correct email format.', (($value['condition'] == true) ? 'not' : ''));
}
}
}
break;
// Equal to value.
case 'Equal':
if (!empty($curElemValue)) {
if (($curElemValue == $value['value']) == $value['condition']) {
unset($this->errors['Equal']);
} else {
if (!is_null($value['msg'])) {
$this->errors['Equal'] = $value['msg'];
} else {
$this->errors['Equal'] = $this->_lang->__('This field value does not equal the correct value.');
}
}
}
break;
// Greater than value.
case 'GreaterThan':
if (!empty($curElemValue)) {
if (($curElemValue > $value['value']) == $value['condition']) {
unset($this->errors['GreaterThan']);
} else {
if (!is_null($value['msg'])) {
$this->errors['GreaterThan'] = $value['msg'];
} else {
$this->errors['GreaterThan'] = $this->_lang->__('This field value is %1 greater than %2.', array((($value['condition'] == true) ? 'not' : ''), $value['value']));
}
}
}
break;
// String length equals value.
case 'Length':
if (!empty($curElemValue)) {
if ((strlen($curElemValue) == $value['value']) == $value['condition']) {
unset($this->errors['Length']);
} else {
if (!is_null($value['msg'])) {
$this->errors['Length'] = $value['msg'];
} else {
$this->errors['Length'] = $this->_lang->__('This field value length is %1 equal to %2 characters long.', array((($value['condition'] == true) ? 'not' : ''), $value['value']));
}
}
}
break;
// String length between two values.
case 'LengthBet':
if (!empty($curElemValue)) {
$numAry = explode('|', $value['value']);
if (((strlen($curElemValue) > $numAry[0]) && (strlen($curElemValue) < $numAry[1])) == $value['condition']) {
unset($this->errors['LengthBet']);
} else {
if (!is_null($value['msg'])) {
$this->errors['LengthBet'] = $value['msg'];
} else {
$this->errors['LengthBet'] = $this->_lang->__('This field value length is %1 between %2 and %3.', array((($value['condition'] == true) ? 'not' : ''), $numAry[0], $numAry[1]));
}
}
}
break;
// String length greater than value.
case 'LengthGT':
if (!empty($curElemValue)) {
if ((strlen($curElemValue) >= $value['value']) == $value['condition']) {
unset($this->errors['LengthGT']);
} else {
if (!is_null($value['msg'])) {
$this->errors['LengthGT'] = $value['msg'];
} else {
$this->errors['LengthGT'] = $this->_lang->__('This field value length must be %1 %2 characters long.', array((($value['condition'] == true) ? 'at least' : 'under'), $value['value']));
}
}
}
break;
// String length less than value.
case 'LengthLT':
if (!empty($curElemValue)) {
if ((strlen($curElemValue) <= $value['value']) == $value['condition']) {
unset($this->errors['LengthLT']);
} else {
if (!is_null($value['msg'])) {
$this->errors['LengthLT'] = $value['msg'];
} else {
$this->errors['LengthLT'] = $this->_lang->__('This field value length must be %1 %2 characters long.', array((($value['condition'] == true) ? 'under' : 'at least'), $value['value']));
}
}
}
break;
// Less than value.
case 'LessThan':
if (!empty($curElemValue)) {
if (($curElemValue < $value['value']) == $value['condition']) {
unset($this->errors['LessThan']);
} else {
if (!is_null($value['msg'])) {
$this->errors['LessThan'] = $value['msg'];
} else {
$this->errors['LessThan'] = $this->_lang->__('This field value is %1 less than %2.', array((($value['condition'] == true) ? 'not' : ''), $value['value']));
}
}
}
break;
// Value not empty.
case 'NotEmpty':
if ((!empty($curElemValue)) == $value['condition']) {
unset($this->errors['NotEmpty']);
} else {
if (!is_null($value['msg'])) {
$this->errors['NotEmpty'] = $value['msg'];
} else {
$this->errors['NotEmpty'] = $this->_lang->__('This field value is %1 empty.', (($value['condition'] == true) ? '' : 'not'));
}
}
break;
// Not equal to value.
case 'NotEqual':
if (!empty($curElemValue)) {
if (($curElemValue != $value['value']) == $value['condition']) {
unset($this->errors['NotEqual']);
} else {
if (!is_null($value['msg'])) {
$this->errors['NotEqual'] = $value['msg'];
} else {
$this->errors['NotEqual'] = $this->_lang->__('This field value does not equal the correct value.');
}
}
}
break;
// Numeric value.
case 'Num':
if (!empty($curElemValue)) {
if ((is_numeric($curElemValue)) == $value['condition']) {
unset($this->errors['Num']);
} else {
if (!is_null($value['msg'])) {
$this->errors['Num'] = $value['msg'];
} else {
$this->errors['Num'] = $this->_lang->__('This field value is %1 a number.', (($value['condition'] == true) ? 'not' : ''));
}
}
}
break;
// Value matches regular expression.
case 'RegEx':
if (!empty($curElemValue)) {
if (preg_match($value['value'], $curElemValue) == $value['condition']) {
unset($this->errors['RegEx']);
} else {
if (!is_null($value['msg'])) {
$this->errors['RegEx'] = $value['msg'];
} else {
$this->errors['RegEx'] = $this->_lang->__('This field value format is %1 correct.', (($value['condition'] == true) ? 'not' : ''));
}
}
}
break;
}
}
}
// If errors are found on any of the form elements, return false.
if (count($this->errors) > 0) {
return false;
} else {
return true;
}
}
/**
* Method to render the child and its child nodes.
*
* @param boolean $ret
* @param int $depth
* @param string $indent
* @return void
*/
public function render($ret = false, $depth = 0, $indent = null)
{
$output = parent::render(true);
// Add error messages if there are any.
if (count($this->errors) > 0) {
foreach ($this->errors as $msg) {
$output .= "{$indent}{$this->_indent}<div class=\"error\">{$msg}</div>\n";
}
}
return $output;
}
}