Skip to content

[Validator] Add "format" option to DateTime constraint #14538

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/Symfony/Component/Validator/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
CHANGELOG
=========

2.8.0
-----

* deprecated `Date` and `Time` constraints
* deprecated `DateValidator` and `TimeValidator` validators
* deprecated `PATTERN` constant in `DateTimeValidator`
* added new optional `format` option to `DateTime` constraint

2.7.0
-----

Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Component/Validator/Constraints/Date.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0. Use {@link DateTime} instead.
*/
class Date extends Constraint
{
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Component/Validator/Constraints/DateTime.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Bernhard Schussek <bschussek@gmail.com>
* @author Radu Murzea <radu.murzea@gmail.com>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are not the author

*
* @api
*/
Expand All @@ -34,4 +35,5 @@ class DateTime extends Constraint
);

public $message = 'This value is not a valid datetime.';
public $format = 'Y-m-d H:i:s';
}
67 changes: 51 additions & 16 deletions src/Symfony/Component/Validator/Constraints/DateTimeValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@

/**
* @author Bernhard Schussek <bschussek@gmail.com>
* @author Radu Murzea <radu.murzea@gmail.com>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

*
* @api
*/
class DateTimeValidator extends DateValidator
{
/**
* @deprecated since version 2.8, to be removed in 3.0.
*/
const PATTERN = '/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/';

/**
Expand All @@ -43,48 +47,79 @@ public function validate($value, Constraint $constraint)

$value = (string) $value;

if (!preg_match(static::PATTERN, $value, $matches)) {
$dateTimeObject = \DateTime::createFromFormat($constraint->format, $value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assign a variable here is not necessary

$errors = \DateTime::getLastErrors();

//the value was successfully parsed
if ($errors['error_count'] + $errors['warning_count'] <= 0) {
return;
}

//see the function's phpdoc for details
$errorCode = $this->getViolationCode($errors, 'errors');

if (! is_null($errorCode)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra space

if ($this->context instanceof ExecutionContextInterface) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(DateTime::INVALID_FORMAT_ERROR)
->setCode($errorCode)
->addViolation();
} else {
$this->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(DateTime::INVALID_FORMAT_ERROR)
->setCode($errorCode)
->addViolation();
}

return;
}

if (!DateValidator::checkDate($matches[1], $matches[2], $matches[3])) {
//see the function's phpdoc for details
$warningCode = $this->getViolationCode($errors, 'warnings');

if (! is_null($warningCode)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra space

if ($this->context instanceof ExecutionContextInterface) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(DateTime::INVALID_DATE_ERROR)
->setCode($warningCode)
->addViolation();
} else {
$this->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(DateTime::INVALID_DATE_ERROR)
->setCode($warningCode)
->addViolation();
}

return;
}
}

/**
* PHP's DateTime stores the errors and warning at unpredictable indexes,
* so it's a bit trickier to retrieve them (we have to use array_values + array_shift).
*
* Also, based on the error/warning message string, we can guess if it was
* a date problem, time problem or format/general problem.
*
* @param array $errors result from calling \DateTime::getLastErrors()
* @param string $key the key under which to search for errors/warnings
* @return mixed an integer representing the error code or NULL if everything was ok
*/
private function getViolationCode($errors, $key)
{
if (isset($errors[$key]) && count($errors[$key]) > 0) {
$allErrors = array_values($errors[$key]);
$firstError = array_shift($allErrors);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be more than one error


if (!TimeValidator::checkTime($matches[4], $matches[5], $matches[6])) {
if ($this->context instanceof ExecutionContextInterface) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(DateTime::INVALID_TIME_ERROR)
->addViolation();
if (strpos($firstError, 'date') !== false) {
return DateTime::INVALID_DATE_ERROR;
} elseif (strpos($firstError, 'time') !== false) {
return DateTime::INVALID_TIME_ERROR;
} else {
$this->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(DateTime::INVALID_TIME_ERROR)
->addViolation();
return DateTime::INVALID_FORMAT_ERROR;
}
} else {
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This else is not necessary

}
}
}
2 changes: 2 additions & 0 deletions src/Symfony/Component/Validator/Constraints/DateValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0. Use {@link DateTimeValidator} instead.
*/
class DateValidator extends ConstraintValidator
{
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Component/Validator/Constraints/Time.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0. Use {@link DateTime} instead.
*/
class Time extends Constraint
{
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Component/Validator/Constraints/TimeValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0. Use {@link DateTimeValidator} instead.
*/
class TimeValidator extends ConstraintValidator
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ public function getInvalidDateTimes()
array('foobar', DateTime::INVALID_FORMAT_ERROR),
array('2010-01-01', DateTime::INVALID_FORMAT_ERROR),
array('00:00:00', DateTime::INVALID_FORMAT_ERROR),
array('2010-0101 01:02:03', DateTime::INVALID_FORMAT_ERROR),
array('2010-01-01X01:02:03', DateTime::INVALID_FORMAT_ERROR),
array('2010-01-01 00:00', DateTime::INVALID_FORMAT_ERROR),
array('2010-13-01 00:00:00', DateTime::INVALID_DATE_ERROR),
array('2010-04-32 00:00:00', DateTime::INVALID_DATE_ERROR),
Expand All @@ -107,4 +109,27 @@ public function getInvalidDateTimes()
array('2010-01-01 00:00:60', DateTime::INVALID_TIME_ERROR),
);
}

/**
* @dataProvider getCustomDateTimes
*/
public function testCustomFormatDateTime($format, $dateTime)
{
$constraint = new DateTime(array(
'format' => $format,
));

$this->validator->validate($dateTime, $constraint);

$this->assertNoViolation();
}

public function getCustomDateTimes()
{
return array(
array('d-m-Y', '15-07-2015'),
array('m-Y-d i:H', '11-2013-29 47:19'),
array('Y F d', '2002 March 17'),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
use Symfony\Component\Validator\Constraints\DateValidator;
use Symfony\Component\Validator\Validation;

/**
* @deprecated since version 2.8, to be removed in 3.0.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing @group legacy

*/
class DateValidatorTest extends AbstractConstraintValidatorTest
{
protected function getApiVersion()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
use Symfony\Component\Validator\Constraints\TimeValidator;
use Symfony\Component\Validator\Validation;

/**
* @deprecated since version 2.8, to be removed in 3.0.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

*/
class TimeValidatorTest extends AbstractConstraintValidatorTest
{
protected function getApiVersion()
Expand Down