From 3b50bf23a1b4c22c096036ba21e823ac347fe233 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Wed, 24 Sep 2014 12:08:18 +0200 Subject: [PATCH] [Validator] Added error codes to all constraints with multiple error causes --- .../Extension/Validator/Constraints/Form.php | 11 +- .../Validator/Constraints/FormValidator.php | 3 +- .../EventListener/ValidationListener.php | 2 +- .../Constraints/FormValidatorTest.php | 14 +- .../EventListener/ValidationListenerTest.php | 4 +- .../Component/Validator/Constraint.php | 29 +++ .../Validator/Constraints/CardScheme.php | 9 + .../Constraints/CardSchemeValidator.php | 2 + .../Validator/Constraints/Choice.php | 10 + .../Validator/Constraints/ChoiceValidator.php | 4 + .../Validator/Constraints/Collection.php | 9 +- .../Constraints/CollectionValidator.php | 2 + .../Component/Validator/Constraints/Count.php | 8 + .../Validator/Constraints/CountValidator.php | 2 + .../Component/Validator/Constraints/Date.php | 8 + .../Validator/Constraints/DateTime.php | 10 + .../Constraints/DateTimeValidator.php | 3 + .../Validator/Constraints/DateValidator.php | 2 + .../Component/Validator/Constraints/Email.php | 10 + .../Validator/Constraints/EmailValidator.php | 4 + .../Component/Validator/Constraints/File.php | 16 ++ .../Validator/Constraints/FileValidator.php | 23 +- .../Component/Validator/Constraints/Iban.php | 15 ++ .../Validator/Constraints/IbanValidator.php | 5 + .../Component/Validator/Constraints/Image.php | 34 +++ .../Validator/Constraints/ImageValidator.php | 10 + .../Component/Validator/Constraints/Isbn.php | 15 ++ .../Validator/Constraints/IsbnValidator.php | 58 ++++- .../Component/Validator/Constraints/Issn.php | 17 ++ .../Validator/Constraints/IssnValidator.php | 7 + .../Validator/Constraints/Length.php | 8 + .../Validator/Constraints/LengthValidator.php | 2 + .../Component/Validator/Constraints/Luhn.php | 9 + .../Validator/Constraints/LuhnValidator.php | 2 + .../Component/Validator/Constraints/Range.php | 10 + .../Validator/Constraints/RangeValidator.php | 3 + .../Component/Validator/Constraints/Time.php | 8 + .../Validator/Constraints/TimeValidator.php | 2 + .../Component/Validator/Constraints/Uuid.php | 17 ++ .../Validator/Constraints/UuidValidator.php | 201 ++++++++++++++++-- .../Validator/Tests/ConstraintTest.php | 9 + .../Constraints/CardSchemeValidatorTest.php | 31 +-- .../Tests/Constraints/ChoiceValidatorTest.php | 6 + .../Constraints/CollectionValidatorTest.php | 3 + .../Tests/Constraints/CountValidatorTest.php | 4 + .../Constraints/DateTimeValidatorTest.php | 23 +- .../Tests/Constraints/DateValidatorTest.php | 15 +- .../Tests/Constraints/EmailValidatorTest.php | 1 + .../Constraints/FileValidatorPathTest.php | 1 + .../Tests/Constraints/FileValidatorTest.php | 22 +- .../Tests/Constraints/IbanValidatorTest.php | 29 +-- .../Tests/Constraints/ImageValidatorTest.php | 24 +++ .../Tests/Constraints/IsbnValidatorTest.php | 70 +++--- .../Tests/Constraints/IssnValidatorTest.php | 21 +- .../Tests/Constraints/LengthValidatorTest.php | 4 + .../Tests/Constraints/LuhnValidatorTest.php | 13 +- .../Tests/Constraints/RangeValidatorTest.php | 41 ++-- .../Tests/Constraints/TimeValidatorTest.php | 17 +- .../Tests/Constraints/UuidValidatorTest.php | 119 ++++++----- .../Tests/Validator/Abstract2Dot5ApiTest.php | 4 +- .../ConstraintViolationBuilderInterface.php | 4 +- 61 files changed, 845 insertions(+), 224 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Validator/Constraints/Form.php b/src/Symfony/Component/Form/Extension/Validator/Constraints/Form.php index 87e332976553..da1a92b5e40b 100644 --- a/src/Symfony/Component/Form/Extension/Validator/Constraints/Form.php +++ b/src/Symfony/Component/Form/Extension/Validator/Constraints/Form.php @@ -18,11 +18,20 @@ */ class Form extends Constraint { + const NOT_SYNCHRONIZED_ERROR = 1; + const NO_SUCH_FIELD_ERROR = 2; + /** - * Violation code marking an invalid form. + * @deprecated Deprecated since Symfony 2.6, to be removed in 3.0. Use + * {@self NOT_SYNCHRONIZED_ERROR} instead. */ const ERR_INVALID = 1; + protected static $errorNames = array( + self::NOT_SYNCHRONIZED_ERROR => 'NOT_SYNCHRONIZED_ERROR', + self::NO_SUCH_FIELD_ERROR => 'NO_SUCH_FIELD_ERROR', + ); + /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php index 7c0dc44ab180..d4e6f466fcae 100644 --- a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php +++ b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php @@ -102,7 +102,7 @@ public function validate($form, Constraint $constraint) $this->buildViolation($config->getOption('invalid_message')) ->setParameters(array_replace(array('{{ value }}' => $clientDataAsString), $config->getOption('invalid_message_parameters'))) ->setInvalidValue($form->getViewData()) - ->setCode(Form::ERR_INVALID) + ->setCode(Form::NOT_SYNCHRONIZED_ERROR) ->setCause($form->getTransformationFailure()) ->addViolation(); } @@ -113,6 +113,7 @@ public function validate($form, Constraint $constraint) $this->buildViolation($config->getOption('extra_fields_message')) ->setParameter('{{ extra_fields }}', implode('", "', array_keys($form->getExtraData()))) ->setInvalidValue($form->getExtraData()) + ->setCode(Form::NO_SUCH_FIELD_ERROR) ->addViolation(); } } diff --git a/src/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php b/src/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php index 62c59ddc4323..37f194380a4e 100644 --- a/src/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php +++ b/src/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php @@ -66,7 +66,7 @@ public function validateForm(FormEvent $event) foreach ($violations as $violation) { // Allow the "invalid" constraint to be put onto // non-synchronized forms - $allowNonSynchronized = Form::ERR_INVALID === $violation->getCode(); + $allowNonSynchronized = $violation->getConstraint() instanceof Form && Form::NOT_SYNCHRONIZED_ERROR === $violation->getCode(); $this->violationMapper->mapViolation($violation, $form, $allowNonSynchronized); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php index 877797f16389..5fa4f39f09a4 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php @@ -231,7 +231,7 @@ function () { throw new TransformationFailedException(); } ->setParameter('{{ value }}', 'foo') ->setParameter('{{ foo }}', 'bar') ->setInvalidValue('foo') - ->setCode(Form::ERR_INVALID) + ->setCode(Form::NOT_SYNCHRONIZED_ERROR) ->setCause($is2Dot4Api ? null : $form->getTransformationFailure()) ->assertRaised(); } @@ -268,7 +268,7 @@ function () { throw new TransformationFailedException(); } ->setParameter('{{ value }}', 'foo') ->setParameter('{{ foo }}', 'bar') ->setInvalidValue('foo') - ->setCode(Form::ERR_INVALID) + ->setCode(Form::NOT_SYNCHRONIZED_ERROR) ->setCause($is2Dot4Api ? null : $form->getTransformationFailure()) ->assertRaised(); } @@ -304,7 +304,7 @@ function () { throw new TransformationFailedException(); } $this->buildViolation('invalid_message_key') ->setParameter('{{ value }}', 'foo') ->setInvalidValue('foo') - ->setCode(Form::ERR_INVALID) + ->setCode(Form::NOT_SYNCHRONIZED_ERROR) ->setCause($is2Dot4Api ? null : $form->getTransformationFailure()) ->assertRaised(); } @@ -558,9 +558,11 @@ public function testViolationIfExtraData() $this->validator->validate($form, new Form()); - $this->assertViolation('Extra!', array( - '{{ extra_fields }}' => 'foo', - ), 'property.path', array('foo' => 'bar')); + $this->buildViolation('Extra!') + ->setParameter('{{ extra_fields }}', 'foo') + ->setInvalidValue(array('foo' => 'bar')) + ->setCode(Form::NO_SUCH_FIELD_ERROR) + ->assertRaised(); } public function testNoViolationIfAllowExtraData() diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php index d819277db08d..845dc8502578 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php @@ -66,7 +66,7 @@ protected function setUp() private function getConstraintViolation($code = null) { - return new ConstraintViolation($this->message, $this->messageTemplate, $this->params, null, 'prop.path', null, null, $code); + return new ConstraintViolation($this->message, $this->messageTemplate, $this->params, null, 'prop.path', null, null, $code, new Form()); } private function getBuilder($name = 'name', $propertyPath = null, $dataClass = null) @@ -109,7 +109,7 @@ public function testMapViolation() public function testMapViolationAllowsNonSyncIfInvalid() { - $violation = $this->getConstraintViolation(Form::ERR_INVALID); + $violation = $this->getConstraintViolation(Form::NOT_SYNCHRONIZED_ERROR); $form = $this->getForm('street'); $this->validator->expects($this->once()) diff --git a/src/Symfony/Component/Validator/Constraint.php b/src/Symfony/Component/Validator/Constraint.php index b6bc216159cd..b08ddfba4180 100644 --- a/src/Symfony/Component/Validator/Constraint.php +++ b/src/Symfony/Component/Validator/Constraint.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; +use Symfony\Component\Validator\Exception\InvalidArgumentException; use Symfony\Component\Validator\Exception\InvalidOptionsException; use Symfony\Component\Validator\Exception\MissingOptionsException; @@ -50,12 +51,40 @@ abstract class Constraint */ const PROPERTY_CONSTRAINT = 'property'; + /** + * Maps error codes to the names of their constants + * @var array + */ + protected static $errorNames = array(); + /** * Domain-specific data attached to a constraint * @var mixed */ public $payload; + /** + * Returns the name of the given error code. + * + * @param int $errorCode The error code + * + * @return string The name of the error code + * + * @throws InvalidArgumentException If the error code does not exist + */ + public static function getErrorName($errorCode) + { + if (!isset(static::$errorNames[$errorCode])) { + throw new InvalidArgumentException(sprintf( + 'The error code "%s" does not exist for constraint of type "%s".', + $errorCode, + get_called_class() + )); + } + + return static::$errorNames[$errorCode]; + } + /** * Initializes the constraint with options. * diff --git a/src/Symfony/Component/Validator/Constraints/CardScheme.php b/src/Symfony/Component/Validator/Constraints/CardScheme.php index 26a0e1c2fd46..14f3b5d8cf0c 100644 --- a/src/Symfony/Component/Validator/Constraints/CardScheme.php +++ b/src/Symfony/Component/Validator/Constraints/CardScheme.php @@ -20,9 +20,18 @@ * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) * * @author Tim Nagel + * @author Bernhard Schussek */ class CardScheme extends Constraint { + const NOT_NUMERIC_ERROR = 1; + const INVALID_FORMAT_ERROR = 2; + + protected static $errorNames = array( + self::NOT_NUMERIC_ERROR => 'NOT_NUMERIC_ERROR', + self::INVALID_FORMAT_ERROR => 'INVALID_FORMAT_ERROR', + ); + public $message = 'Unsupported card type or invalid card number.'; public $schemes; diff --git a/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php b/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php index 7cf7fa4bfe04..62492e61eaae 100644 --- a/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php @@ -117,6 +117,7 @@ public function validate($value, Constraint $constraint) if (!is_numeric($value)) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(CardScheme::NOT_NUMERIC_ERROR) ->addViolation(); return; @@ -135,6 +136,7 @@ public function validate($value, Constraint $constraint) $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(CardScheme::INVALID_FORMAT_ERROR) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Constraints/Choice.php b/src/Symfony/Component/Validator/Constraints/Choice.php index 467b58630310..39a64574d0d2 100644 --- a/src/Symfony/Component/Validator/Constraints/Choice.php +++ b/src/Symfony/Component/Validator/Constraints/Choice.php @@ -23,6 +23,16 @@ */ class Choice extends Constraint { + const NO_SUCH_CHOICE_ERROR = 1; + const TOO_FEW_ERROR = 2; + const TOO_MANY_ERROR = 3; + + protected static $errorNames = array( + self::NO_SUCH_CHOICE_ERROR => 'NO_SUCH_CHOICE_ERROR', + self::TOO_FEW_ERROR => 'TOO_FEW_ERROR', + self::TOO_MANY_ERROR => 'TOO_MANY_ERROR', + ); + public $choices; public $callback; public $multiple = false; diff --git a/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php b/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php index 5640c733173a..1566c318c3de 100644 --- a/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php +++ b/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php @@ -65,6 +65,7 @@ public function validate($value, Constraint $constraint) if (!in_array($_value, $choices, $constraint->strict)) { $this->buildViolation($constraint->multipleMessage) ->setParameter('{{ value }}', $this->formatValue($_value)) + ->setCode(Choice::NO_SUCH_CHOICE_ERROR) ->setInvalidValue($_value) ->addViolation(); @@ -78,6 +79,7 @@ public function validate($value, Constraint $constraint) $this->buildViolation($constraint->minMessage) ->setParameter('{{ limit }}', $constraint->min) ->setPlural((int) $constraint->min) + ->setCode(Choice::TOO_FEW_ERROR) ->addViolation(); return; @@ -87,6 +89,7 @@ public function validate($value, Constraint $constraint) $this->buildViolation($constraint->maxMessage) ->setParameter('{{ limit }}', $constraint->max) ->setPlural((int) $constraint->max) + ->setCode(Choice::TOO_MANY_ERROR) ->addViolation(); return; @@ -94,6 +97,7 @@ public function validate($value, Constraint $constraint) } elseif (!in_array($value, $choices, $constraint->strict)) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Choice::NO_SUCH_CHOICE_ERROR) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Constraints/Collection.php b/src/Symfony/Component/Validator/Constraints/Collection.php index 9917c527c0ae..708c8ed47730 100644 --- a/src/Symfony/Component/Validator/Constraints/Collection.php +++ b/src/Symfony/Component/Validator/Constraints/Collection.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; /** @@ -24,6 +23,14 @@ */ class Collection extends Composite { + const MISSING_FIELD_ERROR = 1; + const NO_SUCH_FIELD_ERROR = 2; + + protected static $errorNames = array( + self::MISSING_FIELD_ERROR => 'MISSING_FIELD_ERROR', + self::NO_SUCH_FIELD_ERROR => 'NO_SUCH_FIELD_ERROR', + ); + public $fields = array(); public $allowExtraFields = false; public $allowMissingFields = false; diff --git a/src/Symfony/Component/Validator/Constraints/CollectionValidator.php b/src/Symfony/Component/Validator/Constraints/CollectionValidator.php index 5ff67f9fe770..c3180d21622b 100644 --- a/src/Symfony/Component/Validator/Constraints/CollectionValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CollectionValidator.php @@ -73,6 +73,7 @@ public function validate($value, Constraint $constraint) ->atPath('['.$field.']') ->setParameter('{{ field }}', $this->formatValue($field)) ->setInvalidValue(null) + ->setCode(Collection::MISSING_FIELD_ERROR) ->addViolation(); } } @@ -84,6 +85,7 @@ public function validate($value, Constraint $constraint) ->atPath('['.$field.']') ->setParameter('{{ field }}', $this->formatValue($field)) ->setInvalidValue($fieldValue) + ->setCode(Collection::NO_SUCH_FIELD_ERROR) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Constraints/Count.php b/src/Symfony/Component/Validator/Constraints/Count.php index 1d64344b4ab6..a3e12fe1342d 100644 --- a/src/Symfony/Component/Validator/Constraints/Count.php +++ b/src/Symfony/Component/Validator/Constraints/Count.php @@ -24,6 +24,14 @@ */ class Count extends Constraint { + const TOO_FEW_ERROR = 1; + const TOO_MANY_ERROR = 2; + + protected static $errorNames = array( + self::TOO_FEW_ERROR => 'TOO_FEW_ERROR', + self::TOO_MANY_ERROR => 'TOO_MANY_ERROR', + ); + public $minMessage = 'This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more.'; public $maxMessage = 'This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less.'; public $exactMessage = 'This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements.'; diff --git a/src/Symfony/Component/Validator/Constraints/CountValidator.php b/src/Symfony/Component/Validator/Constraints/CountValidator.php index 0f40a3f1e0de..d44f537071a3 100644 --- a/src/Symfony/Component/Validator/Constraints/CountValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CountValidator.php @@ -41,6 +41,7 @@ public function validate($value, Constraint $constraint) ->setParameter('{{ limit }}', $constraint->max) ->setInvalidValue($value) ->setPlural((int) $constraint->max) + ->setCode(Count::TOO_MANY_ERROR) ->addViolation(); return; @@ -52,6 +53,7 @@ public function validate($value, Constraint $constraint) ->setParameter('{{ limit }}', $constraint->min) ->setInvalidValue($value) ->setPlural((int) $constraint->min) + ->setCode(Count::TOO_FEW_ERROR) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Constraints/Date.php b/src/Symfony/Component/Validator/Constraints/Date.php index 9e2916896515..2bc444f71af6 100644 --- a/src/Symfony/Component/Validator/Constraints/Date.php +++ b/src/Symfony/Component/Validator/Constraints/Date.php @@ -23,5 +23,13 @@ */ class Date extends Constraint { + const INVALID_FORMAT_ERROR = 1; + const INVALID_DATE_ERROR = 2; + + protected static $errorNames = array( + self::INVALID_FORMAT_ERROR => 'INVALID_FORMAT_ERROR', + self::INVALID_DATE_ERROR => 'INVALID_DATE_ERROR', + ); + public $message = 'This value is not a valid date.'; } diff --git a/src/Symfony/Component/Validator/Constraints/DateTime.php b/src/Symfony/Component/Validator/Constraints/DateTime.php index 1657f43afcd1..ae67ff30efb4 100644 --- a/src/Symfony/Component/Validator/Constraints/DateTime.php +++ b/src/Symfony/Component/Validator/Constraints/DateTime.php @@ -23,5 +23,15 @@ */ class DateTime extends Constraint { + const INVALID_FORMAT_ERROR = 1; + const INVALID_DATE_ERROR = 2; + const INVALID_TIME_ERROR = 3; + + protected static $errorNames = array( + self::INVALID_FORMAT_ERROR => 'INVALID_FORMAT_ERROR', + self::INVALID_DATE_ERROR => 'INVALID_DATE_ERROR', + self::INVALID_TIME_ERROR => 'INVALID_TIME_ERROR', + ); + public $message = 'This value is not a valid datetime.'; } diff --git a/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php b/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php index 88c8e2586229..b459c7873f7c 100644 --- a/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php +++ b/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php @@ -45,6 +45,7 @@ public function validate($value, Constraint $constraint) if (!preg_match(static::PATTERN, $value, $matches)) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(DateTime::INVALID_FORMAT_ERROR) ->addViolation(); return; @@ -53,12 +54,14 @@ public function validate($value, Constraint $constraint) if (!DateValidator::checkDate($matches[1], $matches[2], $matches[3])) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(DateTime::INVALID_DATE_ERROR) ->addViolation(); } if (!TimeValidator::checkTime($matches[4], $matches[5], $matches[6])) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(DateTime::INVALID_TIME_ERROR) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Constraints/DateValidator.php b/src/Symfony/Component/Validator/Constraints/DateValidator.php index e1640b13b385..77f011166661 100644 --- a/src/Symfony/Component/Validator/Constraints/DateValidator.php +++ b/src/Symfony/Component/Validator/Constraints/DateValidator.php @@ -62,6 +62,7 @@ public function validate($value, Constraint $constraint) if (!preg_match(static::PATTERN, $value, $matches)) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Date::INVALID_FORMAT_ERROR) ->addViolation(); return; @@ -70,6 +71,7 @@ public function validate($value, Constraint $constraint) if (!self::checkDate($matches[1], $matches[2], $matches[3])) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Date::INVALID_DATE_ERROR) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Constraints/Email.php b/src/Symfony/Component/Validator/Constraints/Email.php index 1f8755750bc2..36977177bdfd 100644 --- a/src/Symfony/Component/Validator/Constraints/Email.php +++ b/src/Symfony/Component/Validator/Constraints/Email.php @@ -23,6 +23,16 @@ */ class Email extends Constraint { + const INVALID_FORMAT_ERROR = 1; + const MX_CHECK_FAILED_ERROR = 2; + const HOST_CHECK_FAILED_ERROR = 3; + + protected static $errorNames = array( + self::INVALID_FORMAT_ERROR => 'STRICT_CHECK_FAILED_ERROR', + self::MX_CHECK_FAILED_ERROR => 'MX_CHECK_FAILED_ERROR', + self::HOST_CHECK_FAILED_ERROR => 'HOST_CHECK_FAILED_ERROR', + ); + public $message = 'This value is not a valid email address.'; public $checkMX = false; public $checkHost = false; diff --git a/src/Symfony/Component/Validator/Constraints/EmailValidator.php b/src/Symfony/Component/Validator/Constraints/EmailValidator.php index 1f487ca1c4a4..ee588dca9f8c 100644 --- a/src/Symfony/Component/Validator/Constraints/EmailValidator.php +++ b/src/Symfony/Component/Validator/Constraints/EmailValidator.php @@ -68,6 +68,7 @@ public function validate($value, Constraint $constraint) if (!$strictValidator->isValid($value, false, true)) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Email::INVALID_FORMAT_ERROR) ->addViolation(); return; @@ -75,6 +76,7 @@ public function validate($value, Constraint $constraint) } elseif (!preg_match('/.+\@.+\..+/', $value)) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Email::INVALID_FORMAT_ERROR) ->addViolation(); return; @@ -87,6 +89,7 @@ public function validate($value, Constraint $constraint) if (!$this->checkMX($host)) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Email::MX_CHECK_FAILED_ERROR) ->addViolation(); } @@ -96,6 +99,7 @@ public function validate($value, Constraint $constraint) if ($constraint->checkHost && !$this->checkHost($host)) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Email::HOST_CHECK_FAILED_ERROR) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Constraints/File.php b/src/Symfony/Component/Validator/Constraints/File.php index 9ed818c13bed..6bfea29ed968 100644 --- a/src/Symfony/Component/Validator/Constraints/File.php +++ b/src/Symfony/Component/Validator/Constraints/File.php @@ -24,6 +24,22 @@ */ class File extends Constraint { + // Check the Image constraint for clashes if adding new constants here + + const NOT_FOUND_ERROR = 1; + const NOT_READABLE_ERROR = 2; + const EMPTY_ERROR = 3; + const TOO_LARGE_ERROR = 4; + const INVALID_MIME_TYPE_ERROR = 5; + + protected static $errorNames = array( + self::NOT_FOUND_ERROR => 'NOT_FOUND_ERROR', + self::NOT_READABLE_ERROR => 'NOT_READABLE_ERROR', + self::EMPTY_ERROR => 'EMPTY_ERROR', + self::TOO_LARGE_ERROR => 'TOO_LARGE_ERROR', + self::INVALID_MIME_TYPE_ERROR => 'INVALID_MIME_TYPE_ERROR', + ); + public $maxSize; public $binaryFormat; public $mimeTypes = array(); diff --git a/src/Symfony/Component/Validator/Constraints/FileValidator.php b/src/Symfony/Component/Validator/Constraints/FileValidator.php index 78d6efe3ca4a..808a9885d010 100644 --- a/src/Symfony/Component/Validator/Constraints/FileValidator.php +++ b/src/Symfony/Component/Validator/Constraints/FileValidator.php @@ -62,36 +62,43 @@ public function validate($value, Constraint $constraint) $this->buildViolation($constraint->uploadIniSizeErrorMessage) ->setParameter('{{ limit }}', $limitInBytes) ->setParameter('{{ suffix }}', 'bytes') + ->setCode(UPLOAD_ERR_INI_SIZE) ->addViolation(); return; case UPLOAD_ERR_FORM_SIZE: $this->buildViolation($constraint->uploadFormSizeErrorMessage) + ->setCode(UPLOAD_ERR_FORM_SIZE) ->addViolation(); return; case UPLOAD_ERR_PARTIAL: $this->buildViolation($constraint->uploadPartialErrorMessage) + ->setCode(UPLOAD_ERR_PARTIAL) ->addViolation(); return; case UPLOAD_ERR_NO_FILE: $this->buildViolation($constraint->uploadNoFileErrorMessage) + ->setCode(UPLOAD_ERR_NO_FILE) ->addViolation(); return; case UPLOAD_ERR_NO_TMP_DIR: $this->buildViolation($constraint->uploadNoTmpDirErrorMessage) + ->setCode(UPLOAD_ERR_NO_TMP_DIR) ->addViolation(); return; case UPLOAD_ERR_CANT_WRITE: $this->buildViolation($constraint->uploadCantWriteErrorMessage) + ->setCode(UPLOAD_ERR_CANT_WRITE) ->addViolation(); return; case UPLOAD_ERR_EXTENSION: $this->buildViolation($constraint->uploadExtensionErrorMessage) + ->setCode(UPLOAD_ERR_EXTENSION) ->addViolation(); return; @@ -113,6 +120,7 @@ public function validate($value, Constraint $constraint) if (!is_file($path)) { $this->buildViolation($constraint->notFoundMessage) ->setParameter('{{ file }}', $this->formatValue($path)) + ->setCode(File::NOT_FOUND_ERROR) ->addViolation(); return; @@ -121,15 +129,24 @@ public function validate($value, Constraint $constraint) if (!is_readable($path)) { $this->buildViolation($constraint->notReadableMessage) ->setParameter('{{ file }}', $this->formatValue($path)) + ->setCode(File::NOT_READABLE_ERROR) ->addViolation(); return; } $sizeInBytes = filesize($path); + if (0 === $sizeInBytes) { - $this->context->addViolation($constraint->disallowEmptyMessage); - } elseif ($constraint->maxSize) { + $this->buildViolation($constraint->disallowEmptyMessage) + ->setParameter('{{ file }}', $this->formatValue($path)) + ->setCode(File::EMPTY_ERROR) + ->addViolation(); + + return; + } + + if ($constraint->maxSize) { $limitInBytes = $constraint->maxSize; if ($sizeInBytes > $limitInBytes) { @@ -168,6 +185,7 @@ public function validate($value, Constraint $constraint) ->setParameter('{{ size }}', $sizeAsString) ->setParameter('{{ limit }}', $limitAsString) ->setParameter('{{ suffix }}', self::$suffices[$coef]) + ->setCode(File::TOO_LARGE_ERROR) ->addViolation(); return; @@ -198,6 +216,7 @@ public function validate($value, Constraint $constraint) ->setParameter('{{ file }}', $this->formatValue($path)) ->setParameter('{{ type }}', $this->formatValue($mime)) ->setParameter('{{ types }}', $this->formatValues($mimeTypes)) + ->setCode(File::INVALID_MIME_TYPE_ERROR) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Constraints/Iban.php b/src/Symfony/Component/Validator/Constraints/Iban.php index 895a93cd5860..66ce09ae1a63 100644 --- a/src/Symfony/Component/Validator/Constraints/Iban.php +++ b/src/Symfony/Component/Validator/Constraints/Iban.php @@ -19,8 +19,23 @@ * * @author Manuel Reinhard * @author Michael Schummel + * @author Bernhard Schussek */ class Iban extends Constraint { + const TOO_SHORT_ERROR = 1; + const INVALID_COUNTRY_CODE_ERROR = 2; + const INVALID_CHARACTERS_ERROR = 3; + const INVALID_CASE_ERROR = 4; + const CHECKSUM_FAILED_ERROR = 5; + + protected static $errorNames = array( + self::TOO_SHORT_ERROR => 'TOO_SHORT_ERROR', + self::INVALID_COUNTRY_CODE_ERROR => 'INVALID_COUNTRY_CODE_ERROR', + self::INVALID_CHARACTERS_ERROR => 'INVALID_CHARACTERS_ERROR', + self::INVALID_CASE_ERROR => 'INVALID_CASE_ERROR', + self::CHECKSUM_FAILED_ERROR => 'CHECKSUM_FAILED_ERROR', + ); + public $message = 'This is not a valid International Bank Account Number (IBAN).'; } diff --git a/src/Symfony/Component/Validator/Constraints/IbanValidator.php b/src/Symfony/Component/Validator/Constraints/IbanValidator.php index b66561dc2ade..c8bcf4b1ab09 100644 --- a/src/Symfony/Component/Validator/Constraints/IbanValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IbanValidator.php @@ -49,6 +49,7 @@ public function validate($value, Constraint $constraint) if (strlen($canonicalized) < 4) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Iban::TOO_SHORT_ERROR) ->addViolation(); return; @@ -58,6 +59,7 @@ public function validate($value, Constraint $constraint) if (!ctype_alpha($canonicalized{0}) || !ctype_alpha($canonicalized{1})) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Iban::INVALID_COUNTRY_CODE_ERROR) ->addViolation(); return; @@ -67,6 +69,7 @@ public function validate($value, Constraint $constraint) if (!ctype_alnum($canonicalized)) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Iban::INVALID_CHARACTERS_ERROR) ->addViolation(); return; @@ -76,6 +79,7 @@ public function validate($value, Constraint $constraint) if ($canonicalized !== strtoupper($canonicalized)) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Iban::INVALID_CASE_ERROR) ->addViolation(); return; @@ -99,6 +103,7 @@ public function validate($value, Constraint $constraint) if (1 !== $this->bigModulo97($checkSum)) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Iban::CHECKSUM_FAILED_ERROR) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Constraints/Image.php b/src/Symfony/Component/Validator/Constraints/Image.php index 9804fd90cc1c..904ef97b492b 100644 --- a/src/Symfony/Component/Validator/Constraints/Image.php +++ b/src/Symfony/Component/Validator/Constraints/Image.php @@ -16,11 +16,45 @@ * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) * * @author Benjamin Dulau + * @author Bernhard Schussek * * @api */ class Image extends File { + // Don't reuse values used in File + + const SIZE_NOT_DETECTED_ERROR = 10; + const TOO_WIDE_ERROR = 11; + const TOO_NARROW_ERROR = 12; + const TOO_HIGH_ERROR = 13; + const TOO_LOW_ERROR = 14; + const RATIO_TOO_BIG_ERROR = 15; + const RATIO_TOO_SMALL_ERROR = 16; + const SQUARE_NOT_ALLOWED_ERROR = 17; + const LANDSCAPE_NOT_ALLOWED_ERROR = 18; + const PORTRAIT_NOT_ALLOWED_ERROR = 19; + + // Include the mapping from the base class + + protected static $errorNames = array( + self::NOT_FOUND_ERROR => 'NOT_FOUND_ERROR', + self::NOT_READABLE_ERROR => 'NOT_READABLE_ERROR', + self::EMPTY_ERROR => 'EMPTY_ERROR', + self::TOO_LARGE_ERROR => 'TOO_LARGE_ERROR', + self::INVALID_MIME_TYPE_ERROR => 'INVALID_MIME_TYPE_ERROR', + self::SIZE_NOT_DETECTED_ERROR => 'SIZE_NOT_DETECTED_ERROR', + self::TOO_WIDE_ERROR => 'TOO_WIDE_ERROR', + self::TOO_NARROW_ERROR => 'TOO_NARROW_ERROR', + self::TOO_HIGH_ERROR => 'TOO_HIGH_ERROR', + self::TOO_LOW_ERROR => 'TOO_LOW_ERROR', + self::RATIO_TOO_BIG_ERROR => 'RATIO_TOO_BIG_ERROR', + self::RATIO_TOO_SMALL_ERROR => 'RATIO_TOO_SMALL_ERROR', + self::SQUARE_NOT_ALLOWED_ERROR => 'SQUARE_NOT_ALLOWED_ERROR', + self::LANDSCAPE_NOT_ALLOWED_ERROR => 'LANDSCAPE_NOT_ALLOWED_ERROR', + self::PORTRAIT_NOT_ALLOWED_ERROR => 'PORTRAIT_NOT_ALLOWED_ERROR', + ); + public $mimeTypes = 'image/*'; public $minWidth; public $maxWidth; diff --git a/src/Symfony/Component/Validator/Constraints/ImageValidator.php b/src/Symfony/Component/Validator/Constraints/ImageValidator.php index 4eaed687dc98..3444c3896734 100644 --- a/src/Symfony/Component/Validator/Constraints/ImageValidator.php +++ b/src/Symfony/Component/Validator/Constraints/ImageValidator.php @@ -54,6 +54,7 @@ public function validate($value, Constraint $constraint) if (empty($size) || ($size[0] === 0) || ($size[1] === 0)) { $this->buildViolation($constraint->sizeNotDetectedMessage) + ->setCode(Image::SIZE_NOT_DETECTED_ERROR) ->addViolation(); return; @@ -71,6 +72,7 @@ public function validate($value, Constraint $constraint) $this->buildViolation($constraint->minWidthMessage) ->setParameter('{{ width }}', $width) ->setParameter('{{ min_width }}', $constraint->minWidth) + ->setCode(Image::TOO_NARROW_ERROR) ->addViolation(); return; @@ -86,6 +88,7 @@ public function validate($value, Constraint $constraint) $this->buildViolation($constraint->maxWidthMessage) ->setParameter('{{ width }}', $width) ->setParameter('{{ max_width }}', $constraint->maxWidth) + ->setCode(Image::TOO_WIDE_ERROR) ->addViolation(); return; @@ -101,6 +104,7 @@ public function validate($value, Constraint $constraint) $this->buildViolation($constraint->minHeightMessage) ->setParameter('{{ height }}', $height) ->setParameter('{{ min_height }}', $constraint->minHeight) + ->setCode(Image::TOO_LOW_ERROR) ->addViolation(); return; @@ -116,6 +120,7 @@ public function validate($value, Constraint $constraint) $this->buildViolation($constraint->maxHeightMessage) ->setParameter('{{ height }}', $height) ->setParameter('{{ max_height }}', $constraint->maxHeight) + ->setCode(Image::TOO_HIGH_ERROR) ->addViolation(); } } @@ -131,6 +136,7 @@ public function validate($value, Constraint $constraint) $this->buildViolation($constraint->minRatioMessage) ->setParameter('{{ ratio }}', $ratio) ->setParameter('{{ min_ratio }}', $constraint->minRatio) + ->setCode(Image::RATIO_TOO_SMALL_ERROR) ->addViolation(); } } @@ -144,6 +150,7 @@ public function validate($value, Constraint $constraint) $this->buildViolation($constraint->maxRatioMessage) ->setParameter('{{ ratio }}', $ratio) ->setParameter('{{ max_ratio }}', $constraint->maxRatio) + ->setCode(Image::RATIO_TOO_BIG_ERROR) ->addViolation(); } } @@ -152,6 +159,7 @@ public function validate($value, Constraint $constraint) $this->buildViolation($constraint->allowSquareMessage) ->setParameter('{{ width }}', $width) ->setParameter('{{ height }}', $height) + ->setCode(Image::SQUARE_NOT_ALLOWED_ERROR) ->addViolation(); } @@ -159,6 +167,7 @@ public function validate($value, Constraint $constraint) $this->buildViolation($constraint->allowLandscapeMessage) ->setParameter('{{ width }}', $width) ->setParameter('{{ height }}', $height) + ->setCode(Image::LANDSCAPE_NOT_ALLOWED_ERROR) ->addViolation(); } @@ -166,6 +175,7 @@ public function validate($value, Constraint $constraint) $this->buildViolation($constraint->allowPortraitMessage) ->setParameter('{{ width }}', $width) ->setParameter('{{ height }}', $height) + ->setCode(Image::PORTRAIT_NOT_ALLOWED_ERROR) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Constraints/Isbn.php b/src/Symfony/Component/Validator/Constraints/Isbn.php index 90abedd2a806..67d177f4e043 100644 --- a/src/Symfony/Component/Validator/Constraints/Isbn.php +++ b/src/Symfony/Component/Validator/Constraints/Isbn.php @@ -19,9 +19,24 @@ * * @author The Whole Life To Learn * @author Manuel Reinhard + * @author Bernhard Schussek */ class Isbn extends Constraint { + const TOO_SHORT_ERROR = 1; + const TOO_LONG_ERROR = 2; + const INVALID_CHARACTERS_ERROR = 3; + const CHECKSUM_FAILED_ERROR = 4; + const TYPE_NOT_RECOGNIZED_ERROR = 5; + + protected static $errorNames = array( + self::TOO_SHORT_ERROR => 'TOO_SHORT_ERROR', + self::TOO_LONG_ERROR => 'TOO_LONG_ERROR', + self::INVALID_CHARACTERS_ERROR => 'INVALID_CHARACTERS_ERROR', + self::CHECKSUM_FAILED_ERROR => 'CHECKSUM_FAILED_ERROR', + self::TYPE_NOT_RECOGNIZED_ERROR => 'TYPE_NOT_RECOGNIZED_ERROR', + ); + public $isbn10Message = 'This value is not a valid ISBN-10.'; public $isbn13Message = 'This value is not a valid ISBN-13.'; public $bothIsbnMessage = 'This value is neither a valid ISBN-10 nor a valid ISBN-13.'; diff --git a/src/Symfony/Component/Validator/Constraints/IsbnValidator.php b/src/Symfony/Component/Validator/Constraints/IsbnValidator.php index 8972b9161040..8a53fe7941d1 100644 --- a/src/Symfony/Component/Validator/Constraints/IsbnValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IsbnValidator.php @@ -56,9 +56,10 @@ public function validate($value, Constraint $constraint) // Explicitly validate against ISBN-10 if ('isbn10' === $constraint->type) { - if (!$this->validateIsbn10($canonical)) { + if (true !== ($code = $this->validateIsbn10($canonical))) { $this->buildViolation($this->getMessage($constraint, $constraint->type)) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode($code) ->addViolation(); } @@ -67,9 +68,10 @@ public function validate($value, Constraint $constraint) // Explicitly validate against ISBN-13 if ('isbn13' === $constraint->type) { - if (!$this->validateIsbn13($canonical)) { + if (true !== ($code = $this->validateIsbn13($canonical))) { $this->buildViolation($this->getMessage($constraint, $constraint->type)) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode($code) ->addViolation(); } @@ -77,20 +79,49 @@ public function validate($value, Constraint $constraint) } // Try both ISBNs - if (!$this->validateIsbn10($canonical) && !$this->validateIsbn13($canonical)) { + + // First, try ISBN-10 + $code = $this->validateIsbn10($canonical); + + // The ISBN can only be an ISBN-13 if the value was too long for ISBN-10 + if (Isbn::TOO_LONG_ERROR === $code) { + // Try ISBN-13 now + $code = $this->validateIsbn13($canonical); + + // If too short, this means we have 11 or 12 digits + if (Isbn::TOO_SHORT_ERROR === $code) { + $code = Isbn::TYPE_NOT_RECOGNIZED_ERROR; + } + } + + if (true !== $code) { $this->buildViolation($this->getMessage($constraint)) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode($code) ->addViolation(); } } protected function validateIsbn10($isbn) { + // Choose an algorithm so that ERROR_INVALID_CHARACTERS is preferred + // over ERROR_TOO_SHORT/ERROR_TOO_LONG + // Otherwise "0-45122-5244" passes, but "0-45122_5244" reports + // "too long" + + // Error priority: + // 1. ERROR_INVALID_CHARACTERS + // 2. ERROR_TOO_SHORT/ERROR_TOO_LONG + // 3. ERROR_CHECKSUM_FAILED + $checkSum = 0; for ($i = 0; $i < 10; ++$i) { + // If we test the length before the loop, we get an ERROR_TOO_SHORT + // when actually an ERROR_INVALID_CHARACTERS is wanted, e.g. for + // "0-45122_5244" (typo) if (!isset($isbn{$i})) { - return false; + return Isbn::TOO_SHORT_ERROR; } if ('X' === $isbn{$i}) { @@ -98,33 +129,38 @@ protected function validateIsbn10($isbn) } elseif (ctype_digit($isbn{$i})) { $digit = $isbn{$i}; } else { - return false; + return Isbn::INVALID_CHARACTERS_ERROR; } $checkSum += $digit * intval(10 - $i); } if (isset($isbn{$i})) { - return false; + return Isbn::TOO_LONG_ERROR; } - return 0 === $checkSum % 11; + return 0 === $checkSum % 11 ? true : Isbn::CHECKSUM_FAILED_ERROR; } protected function validateIsbn13($isbn) { + // Error priority: + // 1. ERROR_INVALID_CHARACTERS + // 2. ERROR_TOO_SHORT/ERROR_TOO_LONG + // 3. ERROR_CHECKSUM_FAILED + if (!ctype_digit($isbn)) { - return false; + return Isbn::INVALID_CHARACTERS_ERROR; } $length = strlen($isbn); if ($length < 13) { - return false; + return Isbn::TOO_SHORT_ERROR; } if ($length > 13) { - return false; + return Isbn::TOO_LONG_ERROR; } $checkSum = 0; @@ -138,7 +174,7 @@ protected function validateIsbn13($isbn) * 3; } - return 0 === $checkSum % 10; + return 0 === $checkSum % 10 ? true : Isbn::CHECKSUM_FAILED_ERROR; } protected function getMessage($constraint, $type = null) diff --git a/src/Symfony/Component/Validator/Constraints/Issn.php b/src/Symfony/Component/Validator/Constraints/Issn.php index 01a0f4315f6b..39716a28cce3 100644 --- a/src/Symfony/Component/Validator/Constraints/Issn.php +++ b/src/Symfony/Component/Validator/Constraints/Issn.php @@ -18,9 +18,26 @@ * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) * * @author Antonio J. GarcĂ­a Lagar + * @author Bernhard Schussek */ class Issn extends Constraint { + const TOO_SHORT_ERROR = 1; + const TOO_LONG_ERROR = 2; + const MISSING_HYPHEN_ERROR = 3; + const INVALID_CHARACTERS_ERROR = 4; + const INVALID_CASE_ERROR = 5; + const CHECKSUM_FAILED_ERROR = 6; + + protected static $errorNames = array( + self::TOO_SHORT_ERROR => 'TOO_SHORT_ERROR', + self::TOO_LONG_ERROR => 'TOO_LONG_ERROR', + self::MISSING_HYPHEN_ERROR => 'MISSING_HYPHEN_ERROR', + self::INVALID_CHARACTERS_ERROR => 'INVALID_CHARACTERS_ERROR', + self::INVALID_CASE_ERROR => 'INVALID_CASE_ERROR', + self::CHECKSUM_FAILED_ERROR => 'CHECKSUM_FAILED_ERROR', + ); + public $message = 'This value is not a valid ISSN.'; public $caseSensitive = false; public $requireHyphen = false; diff --git a/src/Symfony/Component/Validator/Constraints/IssnValidator.php b/src/Symfony/Component/Validator/Constraints/IssnValidator.php index 2ee8a53dfd7e..e8f28e6a4fbc 100644 --- a/src/Symfony/Component/Validator/Constraints/IssnValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IssnValidator.php @@ -53,6 +53,7 @@ public function validate($value, Constraint $constraint) } elseif ($constraint->requireHyphen) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Issn::MISSING_HYPHEN_ERROR) ->addViolation(); return; @@ -63,6 +64,7 @@ public function validate($value, Constraint $constraint) if ($length < 8) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Issn::TOO_SHORT_ERROR) ->addViolation(); return; @@ -71,6 +73,7 @@ public function validate($value, Constraint $constraint) if ($length > 8) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Issn::TOO_LONG_ERROR) ->addViolation(); return; @@ -81,6 +84,7 @@ public function validate($value, Constraint $constraint) if (!ctype_digit(substr($canonical, 0, 7))) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Issn::INVALID_CHARACTERS_ERROR) ->addViolation(); return; @@ -91,6 +95,7 @@ public function validate($value, Constraint $constraint) if (!ctype_digit($canonical{7}) && 'x' !== $canonical{7} && 'X' !== $canonical{7}) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Issn::INVALID_CHARACTERS_ERROR) ->addViolation(); return; @@ -101,6 +106,7 @@ public function validate($value, Constraint $constraint) if ($constraint->caseSensitive && 'x' === $canonical{7}) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Issn::INVALID_CASE_ERROR) ->addViolation(); return; @@ -119,6 +125,7 @@ public function validate($value, Constraint $constraint) if (0 !== $checkSum % 11) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Issn::CHECKSUM_FAILED_ERROR) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Constraints/Length.php b/src/Symfony/Component/Validator/Constraints/Length.php index b353e9b24d3f..60a46cb8ea1f 100644 --- a/src/Symfony/Component/Validator/Constraints/Length.php +++ b/src/Symfony/Component/Validator/Constraints/Length.php @@ -24,6 +24,14 @@ */ class Length extends Constraint { + const TOO_SHORT_ERROR = 1; + const TOO_LONG_ERROR = 2; + + protected static $errorNames = array( + self::TOO_SHORT_ERROR => 'TOO_SHORT_ERROR', + self::TOO_LONG_ERROR => 'TOO_LONG_ERROR', + ); + public $maxMessage = 'This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less.'; public $minMessage = 'This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.'; public $exactMessage = 'This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters.'; diff --git a/src/Symfony/Component/Validator/Constraints/LengthValidator.php b/src/Symfony/Component/Validator/Constraints/LengthValidator.php index cdc5bea985df..19f3d3937b50 100644 --- a/src/Symfony/Component/Validator/Constraints/LengthValidator.php +++ b/src/Symfony/Component/Validator/Constraints/LengthValidator.php @@ -53,6 +53,7 @@ public function validate($value, Constraint $constraint) ->setParameter('{{ limit }}', $constraint->max) ->setInvalidValue($value) ->setPlural((int) $constraint->max) + ->setCode(Length::TOO_LONG_ERROR) ->addViolation(); return; @@ -64,6 +65,7 @@ public function validate($value, Constraint $constraint) ->setParameter('{{ limit }}', $constraint->min) ->setInvalidValue($value) ->setPlural((int) $constraint->min) + ->setCode(Length::TOO_SHORT_ERROR) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Constraints/Luhn.php b/src/Symfony/Component/Validator/Constraints/Luhn.php index e9b406adede1..24f5bc77ab76 100644 --- a/src/Symfony/Component/Validator/Constraints/Luhn.php +++ b/src/Symfony/Component/Validator/Constraints/Luhn.php @@ -21,8 +21,17 @@ * * @author Tim Nagel * @author Greg Knapp http://gregk.me/2011/php-implementation-of-bank-card-luhn-algorithm/ + * @author Bernhard Schussek */ class Luhn extends Constraint { + const INVALID_CHARACTERS_ERROR = 1; + const CHECKSUM_FAILED_ERROR = 2; + + protected static $errorNames = array( + self::INVALID_CHARACTERS_ERROR => 'INVALID_CHARACTERS_ERROR', + self::CHECKSUM_FAILED_ERROR => 'CHECKSUM_FAILED_ERROR', + ); + public $message = 'Invalid card number.'; } diff --git a/src/Symfony/Component/Validator/Constraints/LuhnValidator.php b/src/Symfony/Component/Validator/Constraints/LuhnValidator.php index c82d6d8917a0..d60b7f860559 100644 --- a/src/Symfony/Component/Validator/Constraints/LuhnValidator.php +++ b/src/Symfony/Component/Validator/Constraints/LuhnValidator.php @@ -57,6 +57,7 @@ public function validate($value, Constraint $constraint) if (!ctype_digit($value)) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Luhn::INVALID_CHARACTERS_ERROR) ->addViolation(); return; @@ -87,6 +88,7 @@ public function validate($value, Constraint $constraint) if (0 === $checkSum || 0 !== $checkSum % 10) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Luhn::CHECKSUM_FAILED_ERROR) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Constraints/Range.php b/src/Symfony/Component/Validator/Constraints/Range.php index 067ffb8bf34d..a12afffbedb8 100644 --- a/src/Symfony/Component/Validator/Constraints/Range.php +++ b/src/Symfony/Component/Validator/Constraints/Range.php @@ -24,6 +24,16 @@ */ class Range extends Constraint { + const INVALID_VALUE_ERROR = 1; + const BEYOND_RANGE_ERROR = 2; + const BELOW_RANGE_ERROR = 3; + + protected static $errorNames = array( + self::INVALID_VALUE_ERROR => 'INVALID_VALUE_ERROR', + self::BEYOND_RANGE_ERROR => 'BEYOND_RANGE_ERROR', + self::BELOW_RANGE_ERROR => 'BELOW_RANGE_ERROR', + ); + public $minMessage = 'This value should be {{ limit }} or more.'; public $maxMessage = 'This value should be {{ limit }} or less.'; public $invalidMessage = 'This value should be a valid number.'; diff --git a/src/Symfony/Component/Validator/Constraints/RangeValidator.php b/src/Symfony/Component/Validator/Constraints/RangeValidator.php index 6cd7afde6f34..c0bde2b72345 100644 --- a/src/Symfony/Component/Validator/Constraints/RangeValidator.php +++ b/src/Symfony/Component/Validator/Constraints/RangeValidator.php @@ -36,6 +36,7 @@ public function validate($value, Constraint $constraint) if (!is_numeric($value) && !$value instanceof \DateTime && !$value instanceof \DateTimeInterface) { $this->buildViolation($constraint->invalidMessage) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Range::INVALID_VALUE_ERROR) ->addViolation(); return; @@ -62,6 +63,7 @@ public function validate($value, Constraint $constraint) $this->buildViolation($constraint->maxMessage) ->setParameter('{{ value }}', $value) ->setParameter('{{ limit }}', $this->formatValue($max, self::PRETTY_DATE)) + ->setCode(Range::BEYOND_RANGE_ERROR) ->addViolation(); return; @@ -71,6 +73,7 @@ public function validate($value, Constraint $constraint) $this->buildViolation($constraint->minMessage) ->setParameter('{{ value }}', $value) ->setParameter('{{ limit }}', $this->formatValue($min, self::PRETTY_DATE)) + ->setCode(Range::BELOW_RANGE_ERROR) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Constraints/Time.php b/src/Symfony/Component/Validator/Constraints/Time.php index 42ede04325be..7998c6f9519b 100644 --- a/src/Symfony/Component/Validator/Constraints/Time.php +++ b/src/Symfony/Component/Validator/Constraints/Time.php @@ -23,5 +23,13 @@ */ class Time extends Constraint { + const INVALID_FORMAT_ERROR = 1; + const INVALID_TIME_ERROR = 2; + + protected static $errorNames = array( + self::INVALID_FORMAT_ERROR => 'INVALID_FORMAT_ERROR', + self::INVALID_TIME_ERROR => 'INVALID_TIME_ERROR', + ); + public $message = 'This value is not a valid time.'; } diff --git a/src/Symfony/Component/Validator/Constraints/TimeValidator.php b/src/Symfony/Component/Validator/Constraints/TimeValidator.php index 3d52fbe43585..bfecf95b52fb 100644 --- a/src/Symfony/Component/Validator/Constraints/TimeValidator.php +++ b/src/Symfony/Component/Validator/Constraints/TimeValidator.php @@ -62,6 +62,7 @@ public function validate($value, Constraint $constraint) if (!preg_match(static::PATTERN, $value, $matches)) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Time::INVALID_FORMAT_ERROR) ->addViolation(); return; @@ -70,6 +71,7 @@ public function validate($value, Constraint $constraint) if (!self::checkTime($matches[1], $matches[2], $matches[3])) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Time::INVALID_TIME_ERROR) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Constraints/Uuid.php b/src/Symfony/Component/Validator/Constraints/Uuid.php index dc73016401a1..3c67a3af0c16 100644 --- a/src/Symfony/Component/Validator/Constraints/Uuid.php +++ b/src/Symfony/Component/Validator/Constraints/Uuid.php @@ -17,9 +17,26 @@ * @Annotation * * @author Colin O'Dell + * @author Bernhard Schussek */ class Uuid extends Constraint { + const TOO_SHORT_ERROR = 1; + const TOO_LONG_ERROR = 2; + const INVALID_CHARACTERS_ERROR = 3; + const INVALID_HYPHEN_PLACEMENT_ERROR = 4; + const INVALID_VERSION_ERROR = 5; + const INVALID_VARIANT_ERROR = 6; + + protected static $errorNames = array( + self::TOO_SHORT_ERROR => 'TOO_SHORT_ERROR', + self::TOO_LONG_ERROR => 'TOO_LONG_ERROR', + self::INVALID_CHARACTERS_ERROR => 'INVALID_CHARACTERS_ERROR', + self::INVALID_HYPHEN_PLACEMENT_ERROR => 'INVALID_HYPHEN_PLACEMENT_ERROR', + self::INVALID_VERSION_ERROR => 'INVALID_VERSION_ERROR', + self::INVALID_VARIANT_ERROR => 'INVALID_VARIANT_ERROR', + ); + // Possible versions defined by RFC 4122 const V1_MAC = 1; const V2_DCE = 2; diff --git a/src/Symfony/Component/Validator/Constraints/UuidValidator.php b/src/Symfony/Component/Validator/Constraints/UuidValidator.php index 5361f12de0f0..fa90778dedd9 100644 --- a/src/Symfony/Component/Validator/Constraints/UuidValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UuidValidator.php @@ -26,28 +26,49 @@ */ class UuidValidator extends ConstraintValidator { + // The strict pattern matches UUIDs like this: + // xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx + + // Roughly speaking: + // x = any hexadecimal character + // M = any allowed version {1..5} + // N = any allowed variant {9, 9, a, b} + + const STRICT_LENGTH = 36; + const STRICT_FIRST_HYPHEN_POSITION = 8; + const STRICT_LAST_HYPHEN_POSITION = 23; + const STRICT_VERSION_POSITION = 14; + const STRICT_VARIANT_POSITION = 19; + + // The loose pattern validates similar yet non-compliant UUIDs. + // Hyphens are completely optional. If present, they should only appear + // between every fourth character: + // xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx + // xxxxxxxxxxxx-xxxx-xxxx-xxxx-xxxx-xxxx + // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + + // The value can also be wrapped with characters like []{}: + // {xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx} + + // Neither the version nor the variant is validated by this pattern. + + const LOOSE_MAX_LENGTH = 39; + const LOOSE_FIRST_HYPHEN_POSITION = 4; + /** - * Regular expression which verifies allowed characters and the proper format. - * - * The strict pattern matches UUIDs like this: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx - * Roughly speaking: x = any hexadecimal character, M = any allowed version, N = any allowed variant. + * @deprecated Deprecated since Symfony 2.6, to be removed in 3.0 */ const STRICT_PATTERN = '/^[a-f0-9]{8}-[a-f0-9]{4}-[%s][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/i'; /** - * The loose pattern validates similar yet non-compliant UUIDs. - * - * Dashes are completely optional. If present, they should only appear between every fourth character. - * The value can also be wrapped with characters like []{} for backwards-compatibility with other systems. - * Neither the version nor the variant is validated by this pattern. + * @deprecated Deprecated since Symfony 2.6, to be removed in 3.0 */ const LOOSE_PATTERN = '/^[a-f0-9]{4}(?:-?[a-f0-9]{4}){7}$/i'; /** - * Properly-formatted UUIDs contain 32 hex digits, separated by 4 dashes. - * We can use this fact to avoid performing a preg_match on strings of other sizes. + * @deprecated Deprecated since Symfony 2.6, to be removed in 3.0 */ - const STRICT_UUID_LENGTH = 36; + const STRICT_UUID_LENGTH = self::STRICT_LENGTH; /** * {@inheritdoc} @@ -65,42 +86,178 @@ public function validate($value, Constraint $constraint) $value = (string) $value; if ($constraint->strict) { - $length = strlen($value); + $this->validateStrict($value, $constraint); + + return; + } + + $this->validateLoose($value, $constraint); + } + + private function validateLoose($value, Uuid $constraint) + { + // Error priority: + // 1. ERROR_INVALID_CHARACTERS + // 2. ERROR_INVALID_HYPHEN_PLACEMENT + // 3. ERROR_TOO_SHORT/ERROR_TOO_LONG + + // Trim any wrapping characters like [] or {} used by some legacy systems + $trimmed = trim($value, '[]{}'); + + // Position of the next expected hyphen + $h = self::LOOSE_FIRST_HYPHEN_POSITION; - if ($length < static::STRICT_UUID_LENGTH) { + // Expected length + $l = self::LOOSE_MAX_LENGTH; + + for ($i = 0; $i < $l; ++$i) { + // Check length + if (!isset($trimmed{$i})) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Uuid::TOO_SHORT_ERROR) ->addViolation(); return; } - if ($length > static::STRICT_UUID_LENGTH) { + // Hyphens must occur every fifth position + // xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx + // ^ ^ ^ ^ ^ ^ ^ + if ('-' === $trimmed{$i}) { + if ($i !== $h) { + $this->buildViolation($constraint->message) + ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Uuid::INVALID_HYPHEN_PLACEMENT_ERROR) + ->addViolation(); + + return; + } + + $h += 5; + + continue; + } + + // Missing hyphens are ignored + if ($i === $h) { + $h += 4; + --$l; + } + + // Check characters + if (!ctype_xdigit($trimmed{$i})) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Uuid::INVALID_CHARACTERS_ERROR) ->addViolation(); return; } + } + + // Check length again + if (isset($trimmed{$i})) { + $this->buildViolation($constraint->message) + ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Uuid::TOO_LONG_ERROR) + ->addViolation(); + } + } - // Insert the allowed versions into the regular expression - $pattern = sprintf(static::STRICT_PATTERN, implode('', $constraint->versions)); + private function validateStrict($value, Uuid $constraint) + { + // Error priority: + // 1. ERROR_INVALID_CHARACTERS + // 2. ERROR_INVALID_HYPHEN_PLACEMENT + // 3. ERROR_TOO_SHORT/ERROR_TOO_LONG + // 4. ERROR_INVALID_VERSION + // 5. ERROR_INVALID_VARIANT - if (!preg_match($pattern, $value)) { + // Position of the next expected hyphen + $h = self::STRICT_FIRST_HYPHEN_POSITION; + + for ($i = 0; $i < self::STRICT_LENGTH; ++$i) { + // Check length + if (!isset($value{$i})) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Uuid::TOO_SHORT_ERROR) ->addViolation(); + + return; } - return; + // Check hyphen placement + // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + // ^ ^ ^ ^ + if ('-' === $value{$i}) { + if ($i !== $h) { + $this->buildViolation($constraint->message) + ->setParameter( + '{{ value }}', + $this->formatValue($value) + ) + ->setCode(Uuid::INVALID_HYPHEN_PLACEMENT_ERROR) + ->addViolation(); + + return; + } + + // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + // ^ + if ($h < self::STRICT_LAST_HYPHEN_POSITION) { + $h += 5; + } + + continue; + } + + // Check characters + if (!ctype_xdigit($value{$i})) { + $this->buildViolation($constraint->message) + ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Uuid::INVALID_CHARACTERS_ERROR) + ->addViolation(); + + return; + } + + // Missing hyphen + if ($i === $h) { + $this->buildViolation($constraint->message) + ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Uuid::INVALID_HYPHEN_PLACEMENT_ERROR) + ->addViolation(); + + return; + } } - // Trim any wrapping characters like [] or {} used by some legacy systems - $value = trim($value, '[]{}'); + // Check length again + if (isset($value{$i})) { + $this->buildViolation($constraint->message) + ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Uuid::TOO_LONG_ERROR) + ->addViolation(); + } + + // Check version + if (!in_array($value{self::STRICT_VERSION_POSITION}, $constraint->versions)) { + $this->buildViolation($constraint->message) + ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Uuid::INVALID_VERSION_ERROR) + ->addViolation(); + } - if (!preg_match(static::LOOSE_PATTERN, $value)) { + // Check variant - first two bits must equal "10" + // 0b10xx + // & 0b1100 (12) + // = 0b1000 (8) + if ((hexdec($value{self::STRICT_VARIANT_POSITION}) & 12) !== 8) { $this->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Uuid::INVALID_VARIANT_ERROR) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Tests/ConstraintTest.php b/src/Symfony/Component/Validator/Tests/ConstraintTest.php index 61a96c1f5aec..f63570c5d294 100644 --- a/src/Symfony/Component/Validator/Tests/ConstraintTest.php +++ b/src/Symfony/Component/Validator/Tests/ConstraintTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Validator\Tests; +use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Tests\Fixtures\ClassConstraint; use Symfony\Component\Validator\Tests\Fixtures\ConstraintA; use Symfony\Component\Validator\Tests\Fixtures\ConstraintB; @@ -197,4 +198,12 @@ public function testSerializeKeepsCustomGroups() $this->assertSame(array('MyGroup'), $constraint->groups); } + + /** + * @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException + */ + public function testGetErrorNameForUnknownCode() + { + Constraint::getErrorName(1); + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php index 40bba756c21e..aab54e590f0d 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php @@ -54,7 +54,7 @@ public function testValidNumbers($scheme, $number) /** * @dataProvider getInvalidNumbers */ - public function testInvalidNumbers($scheme, $number) + public function testInvalidNumbers($scheme, $number, $code) { $constraint = new CardScheme(array( 'schemes' => $scheme, @@ -65,6 +65,7 @@ public function testInvalidNumbers($scheme, $number) $this->buildViolation('myMessage') ->setParameter('{{ value }}', is_string($number) ? '"'.$number.'"' : $number) + ->setCode($code) ->assertRaised(); } @@ -113,20 +114,20 @@ public function getValidNumbers() public function getInvalidNumbers() { return array( - array('VISA', '42424242424242424242'), - array('AMEX', '357298508610146'), - array('DINERS', '31569309025904'), - array('DINERS', '37088894118515'), - array('INSTAPAYMENT', '6313440808445746'), - array('CHINA_UNIONPAY', '622888888888888'), - array('CHINA_UNIONPAY', '62288888888888888888'), - array('AMEX', '30569309025904'), // DINERS number - array('AMEX', 'invalid'), // A string - array('AMEX', 0), // a lone number - array('AMEX', '0'), // a lone number - array('AMEX', '000000000000'), // a lone number - array('DINERS', '3056930'), // only first part of the number - array('DISCOVER', '1117'), // only last 4 digits + array('VISA', '42424242424242424242', CardScheme::INVALID_FORMAT_ERROR), + array('AMEX', '357298508610146', CardScheme::INVALID_FORMAT_ERROR), + array('DINERS', '31569309025904', CardScheme::INVALID_FORMAT_ERROR), + array('DINERS', '37088894118515', CardScheme::INVALID_FORMAT_ERROR), + array('INSTAPAYMENT', '6313440808445746', CardScheme::INVALID_FORMAT_ERROR), + array('CHINA_UNIONPAY', '622888888888888', CardScheme::INVALID_FORMAT_ERROR), + array('CHINA_UNIONPAY', '62288888888888888888', CardScheme::INVALID_FORMAT_ERROR), + array('AMEX', '30569309025904', CardScheme::INVALID_FORMAT_ERROR), // DINERS number + array('AMEX', 'invalid', CardScheme::NOT_NUMERIC_ERROR), // A string + array('AMEX', 0, CardScheme::INVALID_FORMAT_ERROR), // a lone number + array('AMEX', '0', CardScheme::INVALID_FORMAT_ERROR), // a lone number + array('AMEX', '000000000000', CardScheme::INVALID_FORMAT_ERROR), // a lone number + array('DINERS', '3056930', CardScheme::INVALID_FORMAT_ERROR), // only first part of the number + array('DISCOVER', '1117', CardScheme::INVALID_FORMAT_ERROR), // only last 4 digits ); } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/ChoiceValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/ChoiceValidatorTest.php index 84b5bc3b0d63..aa5b8945b2ee 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/ChoiceValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/ChoiceValidatorTest.php @@ -146,6 +146,7 @@ public function testInvalidChoice() $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"baz"') + ->setCode(Choice::NO_SUCH_CHOICE_ERROR) ->assertRaised(); } @@ -162,6 +163,7 @@ public function testInvalidChoiceMultiple() $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"baz"') ->setInvalidValue('baz') + ->setCode(Choice::NO_SUCH_CHOICE_ERROR) ->assertRaised(); } @@ -184,6 +186,7 @@ public function testTooFewChoices() ->setParameter('{{ limit }}', 2) ->setInvalidValue($value) ->setPlural(2) + ->setCode(Choice::TOO_FEW_ERROR) ->assertRaised(); } @@ -206,6 +209,7 @@ public function testTooManyChoices() ->setParameter('{{ limit }}', 2) ->setInvalidValue($value) ->setPlural(2) + ->setCode(Choice::TOO_MANY_ERROR) ->assertRaised(); } @@ -246,6 +250,7 @@ public function testStrictDisallowsDifferentType() $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"2"') + ->setCode(Choice::NO_SUCH_CHOICE_ERROR) ->assertRaised(); } @@ -276,6 +281,7 @@ public function testStrictWithMultipleChoices() $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"3"') ->setInvalidValue('3') + ->setCode(Choice::NO_SUCH_CHOICE_ERROR) ->assertRaised(); } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CollectionValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CollectionValidatorTest.php index fb80070a46d8..0376814341fb 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CollectionValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CollectionValidatorTest.php @@ -146,6 +146,7 @@ public function testExtraFieldsDisallowed() ->setParameter('{{ field }}', '"baz"') ->atPath('property.path[baz]') ->setInvalidValue(6) + ->setCode(Collection::NO_SUCH_FIELD_ERROR) ->assertRaised(); } @@ -207,6 +208,7 @@ public function testMissingFieldsDisallowed() ->setParameter('{{ field }}', '"foo"') ->atPath('property.path[foo]') ->setInvalidValue(null) + ->setCode(Collection::MISSING_FIELD_ERROR) ->assertRaised(); } @@ -319,6 +321,7 @@ public function testRequiredFieldNotPresent() ->setParameter('{{ field }}', '"foo"') ->atPath('property.path[foo]') ->setInvalidValue(null) + ->setCode(Collection::MISSING_FIELD_ERROR) ->assertRaised(); } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CountValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CountValidatorTest.php index 31c7c7856288..6713166ce461 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CountValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CountValidatorTest.php @@ -124,6 +124,7 @@ public function testTooManyValues($value) ->setParameter('{{ limit }}', 4) ->setInvalidValue($value) ->setPlural(4) + ->setCode(Count::TOO_MANY_ERROR) ->assertRaised(); } @@ -144,6 +145,7 @@ public function testTooFewValues($value) ->setParameter('{{ limit }}', 4) ->setInvalidValue($value) ->setPlural(4) + ->setCode(Count::TOO_FEW_ERROR) ->assertRaised(); } @@ -165,6 +167,7 @@ public function testTooManyValuesExact($value) ->setParameter('{{ limit }}', 4) ->setInvalidValue($value) ->setPlural(4) + ->setCode(Count::TOO_MANY_ERROR) ->assertRaised(); } @@ -186,6 +189,7 @@ public function testTooFewValuesExact($value) ->setParameter('{{ limit }}', 4) ->setInvalidValue($value) ->setPlural(4) + ->setCode(Count::TOO_FEW_ERROR) ->assertRaised(); } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/DateTimeValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/DateTimeValidatorTest.php index 89de5fd9a515..25d88aa2ab88 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/DateTimeValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/DateTimeValidatorTest.php @@ -78,7 +78,7 @@ public function getValidDateTimes() /** * @dataProvider getInvalidDateTimes */ - public function testInvalidDateTimes($dateTime) + public function testInvalidDateTimes($dateTime, $code) { $constraint = new DateTime(array( 'message' => 'myMessage', @@ -88,22 +88,23 @@ public function testInvalidDateTimes($dateTime) $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"'.$dateTime.'"') + ->setCode($code) ->assertRaised(); } public function getInvalidDateTimes() { return array( - array('foobar'), - array('2010-01-01'), - array('00:00:00'), - array('2010-01-01 00:00'), - array('2010-13-01 00:00:00'), - array('2010-04-32 00:00:00'), - array('2010-02-29 00:00:00'), - array('2010-01-01 24:00:00'), - array('2010-01-01 00:60:00'), - array('2010-01-01 00:00:60'), + array('foobar', DateTime::INVALID_FORMAT_ERROR), + array('2010-01-01', DateTime::INVALID_FORMAT_ERROR), + array('00:00:00', 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), + array('2010-02-29 00:00:00', DateTime::INVALID_DATE_ERROR), + array('2010-01-01 24:00:00', DateTime::INVALID_TIME_ERROR), + array('2010-01-01 00:60:00', DateTime::INVALID_TIME_ERROR), + array('2010-01-01 00:00:60', DateTime::INVALID_TIME_ERROR), ); } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/DateValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/DateValidatorTest.php index 352ded5422a5..21f0a2dcc3d6 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/DateValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/DateValidatorTest.php @@ -78,7 +78,7 @@ public function getValidDates() /** * @dataProvider getInvalidDates */ - public function testInvalidDates($date) + public function testInvalidDates($date, $code) { $constraint = new Date(array( 'message' => 'myMessage', @@ -88,18 +88,19 @@ public function testInvalidDates($date) $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"'.$date.'"') + ->setCode($code) ->assertRaised(); } public function getInvalidDates() { return array( - array('foobar'), - array('foobar 2010-13-01'), - array('2010-13-01 foobar'), - array('2010-13-01'), - array('2010-04-32'), - array('2010-02-29'), + array('foobar', Date::INVALID_FORMAT_ERROR), + array('foobar 2010-13-01', Date::INVALID_FORMAT_ERROR), + array('2010-13-01 foobar', Date::INVALID_FORMAT_ERROR), + array('2010-13-01', Date::INVALID_DATE_ERROR), + array('2010-04-32', Date::INVALID_DATE_ERROR), + array('2010-02-29', Date::INVALID_DATE_ERROR), ); } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php index fb39f8854052..0361333fdc16 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php @@ -81,6 +81,7 @@ public function testInvalidEmails($email) $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"'.$email.'"') + ->setCode(Email::INVALID_FORMAT_ERROR) ->assertRaised(); } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/FileValidatorPathTest.php b/src/Symfony/Component/Validator/Tests/Constraints/FileValidatorPathTest.php index 25def64c19c9..11b8d4cb7987 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/FileValidatorPathTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/FileValidatorPathTest.php @@ -30,6 +30,7 @@ public function testFileNotFound() $this->buildViolation('myMessage') ->setParameter('{{ file }}', '"foobar"') + ->setCode(File::NOT_FOUND_ERROR) ->assertRaised(); } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/FileValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/FileValidatorTest.php index 8ecdf321a82f..c66b6ca5a36b 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/FileValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/FileValidatorTest.php @@ -181,6 +181,7 @@ public function testMaxSizeExceeded($bytesWritten, $limit, $sizeAsString, $limit ->setParameter('{{ size }}', $sizeAsString) ->setParameter('{{ suffix }}', $suffix) ->setParameter('{{ file }}', '"'.$this->path.'"') + ->setCode(File::TOO_LARGE_ERROR) ->assertRaised(); } @@ -277,12 +278,13 @@ public function testBinaryFormat($bytesWritten, $limit, $binaryFormat, $sizeAsSt $this->validator->validate($this->getFile($this->path), $constraint); - $this->assertViolation('myMessage', array( - '{{ limit }}' => $limitAsString, - '{{ size }}' => $sizeAsString, - '{{ suffix }}' => $suffix, - '{{ file }}' => '"'.$this->path.'"', - )); + $this->buildViolation('myMessage') + ->setParameter('{{ limit }}', $limitAsString) + ->setParameter('{{ size }}', $sizeAsString) + ->setParameter('{{ suffix }}', $suffix) + ->setParameter('{{ file }}', '"'.$this->path.'"') + ->setCode(File::TOO_LARGE_ERROR) + ->assertRaised(); } public function testValidMimeType() @@ -359,6 +361,7 @@ public function testInvalidMimeType() ->setParameter('{{ type }}', '"application/pdf"') ->setParameter('{{ types }}', '"image/png", "image/jpg"') ->setParameter('{{ file }}', '"'.$this->path.'"') + ->setCode(File::INVALID_MIME_TYPE_ERROR) ->assertRaised(); } @@ -388,6 +391,7 @@ public function testInvalidWildcardMimeType() ->setParameter('{{ type }}', '"application/pdf"') ->setParameter('{{ types }}', '"image/*", "image/jpg"') ->setParameter('{{ file }}', '"'.$this->path.'"') + ->setCode(File::INVALID_MIME_TYPE_ERROR) ->assertRaised(); } @@ -401,7 +405,10 @@ public function testDisallowEmpty() $this->validator->validate($this->getFile($this->path), $constraint); - $this->assertViolation('myMessage'); + $this->buildViolation('myMessage') + ->setParameter('{{ file }}', '"'.$this->path.'"') + ->setCode(File::EMPTY_ERROR) + ->assertRaised(); } /** @@ -420,6 +427,7 @@ public function testUploadedFileError($error, $message, array $params = array(), $this->buildViolation('myMessage') ->setParameters($params) + ->setCode($error) ->assertRaised(); } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/IbanValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/IbanValidatorTest.php index d2ecf8f51b80..ab9839a23896 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/IbanValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/IbanValidatorTest.php @@ -156,7 +156,7 @@ public function getValidIbans() /** * @dataProvider getInvalidIbans */ - public function testInvalidIbans($iban) + public function testInvalidIbans($iban, $code) { $constraint = new Iban(array( 'message' => 'myMessage', @@ -166,27 +166,28 @@ public function testInvalidIbans($iban) $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"'.$iban.'"') + ->setCode($code) ->assertRaised(); } public function getInvalidIbans() { return array( - array('CH93 0076 2011 6238 5295'), - array('CH930076201162385295'), - array('GB29 RBOS 6016 1331 9268 19'), - array('CH930072011623852957'), - array('NL39 RASO 0300 0652 64'), - array('NO93 8601117 947'), - array('CY170020 128 0000 0012 0052 7600'), - array('foo'), - array('123'), - array('0750447346'), - array('CH930076201162385295]'), + array('CH93 0076 2011 6238 5295', Iban::CHECKSUM_FAILED_ERROR), + array('CH930076201162385295', Iban::CHECKSUM_FAILED_ERROR), + array('GB29 RBOS 6016 1331 9268 19', Iban::CHECKSUM_FAILED_ERROR), + array('CH930072011623852957', Iban::CHECKSUM_FAILED_ERROR), + array('NL39 RASO 0300 0652 64', Iban::CHECKSUM_FAILED_ERROR), + array('NO93 8601117 947', Iban::CHECKSUM_FAILED_ERROR), + array('CY170020 128 0000 0012 0052 7600', Iban::CHECKSUM_FAILED_ERROR), + array('foo', Iban::TOO_SHORT_ERROR), + array('123', Iban::TOO_SHORT_ERROR), + array('0750447346', Iban::INVALID_COUNTRY_CODE_ERROR), + array('CH930076201162385295]', Iban::INVALID_CHARACTERS_ERROR), //Ibans with lower case values are invalid - array('Ae260211000000230064016'), - array('ae260211000000230064016'), + array('Ae260211000000230064016', Iban::INVALID_CASE_ERROR), + array('ae260211000000230064016', Iban::INVALID_CASE_ERROR), ); } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php index 5d6c9a91ff4d..18f9c1bc0673 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php @@ -71,6 +71,21 @@ public function testValidImage() $this->assertNoViolation(); } + public function testFileNotFound() + { + // Check that the logic from FileValidator still works + $constraint = new Image(array( + 'notFoundMessage' => 'myMessage', + )); + + $this->validator->validate('foobar', $constraint); + + $this->buildViolation('myMessage') + ->setParameter('{{ file }}', '"foobar"') + ->setCode(Image::NOT_FOUND_ERROR) + ->assertRaised(); + } + public function testValidSize() { $constraint = new Image(array( @@ -97,6 +112,7 @@ public function testWidthTooSmall() $this->buildViolation('myMessage') ->setParameter('{{ width }}', '2') ->setParameter('{{ min_width }}', '3') + ->setCode(Image::TOO_NARROW_ERROR) ->assertRaised(); } @@ -112,6 +128,7 @@ public function testWidthTooBig() $this->buildViolation('myMessage') ->setParameter('{{ width }}', '2') ->setParameter('{{ max_width }}', '1') + ->setCode(Image::TOO_WIDE_ERROR) ->assertRaised(); } @@ -127,6 +144,7 @@ public function testHeightTooSmall() $this->buildViolation('myMessage') ->setParameter('{{ height }}', '2') ->setParameter('{{ min_height }}', '3') + ->setCode(Image::TOO_LOW_ERROR) ->assertRaised(); } @@ -142,6 +160,7 @@ public function testHeightTooBig() $this->buildViolation('myMessage') ->setParameter('{{ height }}', '2') ->setParameter('{{ max_height }}', '1') + ->setCode(Image::TOO_HIGH_ERROR) ->assertRaised(); } @@ -205,6 +224,7 @@ public function testRatioTooSmall() $this->buildViolation('myMessage') ->setParameter('{{ ratio }}', 1) ->setParameter('{{ min_ratio }}', 2) + ->setCode(Image::RATIO_TOO_SMALL_ERROR) ->assertRaised(); } @@ -220,6 +240,7 @@ public function testRatioTooBig() $this->buildViolation('myMessage') ->setParameter('{{ ratio }}', 1) ->setParameter('{{ max_ratio }}', 0.5) + ->setCode(Image::RATIO_TOO_BIG_ERROR) ->assertRaised(); } @@ -270,6 +291,7 @@ public function testSquareNotAllowed() $this->buildViolation('myMessage') ->setParameter('{{ width }}', 2) ->setParameter('{{ height }}', 2) + ->setCode(Image::SQUARE_NOT_ALLOWED_ERROR) ->assertRaised(); } @@ -285,6 +307,7 @@ public function testLandscapeNotAllowed() $this->buildViolation('myMessage') ->setParameter('{{ width }}', 2) ->setParameter('{{ height }}', 1) + ->setCode(Image::LANDSCAPE_NOT_ALLOWED_ERROR) ->assertRaised(); } @@ -300,6 +323,7 @@ public function testPortraitNotAllowed() $this->buildViolation('myMessage') ->setParameter('{{ width }}', 1) ->setParameter('{{ height }}', 2) + ->setCode(Image::PORTRAIT_NOT_ALLOWED_ERROR) ->assertRaised(); } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/IsbnValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/IsbnValidatorTest.php index 296ab7c94a3a..e73b89d60bab 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/IsbnValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/IsbnValidatorTest.php @@ -52,20 +52,20 @@ public function getValidIsbn10() public function getInvalidIsbn10() { return array( - array('27234422841'), - array('272344228'), - array('0-4712-9231'), - array('1234567890'), - array('0987656789'), - array('7-35622-5444'), - array('0-4X19-92611'), - array('0_45122_5244'), - array('2870#971#648'), - array('0-9752298-0-x'), - array('1A34567890'), + array('27234422841', Isbn::TOO_LONG_ERROR), + array('272344228', Isbn::TOO_SHORT_ERROR), + array('0-4712-9231', Isbn::TOO_SHORT_ERROR), + array('1234567890', Isbn::CHECKSUM_FAILED_ERROR), + array('0987656789', Isbn::CHECKSUM_FAILED_ERROR), + array('7-35622-5444', Isbn::CHECKSUM_FAILED_ERROR), + array('0-4X19-92611', Isbn::CHECKSUM_FAILED_ERROR), + array('0_45122_5244', Isbn::INVALID_CHARACTERS_ERROR), + array('2870#971#648', Isbn::INVALID_CHARACTERS_ERROR), + array('0-9752298-0-x', Isbn::INVALID_CHARACTERS_ERROR), + array('1A34567890', Isbn::INVALID_CHARACTERS_ERROR), // chr(1) evaluates to 0 // 2070546810 is valid - array('2'.chr(1).'70546810'), + array('2'.chr(1).'70546810', Isbn::INVALID_CHARACTERS_ERROR), ); } @@ -90,20 +90,20 @@ public function getValidIsbn13() public function getInvalidIsbn13() { return array( - array('978-27234422821'), - array('978-272344228'), - array('978-2723442-82'), - array('978-2723442281'), - array('978-0321513774'), - array('979-0431225385'), - array('980-0474292319'), - array('0-4X19-92619812'), - array('978_2723442282'), - array('978#2723442282'), - array('978-272C442282'), + array('978-27234422821', Isbn::TOO_LONG_ERROR), + array('978-272344228', Isbn::TOO_SHORT_ERROR), + array('978-2723442-82', Isbn::TOO_SHORT_ERROR), + array('978-2723442281', Isbn::CHECKSUM_FAILED_ERROR), + array('978-0321513774', Isbn::CHECKSUM_FAILED_ERROR), + array('979-0431225385', Isbn::CHECKSUM_FAILED_ERROR), + array('980-0474292319', Isbn::CHECKSUM_FAILED_ERROR), + array('0-4X19-92619812', Isbn::INVALID_CHARACTERS_ERROR), + array('978_2723442282', Isbn::INVALID_CHARACTERS_ERROR), + array('978#2723442282', Isbn::INVALID_CHARACTERS_ERROR), + array('978-272C442282', Isbn::INVALID_CHARACTERS_ERROR), // chr(1) evaluates to 0 // 978-2070546817 is valid - array('978-2'.chr(1).'70546817'), + array('978-2'.chr(1).'70546817', Isbn::INVALID_CHARACTERS_ERROR), ); } @@ -168,7 +168,7 @@ public function testValidIsbn10($isbn) /** * @dataProvider getInvalidIsbn10 */ - public function testInvalidIsbn10($isbn) + public function testInvalidIsbn10($isbn, $code) { $constraint = new Isbn(array( 'type' => 'isbn10', @@ -179,6 +179,7 @@ public function testInvalidIsbn10($isbn) $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"'.$isbn.'"') + ->setCode($code) ->assertRaised(); } @@ -197,7 +198,7 @@ public function testValidIsbn13($isbn) /** * @dataProvider getInvalidIsbn13 */ - public function testInvalidIsbn13($isbn) + public function testInvalidIsbn13($isbn, $code) { $constraint = new Isbn(array( 'type' => 'isbn13', @@ -208,6 +209,7 @@ public function testInvalidIsbn13($isbn) $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"'.$isbn.'"') + ->setCode($code) ->assertRaised(); } @@ -226,7 +228,7 @@ public function testValidIsbnAny($isbn) /** * @dataProvider getInvalidIsbn10 */ - public function testInvalidIsbnAnyIsbn10($isbn) + public function testInvalidIsbnAnyIsbn10($isbn, $code) { $constraint = new Isbn(array( 'bothIsbnMessage' => 'myMessage', @@ -234,15 +236,21 @@ public function testInvalidIsbnAnyIsbn10($isbn) $this->validator->validate($isbn, $constraint); + // Too long for an ISBN-10, but not long enough for an ISBN-13 + if (Isbn::TOO_LONG_ERROR === $code) { + $code = Isbn::TYPE_NOT_RECOGNIZED_ERROR; + } + $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"'.$isbn.'"') + ->setCode($code) ->assertRaised(); } /** * @dataProvider getInvalidIsbn13 */ - public function testInvalidIsbnAnyIsbn13($isbn) + public function testInvalidIsbnAnyIsbn13($isbn, $code) { $constraint = new Isbn(array( 'bothIsbnMessage' => 'myMessage', @@ -250,8 +258,14 @@ public function testInvalidIsbnAnyIsbn13($isbn) $this->validator->validate($isbn, $constraint); + // Too short for an ISBN-13, but not short enough for an ISBN-10 + if (Isbn::TOO_SHORT_ERROR === $code) { + $code = Isbn::TYPE_NOT_RECOGNIZED_ERROR; + } + $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"'.$isbn.'"') + ->setCode($code) ->assertRaised(); } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/IssnValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/IssnValidatorTest.php index cb7ae3d8925d..a6d39944b0ac 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/IssnValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/IssnValidatorTest.php @@ -82,14 +82,14 @@ public function getValidIssn() public function getInvalidIssn() { return array( - array(0), - array('1539'), - array('2156-537A'), - array('1119-0231'), - array('1684-5312'), - array('1996-0783'), - array('1684-537X'), - array('1996-0795'), + array(0, Issn::TOO_SHORT_ERROR), + array('1539', Issn::TOO_SHORT_ERROR), + array('2156-537A', Issn::INVALID_CHARACTERS_ERROR), + array('1119-0231', Issn::CHECKSUM_FAILED_ERROR), + array('1684-5312', Issn::CHECKSUM_FAILED_ERROR), + array('1996-0783', Issn::CHECKSUM_FAILED_ERROR), + array('1684-537X', Issn::CHECKSUM_FAILED_ERROR), + array('1996-0795', Issn::CHECKSUM_FAILED_ERROR), ); } @@ -134,6 +134,7 @@ public function testCaseSensitiveIssns($issn) $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"'.$issn.'"') + ->setCode(Issn::INVALID_CASE_ERROR) ->assertRaised(); } @@ -151,6 +152,7 @@ public function testRequireHyphenIssns($issn) $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"'.$issn.'"') + ->setCode(Issn::MISSING_HYPHEN_ERROR) ->assertRaised(); } @@ -169,7 +171,7 @@ public function testValidIssn($issn) /** * @dataProvider getInvalidIssn */ - public function testInvalidIssn($issn) + public function testInvalidIssn($issn, $code) { $constraint = new Issn(array( 'message' => 'myMessage', @@ -179,6 +181,7 @@ public function testInvalidIssn($issn) $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"'.$issn.'"') + ->setCode($code) ->assertRaised(); } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/LengthValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/LengthValidatorTest.php index 7674ae24272e..ae27ff25cb45 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/LengthValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/LengthValidatorTest.php @@ -153,6 +153,7 @@ public function testInvalidValuesMin($value, $mbOnly = false) ->setParameter('{{ limit }}', 4) ->setInvalidValue($value) ->setPlural(4) + ->setCode(Length::TOO_SHORT_ERROR) ->assertRaised(); } @@ -177,6 +178,7 @@ public function testInvalidValuesMax($value, $mbOnly = false) ->setParameter('{{ limit }}', 4) ->setInvalidValue($value) ->setPlural(4) + ->setCode(Length::TOO_LONG_ERROR) ->assertRaised(); } @@ -202,6 +204,7 @@ public function testInvalidValuesExactLessThanFour($value, $mbOnly = false) ->setParameter('{{ limit }}', 4) ->setInvalidValue($value) ->setPlural(4) + ->setCode(Length::TOO_SHORT_ERROR) ->assertRaised(); } @@ -227,6 +230,7 @@ public function testInvalidValuesExactMoreThanFour($value, $mbOnly = false) ->setParameter('{{ limit }}', 4) ->setInvalidValue($value) ->setPlural(4) + ->setCode(Length::TOO_LONG_ERROR) ->assertRaised(); } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/LuhnValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/LuhnValidatorTest.php index 4ad3c736eb09..b0e88c3456b0 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/LuhnValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/LuhnValidatorTest.php @@ -78,7 +78,7 @@ public function getValidNumbers() /** * @dataProvider getInvalidNumbers */ - public function testInvalidNumbers($number) + public function testInvalidNumbers($number, $code) { $constraint = new Luhn(array( 'message' => 'myMessage', @@ -88,17 +88,18 @@ public function testInvalidNumbers($number) $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"'.$number.'"') + ->setCode($code) ->assertRaised(); } public function getInvalidNumbers() { return array( - array('1234567812345678'), - array('4222222222222222'), - array('0000000000000000'), - array('000000!000000000'), - array('42-22222222222222'), + array('1234567812345678', Luhn::CHECKSUM_FAILED_ERROR), + array('4222222222222222', Luhn::CHECKSUM_FAILED_ERROR), + array('0000000000000000', Luhn::CHECKSUM_FAILED_ERROR), + array('000000!000000000', Luhn::INVALID_CHARACTERS_ERROR), + array('42-22222222222222', Luhn::INVALID_CHARACTERS_ERROR), ); } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/RangeValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/RangeValidatorTest.php index 0b6055998422..3bfb405e0720 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/RangeValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/RangeValidatorTest.php @@ -117,6 +117,7 @@ public function testInvalidValuesMin($value) $this->buildViolation('myMessage') ->setParameter('{{ value }}', $value) ->setParameter('{{ limit }}', 10) + ->setCode(Range::BELOW_RANGE_ERROR) ->assertRaised(); } @@ -135,6 +136,7 @@ public function testInvalidValuesMax($value) $this->buildViolation('myMessage') ->setParameter('{{ value }}', $value) ->setParameter('{{ limit }}', 20) + ->setCode(Range::BEYOND_RANGE_ERROR) ->assertRaised(); } @@ -155,6 +157,7 @@ public function testInvalidValuesCombinedMax($value) $this->buildViolation('myMaxMessage') ->setParameter('{{ value }}', $value) ->setParameter('{{ limit }}', 20) + ->setCode(Range::BEYOND_RANGE_ERROR) ->assertRaised(); } @@ -175,6 +178,7 @@ public function testInvalidValuesCombinedMin($value) $this->buildViolation('myMinMessage') ->setParameter('{{ value }}', $value) ->setParameter('{{ limit }}', 10) + ->setCode(Range::BELOW_RANGE_ERROR) ->assertRaised(); } @@ -292,10 +296,11 @@ public function testInvalidDatesMin($value) $this->validator->validate($value, $constraint); - $this->assertViolation('myMessage', array( - '{{ value }}' => $value, - '{{ limit }}' => 'Mar 10, 2014, 12:00 AM', - )); + $this->buildViolation('myMessage') + ->setParameter('{{ value }}', $value) + ->setParameter('{{ limit }}', 'Mar 10, 2014, 12:00 AM') + ->setCode(Range::BELOW_RANGE_ERROR) + ->assertRaised(); } /** @@ -314,10 +319,11 @@ public function testInvalidDatesMax($value) $this->validator->validate($value, $constraint); - $this->assertViolation('myMessage', array( - '{{ value }}' => $value, - '{{ limit }}' => 'Mar 20, 2014, 12:00 AM', - )); + $this->buildViolation('myMessage') + ->setParameter('{{ value }}', $value) + ->setParameter('{{ limit }}', 'Mar 20, 2014, 12:00 AM') + ->setCode(Range::BEYOND_RANGE_ERROR) + ->assertRaised(); } /** @@ -338,10 +344,11 @@ public function testInvalidDatesCombinedMax($value) $this->validator->validate($value, $constraint); - $this->assertViolation('myMaxMessage', array( - '{{ value }}' => $value, - '{{ limit }}' => 'Mar 20, 2014, 12:00 AM', - )); + $this->buildViolation('myMaxMessage') + ->setParameter('{{ value }}', $value) + ->setParameter('{{ limit }}', 'Mar 20, 2014, 12:00 AM') + ->setCode(Range::BEYOND_RANGE_ERROR) + ->assertRaised(); } /** @@ -362,10 +369,11 @@ public function testInvalidDatesCombinedMin($value) $this->validator->validate($value, $constraint); - $this->assertViolation('myMinMessage', array( - '{{ value }}' => $value, - '{{ limit }}' => 'Mar 10, 2014, 12:00 AM', - )); + $this->buildViolation('myMinMessage') + ->setParameter('{{ value }}', $value) + ->setParameter('{{ limit }}', 'Mar 10, 2014, 12:00 AM') + ->setCode(Range::BELOW_RANGE_ERROR) + ->assertRaised(); } public function getInvalidValues() @@ -389,6 +397,7 @@ public function testNonNumeric() $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"abcd"') + ->setCode(Range::INVALID_VALUE_ERROR) ->assertRaised(); } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/TimeValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/TimeValidatorTest.php index 23aed04c0f33..a6ca1435ed33 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/TimeValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/TimeValidatorTest.php @@ -78,7 +78,7 @@ public function getValidTimes() /** * @dataProvider getInvalidTimes */ - public function testInvalidTimes($time) + public function testInvalidTimes($time, $code) { $constraint = new Time(array( 'message' => 'myMessage', @@ -88,19 +88,20 @@ public function testInvalidTimes($time) $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"'.$time.'"') + ->setCode($code) ->assertRaised(); } public function getInvalidTimes() { return array( - array('foobar'), - array('foobar 12:34:56'), - array('12:34:56 foobar'), - array('00:00'), - array('24:00:00'), - array('00:60:00'), - array('00:00:60'), + array('foobar', Time::INVALID_FORMAT_ERROR), + array('foobar 12:34:56', Time::INVALID_FORMAT_ERROR), + array('12:34:56 foobar', Time::INVALID_FORMAT_ERROR), + array('00:00', Time::INVALID_FORMAT_ERROR), + array('24:00:00', Time::INVALID_TIME_ERROR), + array('00:60:00', Time::INVALID_TIME_ERROR), + array('00:00:60', Time::INVALID_TIME_ERROR), ); } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UuidValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UuidValidatorTest.php index b34ce8138b70..0abda39f0294 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UuidValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UuidValidatorTest.php @@ -55,9 +55,15 @@ public function testExpectsStringCompatibleType() /** * @dataProvider getValidStrictUuids */ - public function testValidStrictUuids($uuid) + public function testValidStrictUuids($uuid, $versions = null) { - $this->validator->validate($uuid, new Uuid()); + $constraint = new Uuid(); + + if (null !== $versions) { + $constraint->versions = $versions; + } + + $this->validator->validate($uuid, $constraint); $this->assertNoViolation(); } @@ -66,75 +72,81 @@ public function getValidStrictUuids() { return array( array('216fff40-98d9-11e3-a5e2-0800200c9a66'), // Version 1 UUID in lowercase + array('216fff40-98d9-11e3-a5e2-0800200c9a66', array(Uuid::V1_MAC)), array('216FFF40-98D9-11E3-A5E2-0800200C9A66'), // Version 1 UUID in UPPERCASE array('456daefb-5aa6-41b5-8dbc-068b05a8b201'), // Version 4 UUID in lowercase - array('456DAEFb-5AA6-41B5-8DBC-068B05A8B201'), // Version 4 UUID in UPPERCASE + array('456daEFb-5AA6-41B5-8DBC-068B05A8B201'), // Version 4 UUID in mixed case + array('456daEFb-5AA6-41B5-8DBC-068B05A8B201', array(Uuid::V4_RANDOM)), ); } /** * @dataProvider getInvalidStrictUuids */ - public function testInvalidStrictUuids($uuid) + public function testInvalidStrictUuids($uuid, $code, $versions = null) { $constraint = new Uuid(array( 'message' => 'testMessage', )); + if (null !== $versions) { + $constraint->versions = $versions; + } + $this->validator->validate($uuid, $constraint); $this->buildViolation('testMessage') ->setParameter('{{ value }}', '"'.$uuid.'"') + ->setCode($code) ->assertRaised(); } public function getInvalidStrictUuids() { return array( - array('216fff40-98d9-11e3-a5e2-0800200c9a6'), // Too few characters - array('216fff40-98d9-11e3-a5e2-0800200c9a666'), // Too many characters - array('V16fff40-98d9-11e3-a5e2-0800200c9a66'), // Invalid character 'V' - array('2-16fff-4098d-911e3a5e20-800-200c9-a66'), // Non-standard dash positions (randomly placed) - - // Non-standard UUIDs allowed by some other systems - array('216f-ff40-98d9-11e3-a5e2-0800-200c-9a66'), // Non-standard dash positions (every 4 chars) - array('216fff40-98d911e3-a5e20800-200c9a66'), // Non-standard dash positions (every 8 chars) - array('216fff4098d911e3a5e20800200c9a66'), // No dashes at all - array('{216fff40-98d9-11e3-a5e2-0800200c9a66}'), // Wrapped with curly braces + array('216fff40-98d9-11e3-a5e2_0800200c9a66', Uuid::INVALID_CHARACTERS_ERROR), + array('216gff40-98d9-11e3-a5e2-0800200c9a66', Uuid::INVALID_CHARACTERS_ERROR), + array('216Gff40-98d9-11e3-a5e2-0800200c9a66', Uuid::INVALID_CHARACTERS_ERROR), + array('216fff40-98d9-11e3-a5e-20800200c9a66', Uuid::INVALID_HYPHEN_PLACEMENT_ERROR), + array('216f-ff40-98d9-11e3-a5e2-0800200c9a66', Uuid::INVALID_HYPHEN_PLACEMENT_ERROR), + array('216fff40-98d9-11e3-a5e2-0800-200c9a66', Uuid::INVALID_HYPHEN_PLACEMENT_ERROR), + array('216fff40-98d9-11e3-a5e2-0800200c-9a66', Uuid::INVALID_HYPHEN_PLACEMENT_ERROR), + array('216fff40-98d9-11e3-a5e20800200c9a66', Uuid::INVALID_HYPHEN_PLACEMENT_ERROR), + array('216fff4098d911e3a5e20800200c9a66', Uuid::INVALID_HYPHEN_PLACEMENT_ERROR), + array('216fff40-98d9-11e3-a5e2-0800200c9a6', Uuid::TOO_SHORT_ERROR), + array('216fff40-98d9-11e3-a5e2-0800200c9a666', Uuid::TOO_LONG_ERROR), + array('216fff40-98d9-01e3-a5e2-0800200c9a66', Uuid::INVALID_VERSION_ERROR), + array('216fff40-98d9-61e3-a5e2-0800200c9a66', Uuid::INVALID_VERSION_ERROR), + array('216fff40-98d9-71e3-a5e2-0800200c9a66', Uuid::INVALID_VERSION_ERROR), + array('216fff40-98d9-81e3-a5e2-0800200c9a66', Uuid::INVALID_VERSION_ERROR), + array('216fff40-98d9-91e3-a5e2-0800200c9a66', Uuid::INVALID_VERSION_ERROR), + array('216fff40-98d9-a1e3-a5e2-0800200c9a66', Uuid::INVALID_VERSION_ERROR), + array('216fff40-98d9-b1e3-a5e2-0800200c9a66', Uuid::INVALID_VERSION_ERROR), + array('216fff40-98d9-c1e3-a5e2-0800200c9a66', Uuid::INVALID_VERSION_ERROR), + array('216fff40-98d9-d1e3-a5e2-0800200c9a66', Uuid::INVALID_VERSION_ERROR), + array('216fff40-98d9-e1e3-a5e2-0800200c9a66', Uuid::INVALID_VERSION_ERROR), + array('216fff40-98d9-f1e3-a5e2-0800200c9a66', Uuid::INVALID_VERSION_ERROR), + array('216fff40-98d9-11e3-a5e2-0800200c9a66', Uuid::INVALID_VERSION_ERROR, array(Uuid::V2_DCE, Uuid::V3_MD5, Uuid::V4_RANDOM, Uuid::V5_SHA1)), + array('216fff40-98d9-21e3-a5e2-0800200c9a66', Uuid::INVALID_VERSION_ERROR, array(Uuid::V1_MAC, Uuid::V3_MD5, Uuid::V4_RANDOM, Uuid::V5_SHA1)), + array('216fff40-98d9-11e3-05e2-0800200c9a66', Uuid::INVALID_VARIANT_ERROR), + array('216fff40-98d9-11e3-15e2-0800200c9a66', Uuid::INVALID_VARIANT_ERROR), + array('216fff40-98d9-11e3-25e2-0800200c9a66', Uuid::INVALID_VARIANT_ERROR), + array('216fff40-98d9-11e3-35e2-0800200c9a66', Uuid::INVALID_VARIANT_ERROR), + array('216fff40-98d9-11e3-45e2-0800200c9a66', Uuid::INVALID_VARIANT_ERROR), + array('216fff40-98d9-11e3-55e2-0800200c9a66', Uuid::INVALID_VARIANT_ERROR), + array('216fff40-98d9-11e3-65e2-0800200c9a66', Uuid::INVALID_VARIANT_ERROR), + array('216fff40-98d9-11e3-75e2-0800200c9a66', Uuid::INVALID_VARIANT_ERROR), + array('216fff40-98d9-11e3-c5e2-0800200c9a66', Uuid::INVALID_VARIANT_ERROR), + array('216fff40-98d9-11e3-d5e2-0800200c9a66', Uuid::INVALID_VARIANT_ERROR), + array('216fff40-98d9-11e3-e5e2-0800200c9a66', Uuid::INVALID_VARIANT_ERROR), + array('216fff40-98d9-11e3-f5e2-0800200c9a66', Uuid::INVALID_VARIANT_ERROR), + + // Non-standard UUID allowed by some other systems + array('{216fff40-98d9-11e3-a5e2-0800200c9a66}', Uuid::INVALID_CHARACTERS_ERROR), + array('[216fff40-98d9-11e3-a5e2-0800200c9a66]', Uuid::INVALID_CHARACTERS_ERROR), ); } - /** - * @dataProvider getValidStrictUuids - */ - public function testVersionConstraintIsValid($uuid) - { - $constraint = new Uuid(array( - 'versions' => array(Uuid::V1_MAC, Uuid::V4_RANDOM), - )); - - $this->validator->validate($uuid, $constraint); - - $this->assertNoViolation(); - } - - /** - * @dataProvider getValidStrictUuids - */ - public function testVersionConstraintIsInvalid($uuid) - { - $constraint = new Uuid(array( - 'versions' => array(Uuid::V2_DCE, Uuid::V3_MD5), - 'message' => 'myMessage', - )); - - $this->validator->validate($uuid, $constraint); - - $this->buildViolation('myMessage') - ->setParameter('{{ value }}', '"'.$uuid.'"') - ->assertRaised(); - } - /** * @dataProvider getValidNonStrictUuids */ @@ -155,20 +167,21 @@ public function getValidNonStrictUuids() array('216fff40-98d9-11e3-a5e2-0800200c9a66'), // Version 1 UUID in lowercase array('216FFF40-98D9-11E3-A5E2-0800200C9A66'), // Version 1 UUID in UPPERCASE array('456daefb-5aa6-41b5-8dbc-068b05a8b201'), // Version 4 UUID in lowercase - array('456DAEFb-5AA6-41B5-8DBC-068B05A8B201'), // Version 4 UUID in UPPERCASE + array('456DAEFb-5AA6-41B5-8DBC-068b05a8B201'), // Version 4 UUID in mixed case // Non-standard UUIDs allowed by some other systems array('216f-ff40-98d9-11e3-a5e2-0800-200c-9a66'), // Non-standard dash positions (every 4 chars) array('216fff40-98d911e3-a5e20800-200c9a66'), // Non-standard dash positions (every 8 chars) array('216fff4098d911e3a5e20800200c9a66'), // No dashes at all array('{216fff40-98d9-11e3-a5e2-0800200c9a66}'), // Wrapped with curly braces + array('[216fff40-98d9-11e3-a5e2-0800200c9a66]'), // Wrapped with squared braces ); } /** * @dataProvider getInvalidNonStrictUuids */ - public function testInvalidNonStrictUuids($uuid) + public function testInvalidNonStrictUuids($uuid, $code) { $constraint = new Uuid(array( 'strict' => false, @@ -179,16 +192,20 @@ public function testInvalidNonStrictUuids($uuid) $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"'.$uuid.'"') + ->setCode($code) ->assertRaised(); } public function getInvalidNonStrictUuids() { return array( - array('216fff40-98d9-11e3-a5e2-0800200c9a6'), // Too few characters - array('216fff40-98d9-11e3-a5e2-0800200c9a666'), // Too many characters - array('V16fff40-98d9-11e3-a5e2-0800200c9a66'), // Invalid character 'V' - array('2-16fff-4098d-911e3a5e20-800-200c9-a66'), // Non-standard dash positions (randomly placed) + array('216fff40-98d9-11e3-a5e2_0800200c9a66', Uuid::INVALID_CHARACTERS_ERROR), + array('216gff40-98d9-11e3-a5e2-0800200c9a66', Uuid::INVALID_CHARACTERS_ERROR), + array('216Gff40-98d9-11e3-a5e2-0800200c9a66', Uuid::INVALID_CHARACTERS_ERROR), + array('216fff40-98d9-11e3-a5e2_0800200c9a6', Uuid::INVALID_CHARACTERS_ERROR), + array('216fff40-98d9-11e3-a5e-20800200c9a66', Uuid::INVALID_HYPHEN_PLACEMENT_ERROR), + array('216fff40-98d9-11e3-a5e2-0800200c9a6', Uuid::TOO_SHORT_ERROR), + array('216fff40-98d9-11e3-a5e2-0800200c9a666', Uuid::TOO_LONG_ERROR), ); } } diff --git a/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php b/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php index eed7e2cb5c3e..c214b9c07bc5 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php @@ -574,7 +574,7 @@ public function testAddCustomizedViolation() ->setParameter('%param%', 'value') ->setInvalidValue('Invalid value') ->setPlural(2) - ->setCode('Code') + ->setCode(42) ->addViolation(); }; @@ -591,7 +591,7 @@ public function testAddCustomizedViolation() $this->assertSame($entity, $violations[0]->getRoot()); $this->assertSame('Invalid value', $violations[0]->getInvalidValue()); $this->assertSame(2, $violations[0]->getMessagePluralization()); - $this->assertSame('Code', $violations[0]->getCode()); + $this->assertSame(42, $violations[0]->getCode()); } /** diff --git a/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilderInterface.php b/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilderInterface.php index 9cb3fdb7e6ef..5998cbe529d1 100644 --- a/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilderInterface.php +++ b/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilderInterface.php @@ -93,11 +93,9 @@ public function setPlural($number); /** * Sets the violation code. * - * @param mixed $code The violation code + * @param int $code The violation code * * @return ConstraintViolationBuilderInterface This builder - * - * @internal This method is internal and should not be used by user code */ public function setCode($code);