From a0e63a1320e80db2dd85c0337b36ffe02cc40531 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jannis=20Mo=C3=9Fhammer?= Date: Fri, 30 Aug 2013 17:42:39 +0200 Subject: [PATCH] Fix error message and move validation in own DateTimeValidator refs #4581 refs #4632 --- application/views/helpers/DateFormat.php | 7 +- .../Web/Form/Element/DateTimePicker.php | 66 +++----- .../Web/Form/Validator/DateTimeValidator.php | 158 ++++++++++++++++++ .../Web/Form/Element/DateTimePickerTest.php | 16 +- 4 files changed, 200 insertions(+), 47 deletions(-) create mode 100644 library/Icinga/Web/Form/Validator/DateTimeValidator.php diff --git a/application/views/helpers/DateFormat.php b/application/views/helpers/DateFormat.php index 1febf5eeb..3816c291a 100644 --- a/application/views/helpers/DateFormat.php +++ b/application/views/helpers/DateFormat.php @@ -9,6 +9,7 @@ use \Icinga\Application\Icinga; use \Icinga\Application\Config as IcingaConfig; use \Icinga\Util\DateTimeFactory; use \Zend_Controller_Request_Http; +use \Icinga\Web\Form\Validator\DateTimeValidator; /** * Helper to format date and time. Utilizes DateTimeFactory to ensure time zone awareness @@ -60,7 +61,11 @@ class Zend_View_Helper_DateFormat extends Zend_View_Helper_Abstract public function format($timestamp, $format) { $dt = DateTimeFactory::create(); - $dt->setTimestamp($timestamp); + if (DateTimeValidator::isUnixTimestamp($timestamp)) { + $dt->setTimestamp($timestamp); + } else { + return $timestamp; + } return $dt->format($format); } diff --git a/library/Icinga/Web/Form/Element/DateTimePicker.php b/library/Icinga/Web/Form/Element/DateTimePicker.php index 096707940..934a13657 100644 --- a/library/Icinga/Web/Form/Element/DateTimePicker.php +++ b/library/Icinga/Web/Form/Element/DateTimePicker.php @@ -28,9 +28,10 @@ namespace Icinga\Web\Form\Element; -use \Zend_Form_Element_Xhtml; +use Icinga\Web\Form\Validator\DateTimeValidator; +use \Zend_Form_Element_Text; +use \Zend_Form_Element; use \Icinga\Util\DateTimeFactory; -use \Icinga\Exception\ProgrammingError; /** * Datetime form element which returns the input as Unix timestamp after the input has been proven valid. Utilizes @@ -38,7 +39,7 @@ use \Icinga\Exception\ProgrammingError; * * @see isValid() */ -class DateTimePicker extends Zend_Form_Element_Xhtml +class DateTimePicker extends Zend_Form_Element_Text { /** * View helper to use @@ -46,6 +47,12 @@ class DateTimePicker extends Zend_Form_Element_Xhtml */ public $helper = 'formDateTime'; + /** + * The validator used for datetime validation + * @var DateTimeValidator + */ + private $dateValidator; + /** * Valid formats to check user input against * @var array @@ -53,16 +60,18 @@ class DateTimePicker extends Zend_Form_Element_Xhtml public $patterns; /** - * Check whether a variable is a Unix timestamp + * Create a new DateTimePicker * - * @param mixed $timestamp - * @return bool + * @param array|string|\Zend_Config $spec + * @param null $options + * @see Zend_Form_Element::__construct() */ - public function isUnixTimestamp($timestamp) + public function __construct($spec, $options = null) { - return (is_int($timestamp) || ctype_digit($timestamp)) - && ($timestamp <= PHP_INT_MAX) - && ($timestamp >= ~PHP_INT_MAX); + parent::__construct($spec, $options); + $this->dateValidator = new DateTimeValidator($this->patterns); + $this->addValidator($this->dateValidator); + } /** @@ -77,40 +86,17 @@ class DateTimePicker extends Zend_Form_Element_Xhtml */ public function isValid($value, $context = null) { + // Overwrite the internal validator to use + if (!parent::isValid($value, $context)) { return false; } - - if (!is_string($value) && !is_int($value)) { - $this->addErrorMessage( - _('Invalid type given. Date/time string or Unix timestamp expected') - ); - return false; + $pattern = $this->dateValidator->getValidPattern(); + if (!$pattern) { + $this->setValue($value); + return true; } - - if ($this->isUnixTimestamp($value)) { - $dt = DateTimeFactory::create(); - $dt->setTimestamp($value); - } else { - if (!isset($this->patterns)) { - throw new ProgrammingError('Cannot parse datetime string without any pattern'); - } - - $match_found = false; - foreach ($this->patterns as $pattern) { - $dt = DateTimeFactory::parse($value, $pattern); - if ($dt !== false && $dt->format($pattern) === $value) { - $match_found = true; - break; - } - } - if (!$match_found) { - return false; - } - } - - $this->setValue($dt->getTimestamp()); - + $this->setValue(DateTimeFactory::parse($value, $pattern)->getTimestamp()); return true; } } diff --git a/library/Icinga/Web/Form/Validator/DateTimeValidator.php b/library/Icinga/Web/Form/Validator/DateTimeValidator.php new file mode 100644 index 000000000..292ab00c7 --- /dev/null +++ b/library/Icinga/Web/Form/Validator/DateTimeValidator.php @@ -0,0 +1,158 @@ + + * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2 + * @author Icinga Development Team + */ +// {{{ICINGA_LICENSE_HEADER}}} + + +namespace Icinga\Web\Form\Validator; + +use \Icinga\Util\DateTimeFactory; +use \Zend_Validate_Abstract; +use \Icinga\Exception\ProgrammingError; + +/** + * Validator that checks if a textfield contains a correct date format + */ +class DateTimeValidator extends Zend_Validate_Abstract +{ + /** + * Array of allowed patterns for datetime input + * + * @var array + */ + private $patterns = array(); + + /** + * If the input is not a timestamp this contains the pattern that + * matched the input + * + * @var string|bool + */ + private $validPattern = false; + + /** + * Error templates + * + * @var array + * + * @see Zend_Validate_Abstract::$_messageTemplates + */ + // @codingStandardsIgnoreStart + protected $_messageTemplates = array(); + // @codingStandardsIgnoreEnd + + /** + * Create this validator + * + * @param array $patterns Array containing all allowed patterns as strings + */ + public function __construct(array $patterns) + { + $this->patterns = $patterns; + $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 + * + * @param mixed $timestamp + * @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 + */ + 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) + { + $this->validPattern = false; + if (!is_string($value) && !is_int($value)) { + $this->error('INVALID_TYPE'); + return false; + } + + if ($this->isUnixTimestamp($value)) { + $dt = DateTimeFactory::create(); + $dt->setTimestamp($value); + } else { + 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 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; + } +} diff --git a/test/php/library/Icinga/Web/Form/Element/DateTimePickerTest.php b/test/php/library/Icinga/Web/Form/Element/DateTimePickerTest.php index bdf78f60f..5d35a5de0 100644 --- a/test/php/library/Icinga/Web/Form/Element/DateTimePickerTest.php +++ b/test/php/library/Icinga/Web/Form/Element/DateTimePickerTest.php @@ -1,19 +1,23 @@