Permalink
Browse files

bug #10687 [Validator] Fixed string conversion in constraint violatio…

…ns (eagleoneraptor, webmozart)

This PR was merged into the 2.3 branch.

Discussion
----------

[Validator] Fixed string conversion in constraint violations

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #10675
| License       | MIT
| Doc PR        | -

Commits
-------

32ae95b [Validator] Added more detailed inline documentation
08ea6d3 [Validator] Removed information from the violation output if the value is an array, object or resource
d6a783f [Validator] Renamed valueToString() to formatValue(); added missing formatValue() calls
71897d7 [Validator] Fixed CS
cea4155 [Validator] Fixed date-to-string conversion tests to match ICU 51
5aa7e6d [Validator] Added "{{ value }}" parameters where they were missing
f329552 [Validator] Simplified and explained the LuhnValidator
bff09f2 [Validator] Simplified IssnValidator
224e70f [Validator] Fixed and simplified IsbnValidator
fd58870 [Validator] Simplified IBAN validation algorithm
97243bc [Validator] Fixed value-to-string conversion in constraint violations
75e8815 [Validator] Fix constraint violation message parameterization
  • Loading branch information...
2 parents 71edf38 + 32ae95b commit 7d7b5c724fc9c46604123c031a357af46b21860c @webmozart webmozart committed Jul 30, 2014
Showing with 544 additions and 277 deletions.
  1. +106 −0 src/Symfony/Component/Validator/ConstraintValidator.php
  2. +2 −2 src/Symfony/Component/Validator/ConstraintViolation.php
  3. +3 −31 src/Symfony/Component/Validator/Constraints/AbstractComparisonValidator.php
  4. +3 −1 src/Symfony/Component/Validator/Constraints/BlankValidator.php
  5. +6 −2 src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php
  6. +12 −4 src/Symfony/Component/Validator/Constraints/ChoiceValidator.php
  7. +2 −2 src/Symfony/Component/Validator/Constraints/CollectionValidator.php
  8. +3 −1 src/Symfony/Component/Validator/Constraints/CountryValidator.php
  9. +3 −1 src/Symfony/Component/Validator/Constraints/CurrencyValidator.php
  10. +3 −1 src/Symfony/Component/Validator/Constraints/DateValidator.php
  11. +3 −1 src/Symfony/Component/Validator/Constraints/EmailValidator.php
  12. +3 −1 src/Symfony/Component/Validator/Constraints/FalseValidator.php
  13. +13 −9 src/Symfony/Component/Validator/Constraints/FileValidator.php
  14. +82 −21 src/Symfony/Component/Validator/Constraints/IbanValidator.php
  15. +3 −1 src/Symfony/Component/Validator/Constraints/IpValidator.php
  16. +3 −0 src/Symfony/Component/Validator/Constraints/Isbn.php
  17. +60 −41 src/Symfony/Component/Validator/Constraints/IsbnValidator.php
  18. +22 −13 src/Symfony/Component/Validator/Constraints/IssnValidator.php
  19. +3 −1 src/Symfony/Component/Validator/Constraints/LanguageValidator.php
  20. +3 −3 src/Symfony/Component/Validator/Constraints/LengthValidator.php
  21. +3 −1 src/Symfony/Component/Validator/Constraints/LocaleValidator.php
  22. +34 −13 src/Symfony/Component/Validator/Constraints/LuhnValidator.php
  23. +3 −1 src/Symfony/Component/Validator/Constraints/NotBlankValidator.php
  24. +3 −7 src/Symfony/Component/Validator/Constraints/NullValidator.php
  25. +1 −1 src/Symfony/Component/Validator/Constraints/RangeValidator.php
  26. +3 −1 src/Symfony/Component/Validator/Constraints/RegexValidator.php
  27. +3 −1 src/Symfony/Component/Validator/Constraints/TimeValidator.php
  28. +3 −1 src/Symfony/Component/Validator/Constraints/TrueValidator.php
  29. +1 −1 src/Symfony/Component/Validator/Constraints/TypeValidator.php
  30. +3 −2 src/Symfony/Component/Validator/Constraints/UrlValidator.php
  31. +12 −2 src/Symfony/Component/Validator/Tests/Constraints/AbstractComparisonValidatorTestCase.php
  32. +6 −6 src/Symfony/Component/Validator/Tests/Constraints/BlankValidatorTest.php
  33. +4 −4 src/Symfony/Component/Validator/Tests/Constraints/ChoiceValidatorTest.php
  34. +3 −3 src/Symfony/Component/Validator/Tests/Constraints/CollectionValidatorTest.php
  35. +1 −1 src/Symfony/Component/Validator/Tests/Constraints/DateTimeValidatorTest.php
  36. +1 −1 src/Symfony/Component/Validator/Tests/Constraints/DateValidatorTest.php
  37. +1 −1 src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php
  38. +3 −3 src/Symfony/Component/Validator/Tests/Constraints/EqualToValidatorTest.php
  39. +1 −1 src/Symfony/Component/Validator/Tests/Constraints/FalseValidatorTest.php
  40. +1 −1 src/Symfony/Component/Validator/Tests/Constraints/FileValidatorPathTest.php
  41. +5 −5 src/Symfony/Component/Validator/Tests/Constraints/FileValidatorTest.php
  42. +3 −3 src/Symfony/Component/Validator/Tests/Constraints/GreaterThanOrEqualValidatorTest.php
  43. +6 −6 src/Symfony/Component/Validator/Tests/Constraints/GreaterThanValidatorTest.php
  44. +3 −1 src/Symfony/Component/Validator/Tests/Constraints/IbanValidatorTest.php
  45. +5 −5 src/Symfony/Component/Validator/Tests/Constraints/IdenticalToValidatorTest.php
  46. +12 −12 src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php
  47. +8 −0 src/Symfony/Component/Validator/Tests/Constraints/IsbnValidatorTest.php
  48. +3 −3 src/Symfony/Component/Validator/Tests/Constraints/LengthValidatorTest.php
  49. +3 −3 src/Symfony/Component/Validator/Tests/Constraints/LessThanOrEqualValidatorTest.php
  50. +5 −5 src/Symfony/Component/Validator/Tests/Constraints/LessThanValidatorTest.php
  51. +4 −4 src/Symfony/Component/Validator/Tests/Constraints/NotEqualToValidatorTest.php
  52. +3 −3 src/Symfony/Component/Validator/Tests/Constraints/NotIdenticalToValidatorTest.php
  53. +10 −9 src/Symfony/Component/Validator/Tests/Constraints/NullValidatorTest.php
  54. +15 −0 src/Symfony/Component/Validator/Tests/Constraints/RangeValidatorTest.php
  55. +1 −1 src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php
  56. +1 −1 src/Symfony/Component/Validator/Tests/Constraints/TimeValidatorTest.php
  57. +1 −0 src/Symfony/Component/Validator/Tests/Constraints/TrueValidatorTest.php
  58. +27 −27 src/Symfony/Component/Validator/Tests/Constraints/TypeValidatorTest.php
  59. +1 −1 src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php
