8000 feature #12021 [Validator] Added error codes to all constraints with … · symfony/symfony@95d68a1 · GitHub
[go: up one dir, main page]

Skip to content

Commit 95d68a1

Browse files
committed
feature #12021 [Validator] Added error codes to all constraints with multiple error causes (webmozart)
This PR was merged into the 2.6-dev branch. Discussion ---------- [Validator] Added error codes to all constraints with multiple error causes | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #7276 | License | MIT | Doc PR | TODO This PR depends on #12015 and #12016 being merged first. However, a few changes in 52cb7df first must be backported to #12016. This PR introduces error codes for all constraints with multiple error paths. This lets you determine what exactly the reason was that a constraint failed: ```php $validator = Validation::createValidator(); $violations = $validator->validate('0-4X19-92619812', new Isbn()); foreach ($violations as $violation) { var_dump($violation->getCode()); // => int(3) var_dump(Isbn::getErrorName($violation->getCode())); // => string(24) "ERROR_INVALID_CHARACTERS" var_dump($violation->getConstraint()->getErrorName($violation->getCode())); // => string(24) "ERROR_INVALID_CHARACTERS" } ``` The `getErrorName()` method is especially helpful for REST APIs, where you can return both an error code and a description of that error now. **Todos** - [x] Backport a few structural changes to #12016 - [x] Update constraints outside of the Validator component - [x] Rebase on master (after merging #12015 and #12016) Commits ------- 3b50bf2 [Validator] Added error codes to all constraints with multiple error causes
2 parents 2f3bb66 + 3b50bf2 commit 95d68a1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+845
-224
lines changed

src/Symfony/Component/Form/Extension/Validator/Constraints/Form.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,20 @@
1818
*/
1919
class Form extends Constraint
2020
{
21+
const NOT_SYNCHRONIZED_ERROR = 1;
22+
const NO_SUCH_FIELD_ERROR = 2;
23+
2124
/**
22-
* Violation code marking an invalid form.
25+
* @deprecated Deprecated since Symfony 2.6, to be removed in 3.0. Use
26+
* {@self NOT_SYNCHRONIZED_ERROR} instead.
2327
*/
2428
const ERR_INVALID = 1;
2529

30+
protected static $errorNames = array(
31+
self::NOT_SYNCHRONIZED_ERROR => 'NOT_SYNCHRONIZED_ERROR',
32+
self::NO_SUCH_FIELD_ERROR => 'NO_SUCH_FIELD_ERROR',
33+
);
34+
2635
/**
2736
* {@inheritdoc}
2837
*/

src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public function validate($form, Constraint $constraint)
102102
$this->buildViolation($config->getOption('invalid_message'))
103103
->setParameters(array_replace(array('{{ value }}' => $clientDataAsString), $config->getOption('invalid_message_parameters')))
104104
->setInvalidValue($form->getViewData())
105-
->setCode(Form::ERR_INVALID)
105+
->setCode(Form::NOT_SYNCHRONIZED_ERROR)
106106
->setCause($form->getTransformationFailure())
107107
->addViolation();
108108
}
@@ -113,6 +113,7 @@ public function validate($form, Constraint $constraint)
113113
$this->buildViolation($config->getOption('extra_fields_message'))
114114
->setParameter('{{ extra_fields }}', implode('", "', array_keys($form->getExtraData())))
115115
->setInvalidValue($form->getExtraData())
116+
->setCode(Form::NO_SUCH_FIELD_ERROR)
116117
->addViolation();
117118
}
118119
}

src/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public function validateForm(FormEvent $event)
6666
foreach ($violations as $violation) {
6767
// Allow the "invalid" constraint to be put onto
6868
// non-synchronized forms
69-
$allowNonSynchronized = Form::ERR_INVALID === $violation->getCode();
69+
$allowNonSynchronized = $violation->getConstraint() instanceof Form && Form::NOT_SYNCHRONIZED_ERROR === $violation->getCode();
7070

7171
$this->violationMapper->mapViolation($violation, $form, $allowNonSynchronized);
7272
}

src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ function () { throw new TransformationFailedException(); }
231231
->setParameter('{{ value }}', 'foo')
232232
->setParameter('{{ foo }}', 'bar')
233233
->setInvalidValue('foo')
234-
->setCode(Form::ERR_INVALID)
234+
->setCode(Form::NOT_SYNCHRONIZED_ERROR)
235235
->setCause($is2Dot4Api ? null : $form->getTransformationFailure())
236236
->assertRaised();
237237
}
@@ -268,7 +268,7 @@ function () { throw new TransformationFailedException(); }
268268
->setParameter('{{ value }}', 'foo')
269269
->setParameter('{{ foo }}', 'bar')
270270
->setInvalidValue('foo')
271-
->setCode(Form::ERR_INVALID)
271+
->setCode(Form::NOT_SYNCHRONIZED_ERROR)
272272
->setCause($is2Dot4Api ? null : $form->getTransformationFailure())
273273
->assertRaised();
274274
}
@@ -304,7 +304,7 @@ function () { throw new TransformationFailedException(); }
304304
$this->buildViolation('invalid_message_key')
305305
->setParameter('{{ value }}', 'foo')
306306
->setInvalidValue('foo')
307-
->setCode(Form::ERR_INVALID)
307+
->setCode(Form::NOT_SYNCHRONIZED_ERROR)
308308
->setCause($is2Dot4Api ? null : $form->getTransformationFailure())
309309
->assertRaised();
310310
}
@@ -558,9 +558,11 @@ public function testViolationIfExtraData()
558558

