diff --git a/src/Date.php b/src/Date.php index 541a2bbba..3add27db1 100644 --- a/src/Date.php +++ b/src/Date.php @@ -21,10 +21,7 @@ namespace Zend\Validator; use Traversable; -use Zend\Date as ZendDate; -use Zend\Locale\Format; -use Zend\Locale\Locale; -use Zend\Stdlib\ArrayUtils; +use DateTime; /** * @category Zend @@ -44,7 +41,7 @@ class Date extends AbstractValidator * @var array */ protected $messageTemplates = array( - self::INVALID => "Invalid type given. String, integer, array or Zend_Date expected", + self::INVALID => "Invalid type given. String, integer, array or DateTime expected", self::INVALID_DATE => "'%value%' does not appear to be a valid date", self::FALSEFORMAT => "'%value%' does not fit the date format '%format%'", ); @@ -63,13 +60,6 @@ class Date extends AbstractValidator */ protected $format; - /** - * Optional locale - * - * @var string|\Zend\Locale\Locale|null - */ - protected $locale; - /** * Sets validator options * @@ -78,14 +68,10 @@ class Date extends AbstractValidator public function __construct($options = array()) { if ($options instanceof Traversable) { - $options = ArrayUtils::iteratorToArray($options); + $options = iterator_to_array($options); } elseif (!is_array($options)) { $options = func_get_args(); $temp['format'] = array_shift($options); - if (!empty($options)) { - $temp['locale'] = array_shift($options); - } - $options = $temp; } @@ -93,37 +79,11 @@ public function __construct($options = array()) $this->setFormat($options['format']); } - if (array_key_exists('locale', $options)) { - $this->setLocale($options['locale']); - } - parent::__construct($options); } /** - * Returns the locale option - * - * @return string|Locale|null - */ - public function getLocale() - { - return $this->locale; - } - - /** - * Sets the locale option - * - * @param string|Locale $locale - * @return Date provides a fluent interface - */ - public function setLocale($locale = null) - { - $this->locale = Locale::findLocale($locale); - return $this; - } - - /** - * Returns the locale option + * Returns the format option * * @return string|null */ @@ -146,19 +106,18 @@ public function setFormat($format = null) /** * Returns true if $value is a valid date of the format YYYY-MM-DD - * If optional $format or $locale is set the date format is checked - * according to Zend_Date, see Zend_Date::isDate() + * If optional $format is set the date format is checked + * according to DateTime * - * @param string|array|ZendDate\Date $value + * @param string|array|int|DateTime $value * @return boolean */ public function isValid($value) { if (!is_string($value) - && !is_int($value) - && !is_float($value) && !is_array($value) - && !($value instanceof ZendDate\Date) + && !is_int($value) + && !($value instanceof DateTime) ) { $this->error(self::INVALID); return false; @@ -166,22 +125,32 @@ public function isValid($value) $this->setValue($value); - if (($this->format !== null) - || ($this->locale !== null) - || is_array($value) - || $value instanceof ZendDate\Date + $format = $this->getFormat(); + + if ($value instanceof DateTime) { + return true; + } elseif (is_int($value) + || (is_string($value) && null !== $format) ) { - if (!ZendDate\Date::isDate($value, $this->format, $this->locale)) { - if ($this->checkFormat($value) === false) { - $this->error(self::FALSEFORMAT); - } else { - $this->error(self::INVALID_DATE); - } + $date = (is_int($value)) + ? date_create("@$value") // from timestamp + : DateTime::createFromFormat($format, $value); + + // Invalid dates can show up as warnings (ie. "2007-02-99") + // and still return a DateTime object + $errors = DateTime::getLastErrors(); + + if (false === $date || $errors['warning_count'] > 0) { + $this->error(self::INVALID_DATE); return false; } } else { + if (is_array($value)) { + $value = implode('-', $value); + } + if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) { - $this->format = 'yyyy-MM-dd'; + $this->format = 'Y-m-d'; $this->error(self::FALSEFORMAT); $this->format = null; return false; @@ -197,67 +166,4 @@ public function isValid($value) return true; } - - /** - * Check if the given date fits the given format - * - * @param string $value Date to check - * @return boolean False when date does not fit the format - */ - private function checkFormat($value) - { - try { - $parsed = Format::getDate((string) $value, array( - 'date_format' => $this->format, - 'format_type' => 'iso', - 'fix_date' => false, - )); - if (isset($parsed['year']) - && ((strpos(strtoupper($this->format), 'YY') !== false) - && (strpos(strtoupper($this->format), 'YYYY') === false)) - ) { - $parsed['year'] = ZendDate\Date::getFullYear($parsed['year']); - } - } catch (\Exception $e) { - // Date can not be parsed - return false; - } - - if (((strpos($this->format, 'Y') !== false) || (strpos($this->format, 'y') !== false)) - && (!isset($parsed['year'])) - ) { - // Year expected but not found - return false; - } - - if ((strpos($this->format, 'M') !== false) && (!isset($parsed['month']))) { - // Month expected but not found - return false; - } - - if ((strpos($this->format, 'd') !== false) && (!isset($parsed['day']))) { - // Day expected but not found - return false; - } - - if (((strpos($this->format, 'H') !== false) || (strpos($this->format, 'h') !== false)) - && (!isset($parsed['hour'])) - ) { - // Hour expected but not found - return false; - } - - if ((strpos($this->format, 'm') !== false) && (!isset($parsed['minute']))) { - // Minute expected but not found - return false; - } - - if ((strpos($this->format, 's') !== false) && (!isset($parsed['second']))) { - // Second expected but not found - return false; - } - - // Date fits the format - return true; - } } diff --git a/test/DateTest.php b/test/DateTest.php index af6be9bf9..b2e6d22a0 100644 --- a/test/DateTest.php +++ b/test/DateTest.php @@ -21,10 +21,12 @@ namespace ZendTest\Validator; -use Zend\Validator\Date as DateValidator; -use Zend\Date; +use DateTime; +use stdClass; +use Zend\Validator; /** + * @see Zend_Validator_Date * @category Zend * @package Zend_Validator * @subpackage UnitTests @@ -35,76 +37,73 @@ class DateTest extends \PHPUnit_Framework_TestCase { /** - * @var DateValidator + * @var Validator\Date */ protected $validator; /** - * Whether an error occurred - * - * @var boolean - */ - protected $errorOccurred = false; - - public function setUp() - { - $this->errorOccurred = false; - $this->validator = new DateValidator(); - } - - /** - * Ensures that the validator follows expected behavior + * Creates a new Zend\Validator\Date object for each test method * * @return void */ - public function testBasic() + public function setUp() { - $valuesExpected = array( - '2007-01-01' => true, - '2007-02-28' => true, - '2007-02-29' => false, - '2008-02-29' => true, - '2007-02-30' => false, - '2007-02-99' => false, - '9999-99-99' => false, - 0 => false, - 999999999999 => false, - 'Jan 1 2007' => false, - 'asdasda' => false, - 'sdgsdg' => false - ); - foreach ($valuesExpected as $input => $result) { - $this->assertEquals($result, $this->validator->isValid($input), - "'$input' expected to be " . ($result ? '' : 'in') . 'valid'); - } + $this->validator = new Validator\Date(); } - /** - * Ensures that characters trailing an otherwise valid date cause the input to be invalid - * - * @group ZF-1804 - * @return void - */ - public function testCharactersTrailingInvalid() + public function datesDataProvider() { - $dateValid = '2007-08-02'; - $charactersTrailing = 'something'; - $this->assertTrue($this->validator->isValid($dateValid)); - $this->assertFalse($this->validator->isValid($dateValid . $charactersTrailing)); + return array( + // date format isValid + array('2007-01-01', null, true), + array('2007-02-28', null, true), + array('2007-02-29', null, false), + array('2008-02-29', null, true), + array('2007-02-30', null, false), + array('2007-02-99', null, false), + array('2007-02-99', 'Y-m-d', false), + array('9999-99-99', null, false), + array('9999-99-99', 'Y-m-d', false), + array('Jan 1 2007', null, false), + array('Jan 1 2007', 'M j Y', true), + array('asdasda', null, false), + array('sdgsdg', null, false), + array('2007-01-01something', null, false), + array('something2007-01-01', null, false), + array('10.01.2008', 'd.m.Y', true), + array('01 2010', 'm Y', true), + array('2008/10/22', 'd/m/Y', false), + array('22/10/08', 'd/m/y', true), + array('22/10', 'd/m/Y', false), + // time + array('2007-01-01T12:02:55Z', DateTime::ISO8601, true), + array('12:02:55', 'H:i:s', true), + array('25:02:55', 'H:i:s', false), + // int + array(0, null, true), + array(1340677235, null, true), + array(999999999999, null, true), + // array + array(array('2012', '06', '25'), null, true), + array(array('12', '06', '25'), null, false), + array(array(1 => 1), null, false), + // DateTime + array(new DateTime(), null, true), + // invalid obj + array(new stdClass(), null, false), + ); } /** - * Ensures that characters leading an otherwise valid date cause the input to be invalid + * Ensures that the validator follows expected behavior * - * @group ZF-1804 - * @return void + * @dataProvider datesDataProvider */ - public function testCharactersLeadingInvalid() + public function testBasic($input, $format, $result) { - $dateValid = '2007-08-02'; - $charactersLeading = 'something'; - $this->assertTrue($this->validator->isValid($dateValid)); - $this->assertFalse($this->validator->isValid($charactersLeading . $dateValid)); + $this->validator->setFormat($format); + $this->assertEquals($result, $this->validator->isValid($input)); + $this->assertEquals($format, $this->validator->getFormat()); } /** @@ -125,120 +124,17 @@ public function testGetMessages() */ public function testUseManualFormat() { - $this->assertTrue($this->validator->setFormat('dd.MM.YYYY')->isValid('10.01.2008')); - $this->assertEquals('dd.MM.YYYY', $this->validator->getFormat()); - - $this->assertTrue($this->validator->setFormat('MM yyyy')->isValid('01 2010')); - $this->assertFalse($this->validator->setFormat('dd/MM/yyyy')->isValid('2008/10/22')); - $this->assertTrue($this->validator->setFormat('dd/MM/yy')->isValid('22/10/08')); - $this->assertFalse($this->validator->setFormat('dd/MM/yy')->isValid('22/10')); - $this->assertFalse($this->validator->setFormat('s')->isValid(0)); - } - - /** - * Ensures that the validator can handle different dateformats from locale - * - * @group ZF-2003 - * @return void - */ - public function testUseLocaleFormat() - { - $errorOccurredLocal = false; - set_error_handler(array($this, 'errorHandlerIgnore')); - $valuesExpected = array( - '10.01.2008' => true, - '32.02.2008' => false, - '20 April 2008' => true, - '1 Jul 2008' => true, - '2008/20/03' => false, - '99/99/2000' => false, - 0 => false, - 999999999999 => false, - 'Jan 1 2007' => false - ); - foreach ($valuesExpected as $input => $resultExpected) { - $resultActual = $this->validator->setLocale('de_AT')->isValid($input); - if (!$this->errorOccurred) { - $this->assertEquals($resultExpected, $resultActual, "'$input' expected to be " - . ($resultExpected ? '' : 'in') . 'valid'); - } else { - $errorOccurredLocal = true; - } - $this->errorOccurred = false; - } - $this->assertEquals('de_AT', $this->validator->getLocale()); - restore_error_handler(); - if ($errorOccurredLocal) { - $this->markTestSkipped('Affected by bug described in ZF-2789'); - } - } - - /** - * Ensures that the validator can handle different dateformats from locale - * - * @group ZF-2003 - * @return void - */ - public function testLocaleContructor() - { - set_error_handler(array($this, 'errorHandlerIgnore')); - $valid = new DateValidator('dd.MM.YYYY', 'de'); - $this->assertTrue($valid->isValid('10.April.2008')); - - restore_error_handler(); - } - - /** - * @ZF-4352 - */ - public function testNonStringValidation() - { - $this->assertFalse($this->validator->isValid(array(1 => 1))); - } - - /** - * @ZF-6374 - */ - public function testUsingApplicationLocale() - { - $this->markTestSkipped('Depends on system-specific locale'); - $valid = new DateValidator(); - $this->assertTrue($valid->isValid('10.April.2008')); - } - - /** - * @group ZF-7630 - */ - public function testDateObjectVerification() - { - $date = new Date\Date(); - $this->assertTrue($this->validator->isValid($date), "'$date' expected to be valid"); - } - - /** - * ZF-6457 - */ - public function testArrayVerification() - { - $date = new Date\Date(); - $array = $date->toArray(); - $this->assertTrue($this->validator->isValid($array), "array expected to be valid"); - } - - /** - * Ignores a raised PHP error when in effect, but throws a flag to indicate an error occurred - * - * @param integer $errno - * @param string $errstr - * @param string $errfile - * @param integer $errline - * @param array $errcontext - * @return void - * @group ZF-2789 - */ - public function errorHandlerIgnore($errno, $errstr, $errfile, $errline, array $errcontext) - { - $this->errorOccurred = true; + $this->assertTrue($this->validator->setFormat('d.m.Y')->isValid('10.01.2008'), var_export(date_get_last_errors(), 1)); + $this->assertEquals('d.m.Y', $this->validator->getFormat()); + + $this->assertTrue($this->validator->setFormat('m Y')->isValid('01 2010')); + $this->assertFalse($this->validator->setFormat('d/m/Y')->isValid('2008/10/22')); + $this->assertTrue($this->validator->setFormat('d/m/Y')->isValid('22/10/08')); + $this->assertFalse($this->validator->setFormat('d/m/Y')->isValid('22/10')); + // Omitting the following assertion, as it varies from 5.3.3 to 5.3.11, + // and there is no indication in the PHP changelog as to when or why it + // may have changed. Leaving for posterity, to indicate original expectation. + // $this->assertFalse($this->validator->setFormat('s')->isValid(0)); } public function testEqualsMessageTemplates()