<?php
namespace gnomephp\input;
class DataField{
private $value;
private $keyName;
private $messages=array();
private $rules=array();
public function __construct($value, $keyName=null){
$this->setValue($value);
$this->keyName = $keyName;
}
/**
* Returns the value of the field.
*/
public function __toString(){
return $this->value;
}
/**
* Sets field to a specific value.
* @param mixed $value
*/
public function setValue($value){
$this->value = $value;
}
/**
* Alias of __toString() method.
*/
public function getData(){
return $this->__toString();
}
/**
* Validate runs the validation rules applies to this DataField.
* Throws DataFieldValidException if the field
* @throws DataFieldValidException
*/
public function validate($keyName=null){
$errors = array();
// try each rule function
foreach ($this->rules as $rule => $function) {
if (is_callable($function)) {
if ($function($this->value) === FALSE) {
$errors[] = sprintf($this->messages[$rule], $keyName ? $keyName : $this->keyName);
}
}
}
if (count($errors) > 0){
throw new DataFieldValidException($errors);
}
return $this;
}
/// ----- Validation rules goes here -----
/**
* email
* @param string $message
* @return FormValidator
*/
public function email($message='')
{
$message = ( empty ($message) ) ? '%s is an invalid email address.' : $message;
$this->addValidaitonRule(__FUNCTION__, function($email) {
return ( filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE ) ? FALSE : TRUE;
}, $message);
return $this;
}
/**
* required
* @param string $message
* @return FormValidator
*/
public function required($message='')
{
$message = ( empty ($message) ) ? '%s is required.' : $message;
$this->addValidaitonRule(__FUNCTION__, function($string) {
return ( empty ($string) ) ? FALSE : TRUE;
}, $message);
return $this;
}
/**
* Field must start with a specific substring.
*
* @param string $sub
* @param string $message
* @return FormValidator
*/
public function startsWith($sub, $message = null) {
$message = ( empty ($message) ) ? '%s must start with .'.$sub.'.' : $message;
$this->addValidaitonRule(__FUNCTION__, function($string) use ($sub){
return (strlen($string) === 0 || substr($string, 0, strlen($sub)) === $sub);
}, $message);
return $this;
}
/**
* Field has to be valid internet address.
*
* @param string $message
* @return FormValidator
*/
public function url($message = null) {
$message = ( empty ($message) ) ? '%s must be a valid URL.' : $message;
$this->addValidaitonRule(__FUNCTION__, function($string) {
return (strlen(trim($string)) === 0 || filter_var($string, FILTER_VALIDATE_URL)) ? TRUE : FALSE;
}, $message);
return $this;
}
/**
* Field must contain a valid float value.
*
* @param string $message
* @return FormValidator
*/
public function float($message = null) {
$message = ( empty ($message) ) ? '%s must be a valid float value.' : $message;
$this->addValidaitonRule(__FUNCTION__, function($string) {
return (filter_var($string, FILTER_VALIDATE_FLOAT) === FALSE) ? FALSE : TRUE;
}, $message);
return $this;
}
/**
* Field has to be a valid date.
*
* @param string $message
* @return FormValidator
*/
public function date($format='YYYY-MM-DD', $message = null) {
$message = ( empty ($message) ) ? '%s must be a valid date format ('.$format.')' : $message;
if (empty($format)) {
$format = self::getDefaultDateFormat();
}
$this->addValidaitonRule(__FUNCTION__, function($string) use ($format) {
return DataField::validateDate($string, $format);
}, $message);
return $this;
}
/**
* Field has to be a valid credit card number format.
*
* @see https://github.com/funkatron/inspekt/blob/master/Inspekt.php
* @param string $message
* @return FormValidator
*/
public function ccnum($message = null) {
$message = ( empty ($message) ) ? '%s must be a valid credit card number.' : $message;
$this->addValidaitonRule(__FUNCTION__, function($value) {
$value = str_replace(' ', '', $value);
$length = strlen($value);
if ($length < 13 || $length > 19) {
return FALSE;
}
$sum = 0;
$weight = 2;
for ($i = $length - 2; $i >= 0; $i--) {
$digit = $weight * $value[$i];
$sum += floor($digit / 10) + $digit % 10;
$weight = $weight % 2 + 1;
}
$mod = (10 - $sum % 10) % 10;
return ($mod == $value[$length - 1]);
}, $message);
return $this;
}
/**
* Field must contain a valid integer value.
*
* @param string $message
* @return FormValidator
*/
public function integer($message = null) {
$message = ( empty ($message) ) ? '%s must be a valid integer.' : $message;
$this->addValidaitonRule(__FUNCTION__, function($string) {
return (filter_var($string, FILTER_VALIDATE_INT) === FALSE) ? FALSE : TRUE;
}, $message);
return $this;
}
/**
* Every character in field, if completed, must be a digit.
* This is just like integer(), except there is no upper limit.
*
* @param string $message
* @return FormValidator
*/
public function digits($message = null) {
$message = ( empty ($message) ) ? '%s must be a valid digit.' : $message;
$this->addValidaitonRule(__FUNCTION__, function($value) {
return (strlen($value) === 0 || ctype_digit((string) $value));
}, $message);
return $this;
}
/**
*
* Matches a regexp pattern.
*/
public function regexpMatch($pattern, $message = null){
$message = ( empty ($message) ) ? '%s does not match the requiered pattern.' : $message;
$this->addValidaitonRule(__FUNCTION__, function($value) use ($pattern){
if (!$value)return true;
return preg_match($pattern, $value) ? TRUE : FALSE;
}, $message, array($pattern));
return $this;
}
/**
* Field must be a number greater than [or equal to] X.
*
* @param numeric $limit
* @param bool $include Whether to include limit value.
* @param string $message
* @return FormValidator
*/
public function min($limit, $include = TRUE, $message = null) {
$message = ( empty ($message) ) ? '%s must be the value for atleast '.$limit.'.' : $message;
$this->addValidaitonRule(__FUNCTION__, function($value) use ($limit, $include) {
if (strlen($value) === 0) {
return TRUE;
}
$value = (float) $value;
$inc = (bool) $include;
return ($value > $limit || ($inc === TRUE && $value === $limit));
}, $message);
return $this;
}
/**
* Field must be a number greater than [or equal to] X.
*
* @param numeric $limit
* @param bool $include Whether to include limit value.
* @param string $message
* @return FormValidator
*/
public function max($limit, $include = TRUE, $message = null) {
$message = ( empty ($message) ) ? '%s can be the maximum value of '.$limit.'.' : $message;
$this->addValidaitonRule(__FUNCTION__, function($value) use ($limit, $include) {
if (strlen($value) === 0) {
return TRUE;
}
$value = (float) $value;
$limit = (float) $limit;
$inc = (bool) $include;
return ($value < $limit || ($inc === TRUE && $value === $limit));
}, $message);
return $this;
}
/**
* Field must be a number between X and Y.
*
* @param numeric $min
* @param numeric $max
* @param bool $include Whether to include limit value.
* @param string $message
* @return FormValidator
*/
public function between($min, $max, $include = TRUE, $message = null) {
$message = ( empty ($message) ) ? '%s must be between '.$min.' and '.$max.'.' : $message;
$this->min($min, $include, $message)->max($max, $include, $message);
return $this;
}
/**
* numbersonly
* @param string $message
* @return FormValidator
*/
public function numeric($message='')
{
$message = ( empty ($message) ) ? '%s must consist of numbers only.' : $message;
$this->addValidaitonRule(__FUNCTION__, function($string) {
return ( preg_match('/^[-]?[0-9.]+$/', $string) ) ? TRUE : FALSE;
}, $message);
return $this;
}
/**
*
* @param int $len
* @param string $message
* @return FormValidator
*/
public function minLength($minlen, $message='')
{
$message = ( empty ($message) ) ? '%s must be at least ' . $minlen . ' characters or longer.' : $message;
$this->addValidaitonRule(__FUNCTION__, function($string) use ($minlen) {
return ( strlen($string) < $minlen ) ? FALSE : TRUE;
}, $message);
return $this;
}
/**
*
* @param int $len
* @param string $message
* @return FormValidator
*/
public function maxLength($maxlen, $message='')
{
$message = ( empty ($message) ) ? '%s must be no longer than ' . $maxlen . ' characters.' : $message;
$this->addValidaitonRule(__FUNCTION__, function($string) use ($maxlen) {
return ( strlen($string) > $maxlen ) ? FALSE : TRUE;
}, $message);
return $this;
}
/**
*
* @param int $len
* @param string $message
* @return FormValidator
*/
public function length($len, $message='')
{
$message = ( empty ($message) ) ? '%s must be exactly ' . $len . ' characters in length.' : $message;
$this->addValidaitonRule(__FUNCTION__, function($string) use ($len) {
return ( strlen($string) == $len ) ? TRUE : FALSE;
}, $message);
return $this;
}
/**
*
* @param string $field
* @param string $label
* @param string $message
* @return FormValidator
*/
public function matches($field, $label, $message='')
{
$message = ( empty ($message) ) ? '%s must match ' . $label . '.' : $message;
$matchvalue = $field;
$this->addValidaitonRule(__FUNCTION__, function($string) use ($matchvalue) {
return ( (string)$matchvalue == (string)$string ) ? TRUE : FALSE;
}, $message);
return $this;
}
/**
*
* @param string $field
* @param string $label
* @param string $message
* @return FormValidator
*/
public function notMatches($field, $label, $message='')
{
$message = ( empty ($message) ) ? '%s must not match ' . $label . '.' : $message;
$matchvalue = $field;
$this->addValidaitonRule(__FUNCTION__, function($string) use ($matchvalue) {
return ( (string)$matchvalue == (string)$string ) ? FALSE : TRUE;
}, $message);
return $this;
}
/**
* Field has to be a date later than or equal to X.
*
* @param string|integer $date Limit date.
* @param string $format Date format.
* @param string $message
* @return FormValidator
*/
public function maxDate($date = 0, $format = null, $message = null) {
$message = ( empty ($message) ) ? '%s must be between '.$date.'.' : $message;
if (empty($format)) {
$format = DataField::getDefaultDateFormat();
}
if (is_numeric($date)) {
$date = new \DateTime($date . ' days'); // Days difference from today
} else {
$fieldValue = $this->getval($date);
$date = ($fieldValue == FALSE) ? $date : $fieldValue;
$date = \DateTime::createFromFormat($format, $date);
}
$this->addValidaitonRule(__FUNCTION__, function($string) use ($format, $date) {
$limitDate = $date;
return ($limitDate < \DateTime::createFromFormat($format, $string)) ? FALSE : TRUE;
}, $message);
return $this;
}
/**
* Field has to be a date later than or equal to X.
*
* @param string $message
* @return FormValidator
*/
public function minDate($date = 0, $format = null, $message = null) {
if (empty($format)) {
$format = self::getDefaultDateFormat();
}
if (is_numeric($date)) {
$date = new \DateTime($date . ' days'); // Days difference from today
} else {
$fieldValue = $this->getval($date);
$date = ($fieldValue == FALSE) ? $date : $fieldValue;
$date = \DateTime::createFromFormat($format, $date);
}
$this->addValidaitonRule(__FUNCTION__, function($string) use ($date, $format){
$limitDate = $date;
return ($limitDate > \DateTime::createFromFormat($format, $string)) ? FALSE : TRUE;
}, $message);
return $this;
}
/**
* Field has to be valid IP address.
*
* @param string $message
* @return FormValidator
*/
public function ip($message = null) {
$message = ( empty ($message) ) ? '%s is not a valid ip-address.' : $message;
$this->addValidaitonRule(__FUNCTION__, function($string) {
return (strlen(trim($string)) === 0 || filter_var($string, FILTER_VALIDATE_IP)) ? TRUE : FALSE;
}, $message);
return $this;
}
/// ----- Stop validaiton rules....
/**
* addValidaitonRule
* @param string $rule
* @param closure $function
* @param string $message
*/
public function addValidaitonRule($rule, $function, $message='') {
if (is_callable($function)) {
$this->rules[$rule] = $function;
if (!empty($message)) {
$this->messages[$rule] = $message;
}
}
return $this;
}
/**
*
* Validate a date
* see http://www.phpro.org/examples/Validate-Date-Using-PHP.html
* @param string $date
* @param string format
* @return bool
*
*/
static public function validateDate( $date, $format='YYYY-MM-DD')
{
switch( $format )
{
case 'YYYY/MM/DD':
case 'YYYY-MM-DD':
@list( $y, $m, $d ) = preg_split( '/[-\.\/ ]/', $date );
break;
case 'YYYY/DD/MM':
case 'YYYY-DD-MM':
@list( $y, $d, $m ) = preg_split( '/[-\.\/ ]/', $date );
break;
case 'DD-MM-YYYY':
case 'DD/MM/YYYY':
@list( $d, $m, $y ) = preg_split( '/[-\.\/ ]/', $date );
break;
case 'MM-DD-YYYY':
case 'MM/DD/YYYY':
@list( $m, $d, $y ) = preg_split( '/[-\.\/ ]/', $date );
break;
case 'YYYYMMDD':
$y = substr( $date, 0, 4 );
$m = substr( $date, 4, 2 );
$d = substr( $date, 6, 2 );
break;
case 'YYYYDDMM':
$y = substr( $date, 0, 4 );
$d = substr( $date, 4, 2 );
$m = substr( $date, 6, 2 );
break;
default:
throw new \Exception( "Invalid Date Format" );
}
return @checkdate( $m, $d, $y );
}
/**
* Date format.
*
* @return string
*/
private static function getDefaultDateFormat() {
return 'YYYY-MM-DD';
}
}