@@ -32,4 +32,110 @@ public function initialize(ExecutionContextInterface $context)
{
$this->context = $context;
}
+
+ /**
+ * Returns a string representation of the type of the value.
+ *
+ * This method should be used if you pass the type of a value as
+ * message parameter to a constraint violation. Note that such
+ * parameters should usually not be included in messages aimed at
+ * non-technical people.
+ *
+ * @param mixed $value The value to return the type of
+ *
+ * @return string The type of the value
+ */
+ protected function formatTypeOf($value)
+ {
+ return is_object($value) ? get_class($value) : gettype($value);
+ }
+
+ /**
+ * Returns a string representation of the value.
+ *
+ * This method returns the equivalent PHP tokens for most scalar types
+ * (i.e. "false" for false, "1" for 1 etc.). Strings are always wrapped
+ * in double quotes ("). Objects, arrays and resources are formatted as
+ * "object", "array" and "resource". If the parameter $prettyDateTime
+ * is set to true, {@link \DateTime} objects will be formatted as
+ * RFC-3339 dates ("Y-m-d H:i:s").
+ *
+ * Be careful when passing message parameters to a constraint violation
+ * that (may) contain objects, arrays or resources. These parameters
+ * should only be displayed for technical users. Non-technical users
+ * won't know what an "object", "array" or "resource" is and will be
+ * confused by the violation message.
+ *
+ * @param mixed $value The value to format as string
+ * @param bool $prettyDateTime Whether to format {@link \DateTime}
+ * objects as RFC-3339 dates ("Y-m-d H:i:s")
+ *
+ * @return string The string representation of the passed value
+ */
+ protected function formatValue($value, $prettyDateTime = false)
+ {
+ if ($prettyDateTime && $value instanceof \DateTime) {
+ if (class_exists('IntlDateFormatter')) {
+ $locale = \Locale::getDefault();
+ $formatter = new \IntlDateFormatter($locale, \IntlDateFormatter::MEDIUM, \IntlDateFormatter::SHORT);
+
+ return $formatter->format($value);
+ }
+
+ return $value->format('Y-m-d H:i:s');
+ }
+
+ if (is_object($value)) {
+ return 'object';
+ }
+
+ if (is_array($value)) {
+ return 'array';
+ }
+
+ if (is_string($value)) {
+ return '"'.$value.'"';
+ }
+
+ if (is_resource($value)) {
+ return 'resource';
+ }
+
+ if (null === $value) {
+ return 'null';
+ }
+
+ if (false === $value) {
+ return 'false';
+ }
+
+ if (true === $value) {
+ return 'true';
+ }
+
+ return (string) $value;
+ }
+
+ /**
+ * Returns a string representation of a list of values.
+ *
+ * Each of the values is converted to a string using
+ * {@link formatValue()}. The values are then concatenated with commas.
+ *
+ * @param array $values A list of values
+ * @param bool $prettyDateTime Whether to format {@link \DateTime}
+ * objects as RFC-3339 dates ("Y-m-d H:i:s")
+ *
+ * @return string The string representation of the value list
+ *
+ * @see formatValue()
+ */
+ protected function formatValues(array $values, $prettyDateTime = false)
+ {
+ foreach ($values as $key => $value) {
+ $values[$key] = $this->formatValue($value, $prettyDateTime);
+ }
+
+ return implode(', ', $values);
+ }
}
@@ -96,9 +96,9 @@ public function __construct($message, $messageTemplate, array $messageParameters
public function __toString()
{
if (is_object($this->root)) {
- $class = get_class($this->root);
+ $class = 'Object('.get_class($this->root).')';
} elseif (is_array($this->root)) {
- $class = "Array";
+ $class = 'Array';
} else {
$class = (string) $this->root;
}
@@ -32,42 +32,14 @@ public function validate($value, Constraint $constraint)
if (!$this->compareValues($value, $constraint->value)) {
$this->context->addViolation($constraint->message, array(
- '{{ value }}' => $this->valueToString($constraint->value),
- '{{ compared_value }}' => $this->valueToString($constraint->value),
- '{{ compared_value_type }}' => $this->valueToType($constraint->value)
+ '{{ value }}' => $this->formatValue($value, true),
+ '{{ compared_value }}' => $this->formatValue($constraint->value, true),
+ '{{ compared_value_type }}' => $this->formatTypeOf($constraint->value)
));
}
}
/**
- * Returns a string representation of the type of the value.
- *
- * @param mixed $value
- *
- * @return string
- */
- private function valueToType($value)
- {
- return is_object($value) ? get_class($value) : gettype($value);
- }
-
- /**
- * Returns a string representation of the value.
- *
- * @param mixed $value
- *
- * @return string
- */
- private function valueToString($value)
- {
- if ($value instanceof \DateTime) {
- return $value->format('Y-m-d H:i:s');
- }
-
- return var_export($value, true);
- }
-
- /**
* Compares the two given values to find if their relationship is valid
*
* @param mixed $value1 The first value to compare
@@ -27,7 +27,9 @@ class BlankValidator extends ConstraintValidator
public function validate($value, Constraint $constraint)
{
if ('' !== $value && null !== $value) {
- $this->context->addViolation($constraint->message, array('{{ value }}' => $value));
+ $this->context->addViolation($constraint->message, array(
+ '{{ value }}' => $this->formatValue($value)
+ ));
}
}
}
@@ -108,7 +108,9 @@ public function validate($value, Constraint $constraint)
}
if (!is_numeric($value)) {
- $this->context->addViolation($constraint->message);
+ $this->context->addViolation($constraint->message, array(
+ '{{ value }}' => $this->formatValue($value),
+ ));
return;
}
@@ -124,6 +126,8 @@ public function validate($value, Constraint $constraint)
}
}
- $this->context->addViolation($constraint->message);
+ $this->context->addViolation($constraint->message, array(
+ '{{ value }}' => $this->formatValue($value),
+ ));
}
}
@@ -59,25 +59,33 @@ public function validate($value, Constraint $constraint)
if ($constraint->multiple) {
foreach ($value as $_value) {
if (!in_array($_value, $choices, $constraint->strict)) {
- $this->context->addViolation($constraint->multipleMessage, array('{{ value }}' => $_value));
+ $this->context->addViolation($constraint->multipleMessage, array(
+ '{{ value }}' => $this->formatValue($_value),
+ ));
}
}
$count = count($value);
if ($constraint->min !== null && $count < $constraint->min) {
- $this->context->addViolation($constraint->minMessage, array('{{ limit }}' => $constraint->min), null, (int) $constraint->min);
+ $this->context->addViolation($constraint->minMessage, array(
+ '{{ limit }}' => $constraint->min
+ ), null, (int) $constraint->min);
return;
}
if ($constraint->max !== null && $count > $constraint->max) {
- $this->context->addViolation($constraint->maxMessage, array('{{ limit }}' => $constraint->max), null, (int) $constraint->max);
+ $this->context->addViolation($constraint->maxMessage, array(
+ '{{ limit }}' => $constraint->max
+ ), null, (int) $constraint->max);
return;
}
} elseif (!in_array($value, $choices, $constraint->strict)) {
- $this->context->addViolation($constraint->message, array('{{ value }}' => $value));
+ $this->context->addViolation($constraint->message, array(
+ '{{ value }}' => $this->formatValue($value)
+ ));
}
}
}
@@ -48,7 +48,7 @@ public function validate($value, Constraint $constraint)
}
} elseif (!$fieldConstraint instanceof Optional && !$constraint->allowMissingFields) {
$this->context->addViolationAt('['.$field.']', $constraint->missingFieldsMessage, array(
- '{{ field }}' => $field
+ '{{ field }}' => $this->formatValue($field)
), null);
}
}
@@ -57,7 +57,7 @@ public function validate($value, Constraint $constraint)
foreach ($value as $field => $fieldValue) {
if (!isset($constraint->fields[$field])) {
$this->context->addViolationAt('['.$field.']', $constraint->extraFieldsMessage, array(
- '{{ field }}' => $field
+ '{{ field }}' => $this->formatValue($field)
), $fieldValue);
}
}
@@ -42,7 +42,9 @@ public function validate($value, Constraint $constraint)
$countries = Intl::getRegionBundle()->getCountryNames();
if (!isset($countries[$value])) {
- $this->context->addViolation($constraint->message, array('{{ value }}' => $value));
+ $this->context->addViolation($constraint->message, array(
+ '{{ value }}' => $this->formatValue($value),
+ ));
}
}
}
@@ -42,7 +42,9 @@ public function validate($value, Constraint $constraint)
$currencies = Intl::getCurrencyBundle()->getCurrencyNames();
if (!isset($currencies[$value])) {
- $this->context->addViolation($constraint->message, array('{{ value }}' => $value));
+ $this->context->addViolation($constraint->message, array(
+ '{{ value }}' => $this->formatValue($value),
+ ));
}
}
}
@@ -40,7 +40,9 @@ public function validate($value, Constraint $constraint)
$value = (string) $value;
if (!preg_match(static::PATTERN, $value, $matches) || !checkdate($matches[2], $matches[3], $matches[1])) {
- $this->context->addViolation($constraint->message, array('{{ value }}' => $value));
+ $this->context->addViolation($constraint->message, array(
+ '{{ value }}' => $this->formatValue($value),
+ ));
}
}
}
@@ -50,7 +50,9 @@ public function validate($value, Constraint $constraint)
}
if (!$valid) {
- $this->context->addViolation($constraint->message, array('{{ value }}' => $value));
+ $this->context->addViolation($constraint->message, array(
+ '{{ value }}' => $this->formatValue($value),
+ ));
}
}
@@ -30,6 +30,8 @@ public function validate($value, Constraint $constraint)
return;
}
- $this->context->addViolation($constraint->message);
+ $this->context->addViolation($constraint->message, array(
+ '{{ value }}' => $this->formatValue($value),
+ ));
}
}
@@ -96,13 +96,17 @@ public function validate($value, Constraint $constraint)
$path = $value instanceof FileObject ? $value->getPathname() : (string) $value;
if (!is_file($path)) {
- $this->context->addViolation($constraint->notFoundMessage, array('{{ file }}' => $path));
+ $this->context->addViolation($constraint->notFoundMessage, array(
+ '{{ file }}' => $this->formatValue($path)
+ ));
return;
}
if (!is_readable($path)) {
- $this->context->addViolation($constraint->notReadableMessage, array('{{ file }}' => $path));
+ $this->context->addViolation($constraint->notReadableMessage, array(
+ '{{ file }}' => $this->formatValue($path)
+ ));
return;
}
@@ -126,10 +130,10 @@ public function validate($value, Constraint $constraint)
if ($size > $limit) {
$this->context->addViolation($constraint->maxSizeMessage, array(
- '{{ size }}' => $size,
- '{{ limit }}' => $limit,
- '{{ suffix }}' => $suffix,
- '{{ file }}' => $path,
+ '{{ size }}' => $size,
+ '{{ limit }}' => $limit,
+ '{{ suffix }}' => $suffix,
+ '{{ file }}' => $this->formatValue($path),
));
return;
@@ -161,9 +165,9 @@ public function validate($value, Constraint $constraint)
if (false === $valid) {
$this->context->addViolation($constraint->mimeTypesMessage, array(
- '{{ type }}' => '"'.$mime.'"',
- '{{ types }}' => '"'.implode('", "', $mimeTypes) .'"',
- '{{ file }}' => $path,
+ '{{ type }}' => $this->formatValue($mime),
+ '{{ types }}' => $this->formatValues($mimeTypes),
+ '{{ file }}' => $this->formatValue($path),
));
}
}
Oops, something went wrong.

0 comments on commit 7d7b5c7

Please sign in to comment.