lib: Let `DateTimeValidator' validate values as defined in HTML5

See http://www.w3.org/TR/html-markup/datatypes.html#common.data.datetime for the specification.

refs #6593
This commit is contained in:
Eric Lippmann 2014-09-03 14:36:18 +02:00
parent 0b1d2bf685
commit 1a4e908461
1 changed files with 21 additions and 96 deletions

View File

@ -4,127 +4,52 @@
namespace Icinga\Web\Form\Validator; namespace Icinga\Web\Form\Validator;
use Icinga\Util\DateTimeFactory; use DateTime;
use Zend_Validate_Abstract; use Zend_Validate_Abstract;
use Icinga\Exception\ProgrammingError;
/** /**
* Validator that checks if a textfield contains a correct date format * Validator for date-and-time input controls
*
* @see \Icinga\Web\Form\Element\DateTimePicker For the date-and-time input control.
*/ */
class DateTimeValidator extends Zend_Validate_Abstract class DateTimeValidator extends Zend_Validate_Abstract
{ {
/** protected $local;
* Array of allowed patterns for datetime input
*
* @var array
*/
private $patterns = array();
/** /**
* If the input is not a timestamp this contains the pattern that * Create a new date-and-time input control validator
* matched the input
* *
* @var string|bool * @param bool $local
*/ */
private $validPattern = false; public function __construct($local)
/**
* Error templates
*
* @var array
*
* @see Zend_Validate_Abstract::$_messageTemplates
*/
protected $_messageTemplates = array();
/**
* Create this validator
*
* @param array $patterns Array containing all allowed patterns as strings
*/
public function __construct(array $patterns)
{ {
$this->patterns = $patterns; $this->local = (bool) $local;
$this->_messageTemplates = array(
'INVALID_TYPE' => 'Invalid type given. Date/time string or Unix timestamp expected',
'NO_MATCHING_PATTERN' => 'Invalid format given, valid formats are ' . $this->getAllowedPatternList()
);
} }
/** /**
* Check whether a variable is a Unix timestamp * Is the date and time valid?
*
* @param string|DateTime $value
* @param mixed $context
* *
* @param mixed $timestamp
* @return bool * @return bool
*/
public static function isUnixTimestamp($timestamp)
{
return (is_int($timestamp) || ctype_digit($timestamp))
&& ($timestamp <= PHP_INT_MAX)
&& ($timestamp >= ~PHP_INT_MAX);
}
/**
* Returns a printable string containing all configured patterns
* *
* @return string * @see \Zend_Validate_Interface::isValid()
*/
private function getAllowedPatternList()
{
return '"' . join('","', $this->patterns) . '"';
}
/**
* Validate the input value and set the value of @see validPattern if the input machtes a pattern
*
* @param string $value The format string to validate
* @param null $context The form context (ignored)
*
* @return bool True when the input is valid, otherwise false
*
* @see Zend_Validate_Abstract::isValid()
*/ */
public function isValid($value, $context = null) public function isValid($value, $context = null)
{ {
$this->validPattern = false; if (! $value instanceof DateTime && ! is_string($value)) {
if (!is_string($value) && !is_int($value)) { $this->_error(t('Invalid type given. Instance of DateTime or date/time string expected'));
$this->error('INVALID_TYPE');
return false; return false;
} }
if (is_string($value)) {
if ($this->isUnixTimestamp($value)) { $format = $this->local === true ? 'Y-m-d\TH:i:s' : DateTime::RFC3339;
$dt = DateTimeFactory::create(); $dateTime = DateTime::createFromFormat($format, $value);
$dt->setTimestamp($value); if ($dateTime === false || $dateTime->format($format) !== $value) {
} else { $this->_error(sprintf(t('Date/time string not in the expected format %s'), $format));
if (!isset($this->patterns)) {
throw new ProgrammingError('There are no allowed timeformats configured');
}
$match_found = false;
foreach ($this->patterns as $pattern) {
$dt = DateTimeFactory::parse($value, $pattern);
if ($dt !== false && $dt->format($pattern) === $value) {
$match_found = true;
$this->validPattern = $pattern;
break;
}
}
if (!$match_found) {
$this->_error('NO_MATCHING_PATTERN');
return false; return false;
} }
} }
return true; return true;
} }
/**
* Return the matched pattern if any or false if input is a timestamp
*
* @return bool|string False if input was a timestamp otherwise string with the dateformat pattern
*/
public function getValidPattern()
{
return $this->validPattern;
}
} }