559559
$this->validator->validate($form, new Form());
560560

561-
$this->assertViolation('Extra!', array(
562-
'{{ extra_fields }}' => 'foo',
563-
), 'property.path', array('foo' => 'bar'));
561+
$this->buildViolation('Extra!')
562+
->setParameter('{{ extra_fields }}', 'foo')
563+
->setInvalidValue(array('foo' => 'bar'))
564+
->setCode(Form::NO_SUCH_FIELD_ERROR)
565+
->assertRaised();
564566
}
565567

566568
public function testNoViolationIfAllowExtraData()

src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ protected function setUp()
6666

6767
private function getConstraintViolation($code = null)
6868
{
69-
return new ConstraintViolation($this->message, $this->messageTemplate, $this->params, null, 'prop.path', null, null, $code);
69+
return new ConstraintViolation($this->message, $this->messageTemplate, $this->params, null, 'prop.path', null, null, $code, new Form());
7070
}
7171

7272
private function getBuilder($name = 'name', $propertyPath = null, $dataClass = null)
@@ -109,7 +109,7 @@ public function testMapViolation()
109109

110110
public function testMapViolationAllowsNonSyncIfInvalid()
111111
{
112-
$violation = $this->getConstraintViolation(Form::ERR_INVALID);
112+
$violation = $this->getConstraintViolation(Form::NOT_SYNCHRONIZED_ERROR);
113113
$form = $this->getForm('street');
114114

115115
$this->validator->expects($this->once())

src/Symfony/Component/Validator/Constraint.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Validator;
1313

1414
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
15+
use Symfony\Component\Validator\Exception\InvalidArgumentException;
1516
use Symfony\Component\Validator\Exception\InvalidOptionsException;
1617
use Symfony\Component\Validator\Exception\MissingOptionsException;
1718

@@ -50,12 +51,40 @@ abstract class Constraint
5051
*/
5152
const PROPERTY_CONSTRAINT = 'property';
5253

54+
/**
55+
* Maps error codes to the names of their constants
56+
* @var array
57+
*/
58+
protected static $errorNames = array();
59+
5360
/**
5461
* Domain-specific data attached to a constraint
5562
* @var mixed
5663
*/
5764
public $payload;
5865

66+
/**
67+
* Returns the name of the given error code.
68+
*
69+
* @param int $errorCode The error code
70+
*
71+
* @return string The name of the error code
72+
*
73+
* @throws InvalidArgumentException If the error code does not exist
74+
*/
75+
public static function getErrorName($errorCode)
76+
{
77+
if (!isset(static::$errorNames[$errorCode])) {
78+
throw new InvalidArgumentException(sprintf(
79+
'The error code "%s" does not exist for constraint of type "%s".',
80+
$errorCode,
81+
get_called_class()
82+
));
83+
}
84+
85+
return static::$errorNames[$errorCode];
86+
}
87+
5988
/**
6089
* Initializes the constraint with options.
6190
*

src/Symfony/Component/Validator/Constraints/CardScheme.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,18 @@
2020
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
2121
*
2222
* @author Tim Nagel <t.nagel@infinite.net.au>
23+
* @author Bernhard Schussek <bschussek@gmail.com>
2324
*/
2425
class CardScheme extends Constraint
2526
{
27+
const NOT_NUMERIC_ERROR = 1;
28+
const INVALID_FORMAT_ERROR = 2;
29+
30+
protected static $errorNames = array(
31+
self::NOT_NUMERIC_ERROR => 'NOT_NUMERIC_ERROR',
32+
self::INVALID_FORMAT_ERROR => 'INVALID_FORMAT_ERROR',
33+
);
34+
2635
public $message = 'Unsupported card type or invalid card number.';
2736
public $schemes;
2837

src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ public function validate($value, Constraint $constraint)
117117
if (!is_numeric($value)) {
118118
$this->buildViolation($constraint->message)
119119
->setParameter('{{ value }}', $this->formatValue($value))
120+
->setCode(CardScheme::NOT_NUMERIC_ERROR)
120121
->addViolation();
121122

122123
return;
@@ -135,6 +136,7 @@ public function validate($value, Constraint $constraint)
135136

136137
$this->buildViolation($constraint->message)
137138
->setParameter('{{ value }}', $this->formatValue($value))
139+
->setCode(CardScheme::INVALID_FORMAT_ERROR)
138140
->addViolation();
139141
}
140142
}

src/Symfony/Component/Validator/Constraints/Choice.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@
2323
*/
2424
class Choice extends Constraint
2525
{
26+
const NO_SUCH_CHOICE_ERROR = 1;
27+
const TOO_FEW_ERROR = 2;
28+
const TOO_MANY_ERROR = 3;
29+
30+
protected static $errorNames = array(
31+
self::NO_SUCH_CHOICE_ERROR => 'NO_SUCH_CHOICE_ERROR',
32+
self::TOO_FEW_ERROR => 'TOO_FEW_ERROR',
33+
self::TOO_MANY_ERROR => 'TOO_MANY_ERROR',
34+
);
35+
2636
public $choices;
2737
public $callback;
2838
public $multiple = false;

src/Symfony/Component/Validator/Constraints/ChoiceValidator.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ public function validate($value, Constraint $constraint)
6565
if (!in_array($_value, $choices, $constraint->strict)) {
6666
$this->buildViolation($constraint->multipleMessage)
6767
->setParameter('{{ value }}', $this->formatValue($_value))
68+
->setCode(Choice::NO_SUCH_CHOICE_ERROR)
6869
->setInvalidValue($_value)
6970
->addViolation();
7071

@@ -78,6 +79,7 @@ public function validate($value, Constraint $constraint)
7879
$this->buildViolation($constraint->minMessage)
7980
->setParameter('{{ limit }}', $constraint->min)
8081
->setPlural((int) $constraint->min)
82+
->setCode(Choice::TOO_FEW_ERROR)
8183
->addViolation();
8284

8385
return;
@@ -87,13 +89,15 @@ public function validate($value, Constraint $constraint)
8789
$this->buildViolation($constraint->maxMessage)
8890
->setParameter('{{ limit }}', $constraint->max)
8991
->setPlural((int) $constraint->max)
92+
->setCode(Choice::TOO_MANY_ERROR)
9093
->addViolation();
9194

9295
return;
9396
}
9497
} elseif (!in_array($value, $choices, $constraint->strict)) {
9598
$this->buildViolation($constraint->message)
9699
->setParameter('{{ value }}', $this->formatValue($value))
100+
->setCode(Choice::NO_SUCH_CHOICE_ERROR)
97101
->addViolation();
98102
}
99103
}

