Skip to content

[Validator] Add CollectionSize constraint #4149

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 16, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,18 @@
<source>A PHP extension caused the upload to fail.</source>
<target>A PHP extension caused the upload to fail.</target>
</trans-unit>
<trans-unit id="54">
<source>This collection should contain {{ limit }} elements or more.</source>
<target>This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more.</target>
</trans-unit>
<trans-unit id="55">
<source>This collection should contain {{ limit }} elements or less.</source>
<target>This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less.</target>
</trans-unit>
<trans-unit id="56">
<source>This collection should contain exactly {{ limit }} elements.</source>
<target>This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements.</target>
</trans-unit>
</body>
</file>
</xliff>
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,15 @@
</trans-unit>
<trans-unit id="19">
<source>This value is too long. It should have {{ limit }} characters or less.</source>
<target>Cette chaine est trop longue. Elle doit avoir au maximum {{ limit }} caractères.</target>
<target>Cette chaine est trop longue. Elle doit avoir au maximum {{ limit }} caractère.|Cette chaine est trop longue. Elle doit avoir au maximum {{ limit }} caractères.</target>
</trans-unit>
<trans-unit id="20">
<source>This value should be {{ limit }} or more.</source>
<target>Cette valeur doit être supérieure ou égale à {{ limit }}.</target>
</trans-unit>
<trans-unit id="21">
<source>This value is too short. It should have {{ limit }} characters or more.</source>
<target>Cette chaine est trop courte. Elle doit avoir au minimum {{ limit }} caractères.</target>
<target>Cette chaine est trop courte. Elle doit avoir au minimum {{ limit }} caractère.|Cette chaine est trop courte. Elle doit avoir au minimum {{ limit }} caractères.</target>
</trans-unit>
<trans-unit id="22">
<source>This value should not be blank.</source>
Expand Down Expand Up @@ -192,7 +192,7 @@
</trans-unit>
<trans-unit id="48">
<source>This value should have exactly {{ limit }} characters.</source>
<target>Cette chaine doit avoir exactement {{ limit }} caractères.</target>
<target>Cette chaine doit avoir exactement {{ limit }} caractère.|Cette chaine doit avoir exactement {{ limit }} caractères.</target>
</trans-unit>
<trans-unit id="49">
<source>The file was only partially uploaded.</source>
Expand All @@ -214,6 +214,18 @@
<source>A PHP extension caused the upload to fail.</source>
<target>Une extension PHP a empêché le transfert du fichier.</target>
</trans-unit>
<trans-unit id="54">
<source>This collection should contain {{ limit }} elements or more.</source>
<target>Cette collection doit contenir {{ limit }} élément ou plus.|Cette collection doit contenir {{ limit }} éléments ou plus.</target>
</trans-unit>
<trans-unit id="55">
<source>This collection should contain {{ limit }} elements or less.</source>
<target>Cette collection doit contenir {{ limit }} élément ou moins.|Cette collection doit contenir {{ limit }} éléments ou moins.</target>
</trans-unit>
<trans-unit id="56">
<source>This collection should contain exactly {{ limit }} elements.</source>
<target>Cette collection doit contenir exactement {{ limit }} élément.|Cette collection doit contenir exactement {{ limit }} éléments.</target>
</trans-unit>
</body>
</file>
</xliff>
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,19 @@ public function guessTypeForConstraint(Constraint $constraint)
case 'Symfony\Component\Validator\Constraints\MaxLength':
case 'Symfony\Component\Validator\Constraints\MinLength':
case 'Symfony\Component\Validator\Constraints\Regex':
case 'Symfony\Component\Validator\Constraints\SizeLength':
return new TypeGuess('text', array(), Guess::LOW_CONFIDENCE);

case 'Symfony\Component\Validator\Constraints\Min':
case 'Symfony\Component\Validator\Constraints\Size':
switch ($constraint->type) {
case 'string':
return new TypeGuess('text', array(), Guess::LOW_CONFIDENCE);
case 'collection':
return new TypeGuess('collection', array(), Guess::MEDIUM_CONFIDENCE);
}
break;