src/Symfony/Component/Validator/Constraints/Collection.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
namespace Symfony\Component\Validator\Constraints;
1313

14-
use Symfony\Component\Validator\Constraint;
1514
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
1615

1716
/**
@@ -24,6 +23,14 @@
2423
*/
2524
class Collection extends Composite
2625
{
26+
const MISSING_FIELD_ERROR = 1;
27+
const NO_SUCH_FIELD_ERROR = 2;
28+
29+
protected static $errorNames = array(
30+
self::MISSING_FIELD_ERROR => 'MISSING_FIELD_ERROR',
31+
self::NO_SUCH_FIELD_ERROR => 'NO_SUCH_FIELD_ERROR',
32+
);
33+
2734
public $fields = array();
2835
public $allowExtraFields = false;
2936
public $allowMissingFields = false;

src/Symfony/Component/Validator/Constraints/CollectionValidator.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ public function validate($value, Constraint $constraint)
7373
->atPath('['.$field.']')
7474
->setParameter('{{ field }}', $this->formatValue($field))
7575
->setInvalidValue(null)
76+
->setCode(Collection::MISSING_FIELD_ERROR)
7677
->addViolation();
7778
}
7879
}
@@ -84,6 +85,7 @@ public function validate($value, Constraint $constraint)
8485
->atPath('['.$field.']')
8586
->setParameter('{{ field }}', $this->formatValue($field))
8687
->setInvalidValue($fieldValue)
88+
->setCode(Collection::NO_SUCH_FIELD_ERROR)
8789
->addViolation();
8890
}
8991
}

src/Symfony/Component/Validator/Constraints/Count.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@
2424
*/
2525
class Count extends Constraint
2626
{
27+
const TOO_FEW_ERROR = 1;
28+
const TOO_MANY_ERROR = 2;
29+
30+
protected static $errorNames = array(
31+
self::TOO_FEW_ERROR => 'TOO_FEW_ERROR',
32+
self::TOO_MANY_ERROR => 'TOO_MANY_ERROR',
33+
);
34+
2735
public $minMessage = 'This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more.';
2836
public $maxMessage = 'This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less.';
2937
public $exactMessage = 'This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements.';

src/Symfony/Component/Validator/Constraints/CountValidator.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public function validate($value, Constraint $constraint)
4141
->setParameter('{{ limit }}', $constraint->max)
4242
->setInvalidValue($value)
4343
->setPlural((int) $constraint->max)
44+
->setCode(Count::TOO_MANY_ERROR)
4445
->addViolation();
4546

4647
return;
@@ -52,6 +53,7 @@ public function validate($value, Constraint $constraint)
5253
->setParameter('{{ limit }}', $constraint->min)
5354
->setInvalidValue($value)
5455
->setPlural((int) $constraint->min)
56+
->setCode(Count::TOO_FEW_ERROR)
5557
->addViolation();
5658
}
5759
}

src/Symfony/Component/Validator/Constraints/Date.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,13 @@
2323
*/
2424
class Date extends Constraint
2525
{
26+
const INVALID_FORMAT_ERROR = 1;
27+
const INVALID_DATE_ERROR = 2;
28+
29+
protected static $errorNames = array(
30+
self::INVALID_FORMAT_ERROR => 'INVALID_FORMAT_ERROR',
31+
self::INVALID_DATE_ERROR => 'INVALID_DATE_ERROR',
32+
);
33+
2634
public $message = 'This value is not a valid date.';
2735
}

src/Symfony/Component/Validator/Constraints/DateTime.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,15 @@
2323
*/
2424
class DateTime extends Constraint
2525
{
26+
const INVALID_FORMAT_ERROR = 1;
27+
const INVALID_DATE_ERROR = 2;
28+
const INVALID_TIME_ERROR = 3;
29+
30+
protected static $errorNames = array(
31+
self::INVALID_FORMAT_ERROR => 'INVALID_FORMAT_ERROR',
32+
self::INVALID_DATE_ERROR => 'INVALID_DATE_ERROR',
33+
self::INVALID_TIME_ERROR => 'INVALID_TIME_ERROR',
34+
);
35+
2636
public $message = 'This value is not a valid datetime.';
2737
}

src/Symfony/Component/Validator/Constraints/DateTimeValidator.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 + 10000 45,7 @@ public function validate($value, Constraint $constraint)
4545
if (!preg_match(static::PATTERN, $value, $matches)) {
4646
$this->buildViolation($constraint->message)
4747
->setParameter('{{ value }}', $this->formatValue($value))
48+
->setCode(DateTime::INVALID_FORMAT_ERROR)
4849
->addViolation();
4950

5051
return;
@@ -53,12 +54,14 @@ public function validate($value, Constraint $constraint)
5354
if (!DateValidator::checkDate($matches[1], $matches[2], $matches[3])) {
5455
$this->buildViolation($constraint->message)
5556
->setParameter('{{ value }}', $this->formatValue($value))
57+
->setCode(DateTime::INVALID_DATE_ERROR)
5658
->addViolation();
5759
}
5860

5961
if (!TimeValidator::checkTime($matches[4], $matches[5], $matches[6])) {
6062
$this->buildViolation($constraint->message)
6163
->setParameter('{{ value }}', $this->formatValue($value))
64+
->setCode(DateTime::INVALID_TIME_ERROR)
6265
->addViolation();
6366
}
6467
}

src/Symfony/Component/Validator/Constraints/DateValidator.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public function validate($value, Constraint $constraint)
6262
if (!preg_match(static::PATTERN, $value, $matches)) {
6363
$this->buildViolation($constraint->message)
6464
->setParameter('{{ value }}', $this->formatValue($value))
65+
->setCode(Date::INVALID_FORMAT_ERROR)
6566
->addViolation();
6667

6768
return;
@@ -70,6 +71,7 @@ public function validate($value, Constraint $constraint)
7071
if (!self::checkDate($matches[1], $matches[2], $matches[3])) {
7172
$this->buildViolation($constraint->message)
7273
->setParameter('{{ value }}', $this->formatValue($value))
74+
->setCode(Date::INVALID_DATE_ERROR)
7375
->addViolation();
7476
}
7577
}

src/Symfony/Component/Validator/Constraints/Email.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@
2323
*/
2424
class Email extends Constraint
2525
{
26+
const INVALID_FORMAT_ERROR = 1;
27+
const MX_CHECK_FAILED_ERROR = 2;
28+
const HOST_CHECK_FAILED_ERROR = 3;
29+
30+
protected static $errorNames = array(
31+
self::INVALID_FORMAT_ERROR => 'STRICT_CHECK_FAILED_ERROR',
32+
self::MX_CHECK_FAILED_ERROR => 'MX_CHECK_FAILED_ERROR',
33+
self::HOST_CHECK_FAILED_ERROR => 'HOST_CHECK_FAILED_ERROR',
34+
);
35+
2636
public $message = 'This value is not a valid email address.';
2737
public $checkMX = false;
2838
public $checkHost = false;

0 commit comments

Comments
 (0)
0