case 'Symfony\Component\Validator\Constraints\Min':
case 'Symfony\Component\Validator\Constraints\Range':
case 'Symfony\Component\Validator\Constraints\Max':
return new TypeGuess('number', array(), Guess::LOW_CONFIDENCE);
}
Expand Down Expand Up @@ -194,8 +202,11 @@ public function guessMaxLengthForConstraint(Constraint $constraint)
case 'Symfony\Component\Validator\Constraints\MaxLength':
return new ValueGuess($constraint->limit, Guess::HIGH_CONFIDENCE);

case 'Symfony\Component\Validator\Constraints\SizeLength':
return new ValueGuess($constraint->max, Guess::HIGH_CONFIDENCE);
case 'Symfony\Component\Validator\Constraints\Size':
if ('string' === $constraint->type && null !== $constraint->max) {
return new ValueGuess($constraint->max, Guess::HIGH_CONFIDENCE);
}
break;

case 'Symfony\Component\Validator\Constraints\Type':
if (in_array($constraint->type, array('double', 'float', 'numeric', 'real'))) {
Expand All @@ -206,7 +217,7 @@ public function guessMaxLengthForConstraint(Constraint $constraint)
case 'Symfony\Component\Validator\Constraints\Max':
return new ValueGuess(strlen((string) $constraint->limit), Guess::LOW_CONFIDENCE);

case 'Symfony\Component\Validator\Constraints\Size':
case 'Symfony\Component\Validator\Constraints\Range':
return new ValueGuess(strlen((string) $constraint->max), Guess::LOW_CONFIDENCE);
}
}
Expand All @@ -224,7 +235,23 @@ public function guessPatternForConstraint(Constraint $constraint)
case 'Symfony\Component\Validator\Constraints\MinLength':
return new ValueGuess(sprintf('.{%s,}', (string) $constraint->limit), Guess::LOW_CONFIDENCE);

case 'Symfony\Component\Validator\Constraints\SizeLength':
case 'Symfony\Component\Validator\Constraints\Size':
if ('string' !== $constraint->type) {
return;
}

if ($constraint->min === $constraint->max) {
return new ValueGuess(sprintf('.{%s}', (string) $constraint->min), Guess::LOW_CONFIDENCE);
}

if (null === $constraint->min) {
return new ValueGuess(sprintf('.{0,%s}', (string) $constraint->max), Guess::LOW_CONFIDENCE);
}

if (null === $constraint->max) {
return new ValueGuess(sprintf('.{%s,}', (string) $constraint->min), Guess::LOW_CONFIDENCE);
}

return new ValueGuess(sprintf('.{%s,%s}', (string) $constraint->min, (string) $constraint->max), Guess::LOW_CONFIDENCE);

case 'Symfony\Component\Validator\Constraints\Regex':
Expand All @@ -233,7 +260,7 @@ public function guessPatternForConstraint(Constraint $constraint)
case 'Symfony\Component\Validator\Constraints\Min':
return new ValueGuess(sprintf('.{%s,}', strlen((string) $constraint->limit)), Guess::LOW_CONFIDENCE);

case 'Symfony\Component\Validator\Constraints\Size':
case 'Symfony\Component\Validator\Constraints\Range':
return new ValueGuess(sprintf('.{%s,%s}', strlen((string) $constraint->min), strlen((string) $constraint->max)), Guess::LOW_CONFIDENCE);

case 'Symfony\Component\Validator\Constraints\Type':
Expand Down
4 changes: 2 additions & 2 deletions src/Symfony/Component/Validator/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ CHANGELOG
-----

* added support for `ctype_*` assertions in `TypeValidator`
* added a Size validator
* added a SizeLength validator
* added a Range validator for numeric values
* added a Size validator for string & collections
* improved the ImageValidator with min width, max width, min height, and max height constraints
* added support for MIME with wildcard in FileValidator
* changed Collection validator to add "missing" and "extra" errors to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,13 @@
*
* @api
*/
class SizeLength extends Constraint
class Range extends Constraint
{
public $minMessage = 'This value is too short. It should have {{ limit }} characters or more.';
public $maxMessage = 'This value is too long. It should have {{ limit }} characters or less.';
public $exactMessage = 'This value should have exactly {{ limit }} characters.';
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.';
public $min;
public $max;
public $charset = 'UTF-8';

/**
* {@inheritDoc}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,64 +13,52 @@

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;

/**
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @api
*/
class SizeLengthValidator extends ConstraintValidator
class RangeValidator extends ConstraintValidator
{
/**
* Checks if the passed value is valid.
*
* @param mixed $value The value that should be validated
* @param Constraint $constraint The constraint for the validation
*
* @return Boolean Whether or not the value is valid
*
* @api
*/
public function validate($value, Constraint $constraint)
{
if (null === $value || '' === $value) {
if (null === $value) {
return;
}

if (!is_scalar($value) && !(is_object($value) && method_exists($value, '__toString'))) {
throw new UnexpectedTypeException($value, 'string');
}

$value = (string) $value;

if (function_exists('grapheme_strlen') && 'UTF-8' === $constraint->charset) {
$length = grapheme_strlen($value);
} elseif (function_exists('mb_strlen')) {
$length = mb_strlen($value, $constraint->charset);
} else {
$length = strlen($value);
}

if ($constraint->min == $constraint->max && $length != $constraint->max) {
$this->context->addViolation($constraint->exactMessage, array(
if (!is_numeric($value)) {
$this->context->addViolation($constraint->invalidMessage, array(
'{{ value }}' => $value,
'{{ limit }}' => $constraint->max,
), null, (int) $constraint->max);
));

return;
}

if ($length > $constraint->max) {
if ($value > $constraint->max) {
$this->context->addViolation($constraint->maxMessage, array(
'{{ value }}' => $value,
'{{ limit }}' => $constraint->max,
), null, (int) $constraint->max);
));

return;
}

if ($length < $constraint->min) {
if ($value < $constraint->min) {
$this->context->addViolation($constraint->minMessage, array(
'{{ value }}' => $value,
'{{ limit }}' => $constraint->min,
), null, (int) $constraint->min);
));
}
}
}
69 changes: 61 additions & 8 deletions src/Symfony/Component/Validator/Constraints/Size.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,70 @@
*/
class Size extends Constraint
{
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.';
const TYPE_STRING = 'string';
const TYPE_COLLECTION = 'collection';

public $minMessage;
public $maxMessage;
public $exactMessage;
public $type;
public $min;
public $max;
public $charset = 'UTF-8';

private $stringMinMessage = 'This value is too short. It should have {{ limit }} characters or more.';
private $stringMaxMessage = 'This value is too long. It should have {{ limit }} characters or less.';
private $stringExactMessage = 'This value should have exactly {{ limit }} characters.';
Copy link
Contributor

Choose a reason for hiding this comment

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

"characters" is not consistent with "element(s)"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can either replace characters by character(s) or replace element(s) by elements.
The first solution makes more sense to me but also implies some little changes in many places

  • update every existing message to be consistant
  • maybe use pluralization in the translations

What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

may be "elements" not to change to many things in this PR


private $collectionMinMessage = 'This collection should contain {{ limit }} elements or more.';
private $collectionMaxMessage = 'This collection should contain {{ limit }} elements or less.';
private $collectionExactMessage = 'This collection should contain exactly {{ limit }} elements.';

public function getMinMessage($type)
{
if (null !== $this->minMessage) {
return $this->minMessage;
}

switch ($type) {
case static::TYPE_STRING:
return $this->stringMinMessage;
case static::TYPE_COLLECTION:
return $this->collectionMinMessage;
default:
throw new \InvalidArgumentException('Invalid type specified.');
}
}

public function getMaxMessage($type)
{
if (null !== $this->maxMessage) {
return $this->maxMessage;
}

/**
* {@inheritDoc}
*/
public function getRequiredOptions()
switch ($type) {
case static::TYPE_STRING:
return $this->stringMaxMessage;
case static::TYPE_COLLECTION:
return $this->collectionMaxMessage;
default:
throw new \InvalidArgumentException('Invalid type specified.');
}
}

public function getExactMessage($type)
{
return array('min', 'max');
if (null !== $this->exactMessage) {
return $this->exactMessage;
}

switch ($type) {
case static::TYPE_STRING:
return $this->stringExactMessage;
case static::TYPE_COLLECTION:
return $this->collectionExactMessage;
default:
throw new \InvalidArgumentException('Invalid type specified.');
}
}
}
Loading