diff --git a/UPGRADE-2.2.md b/UPGRADE-2.2.md index 825e7f2570..39fb89bc0b 100644 --- a/UPGRADE-2.2.md +++ b/UPGRADE-2.2.md @@ -319,3 +319,21 @@ // ... } ``` + + * The constraint `Choice` was deprecated and will be removed in Symfony 2.3. + You should use the new constraint `OneOf` instead. + + Before: + + ``` + /** @Assert\Choice(choices = {"male", "female"}, message = "Choose a valid gender.") */ + protected $gender; + ``` + + After: + + ``` + /** @Assert\OneOf(choices = {"male", "female"}, message = "Choose a valid gender.") */ + protected $gender; + ``` + diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 20d499f855..4e9eaa532a 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -28,6 +28,7 @@ CHANGELOG As of Symfony 2.3, this method will be typed against `MetadataFactoryInterface` instead. * [BC BREAK] the switches `traverse` and `deep` in the `Valid` constraint and in `GraphWalker::walkReference` are ignored for arrays now. Arrays are always traversed recursively. + * deprecated `Choice` constraint in favor of the new `OneOf` constraint. 2.1.0 ----- diff --git a/src/Symfony/Component/Validator/Constraints/Choice.php b/src/Symfony/Component/Validator/Constraints/Choice.php index b73bd77ca3..19d8998b8f 100644 --- a/src/Symfony/Component/Validator/Constraints/Choice.php +++ b/src/Symfony/Component/Validator/Constraints/Choice.php @@ -11,31 +11,19 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Validator\Constraint; - /** * @Annotation * * @api + * + * @deprecated Deprecated since version 2.2, to be removed in 2.3. Use + * {@link OneOf} instead. */ -class Choice extends Constraint +class Choice extends OneOf { - public $choices; - public $callback; - public $multiple = false; - public $strict = false; - public $min = null; - public $max = null; - public $message = 'The value you selected is not a valid choice.'; - public $multipleMessage = 'One or more of the given values is invalid.'; - public $minMessage = 'You must select at least {{ limit }} choices.'; - public $maxMessage = 'You must select at most {{ limit }} choices.'; - - /** - * {@inheritDoc} - */ - public function getDefaultOption() + public function __construct($options = null) { - return 'choices'; + trigger_error('Choice constraint is deprecated since version 2.2 and will be removed in 2.3. Use OneOf instead', E_USER_DEPRECATED); + parent::__construct($options); } } diff --git a/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php b/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php index 96e2833f60..296f35753e 100644 --- a/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php +++ b/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php @@ -11,11 +11,6 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Validator\Constraint; -use Symfony\Component\Validator\ConstraintValidator; -use Symfony\Component\Validator\Exception\ConstraintDefinitionException; -use Symfony\Component\Validator\Exception\UnexpectedTypeException; - /** * ChoiceValidator validates that the value is one of the expected values. * @@ -24,60 +19,15 @@ use Symfony\Component\Validator\Exception\UnexpectedTypeException; * @author Bernhard Schussek * * @api + * + * @deprecated Deprecated since version 2.2, to be removed in 2.3. Use + * {@link OneOfValidator} instead. */ -class ChoiceValidator extends ConstraintValidator +class ChoiceValidator extends OneOfValidator { - /** - * {@inheritDoc} - */ - public function validate($value, Constraint $constraint) + public function __construct($options = null) { - if (!$constraint->choices && !$constraint->callback) { - throw new ConstraintDefinitionException('Either "choices" or "callback" must be specified on constraint Choice'); - } - - if (null === $value) { - return; - } - - if ($constraint->multiple && !is_array($value)) { - throw new UnexpectedTypeException($value, 'array'); - } - - if ($constraint->callback) { - if (is_callable(array($this->context->getCurrentClass(), $constraint->callback))) { - $choices = call_user_func(array($this->context->getCurrentClass(), $constraint->callback)); - } elseif (is_callable($constraint->callback)) { - $choices = call_user_func($constraint->callback); - } else { - throw new ConstraintDefinitionException('The Choice constraint expects a valid callback'); - } - } else { - $choices = $constraint->choices; - } - - if ($constraint->multiple) { - foreach ($value as $_value) { - if (!in_array($_value, $choices, $constraint->strict)) { - $this->context->addViolation($constraint->multipleMessage, array('{{ value }}' => $_value)); - } - } - - $count = count($value); - - if ($constraint->min !== null && $count < $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); - - return; - } - } elseif (!in_array($value, $choices, $constraint->strict)) { - $this->context->addViolation($constraint->message, array('{{ value }}' => $value)); - } + trigger_error('ChoiceValidator is deprecated since version 2.2 and will be removed in 2.3. Use OneOfValidator instead', E_USER_DEPRECATED); + parent::__construct($options); } } diff --git a/src/Symfony/Component/Validator/Constraints/OneOf.php b/src/Symfony/Component/Validator/Constraints/OneOf.php new file mode 100644 index 0000000000..01287db269 --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/OneOf.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +use Symfony\Component\Validator\Constraint; + +/** + * @Annotation + * + * @api + */ +class OneOf extends Constraint +{ + public $choices; + public $callback; + public $multiple = false; + public $strict = false; + public $min = null; + public $max = null; + public $message = 'The value you selected is not a valid choice.'; + public $multipleMessage = 'One or more of the given values is invalid.'; + public $minMessage = 'You must select at least {{ limit }} choices.'; + public $maxMessage = 'You must select at most {{ limit }} choices.'; + + /** + * {@inheritDoc} + */ + public function getDefaultOption() + { + return 'choices'; + } +} diff --git a/src/Symfony/Component/Validator/Constraints/OneOfValidator.php b/src/Symfony/Component/Validator/Constraints/OneOfValidator.php new file mode 100644 index 0000000000..a707d37319 --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/OneOfValidator.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\ConstraintDefinitionException; +use Symfony\Component\Validator\Exception\UnexpectedTypeException; + +/** + * ChoiceValidator validates that the value is one of the expected values. + * + * @author Fabien Potencier + * @author Florian Eckerstorfer + * @author Bernhard Schussek + * + * @api + */ +class OneOfValidator extends ConstraintValidator +{ + /** + * {@inheritDoc} + */ + public function validate($value, Constraint $constraint) + { + if (!$constraint->choices && !$constraint->callback) { + throw new ConstraintDefinitionException('Either "choices" or "callback" must be specified on constraint Choice'); + } + + if (null === $value) { + return; + } + + if ($constraint->multiple && !is_array($value)) { + throw new UnexpectedTypeException($value, 'array'); + } + + if ($constraint->callback) { + if (is_callable(array($this->context->getCurrentClass(), $constraint->callback))) { + $choices = call_user_func(array($this->context->getCurrentClass(), $constraint->callback)); + } elseif (is_callable($constraint->callback)) { + $choices = call_user_func($constraint->callback); + } else { + throw new ConstraintDefinitionException('The OneOf constraint expects a valid callback'); + } + } else { + $choices = $constraint->choices; + } + + if ($constraint->multiple) { + foreach ($value as $_value) { + if (!in_array($_value, $choices, $constraint->strict)) { + $this->context->addViolation($constraint->multipleMessage, array('{{ value }}' => $_value)); + } + } + + $count = count($value); + + if ($constraint->min !== null && $count < $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); + + return; + } + } elseif (!in_array($value, $choices, $constraint->strict)) { + $this->context->addViolation($constraint->message, array('{{ value }}' => $value)); + } + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/ChoiceValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/OneOfValidatorTest.php similarity index 76% rename from src/Symfony/Component/Validator/Tests/Constraints/ChoiceValidatorTest.php rename to src/Symfony/Component/Validator/Tests/Constraints/OneOfValidatorTest.php index 34221ffda2..7786455719 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/ChoiceValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/OneOfValidatorTest.php @@ -12,15 +12,15 @@ namespace Symfony\Component\Validator\Tests\Constraints; use Symfony\Component\Validator\ExecutionContext; -use Symfony\Component\Validator\Constraints\Choice; -use Symfony\Component\Validator\Constraints\ChoiceValidator; +use Symfony\Component\Validator\Constraints\OneOf; +use Symfony\Component\Validator\Constraints\OneOfValidator; -function choice_callback() +function oneof_callback() { return array('foo', 'bar'); } -class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase +class OneOfValidatorTest extends \PHPUnit_Framework_TestCase { protected $context; protected $validator; @@ -33,7 +33,7 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase protected function setUp() { $this->context = $this->getMock('Symfony\Component\Validator\ExecutionContext', array(), array(), '', false); - $this->validator = new ChoiceValidator(); + $this->validator = new OneOfValidator(); $this->validator->initialize($this->context); $this->context->expects($this->any()) @@ -52,7 +52,7 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase */ public function testExpectArrayIfMultipleIsTrue() { - $constraint = new Choice(array( + $constraint = new OneOf(array( 'choices' => array('foo', 'bar'), 'multiple' => true, )); @@ -65,7 +65,7 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase $this->context->expects($this->never()) ->method('addViolation'); - $this->validator->validate(null, new Choice(array('choices' => array('foo', 'bar')))); + $this->validator->validate(null, new OneOf(array('choices' => array('foo', 'bar')))); } /** @@ -73,7 +73,7 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase */ public function testChoicesOrCallbackExpected() { - $this->validator->validate('foobar', new Choice()); + $this->validator->validate('foobar', new OneOf()); } /** @@ -81,12 +81,12 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase */ public function testValidCallbackExpected() { - $this->validator->validate('foobar', new Choice(array('callback' => 'abcd'))); + $this->validator->validate('foobar', new OneOf(array('callback' => 'abcd'))); } - public function testValidChoiceArray() + public function testValidOneOfChoicesArray() { - $constraint = new Choice(array('choices' => array('foo', 'bar'))); + $constraint = new OneOf(array('choices' => array('foo', 'bar'))); $this->context->expects($this->never()) ->method('addViolation'); @@ -94,9 +94,9 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase $this->validator->validate('bar', $constraint); } - public function testValidChoiceCallbackFunction() + public function testValidOneOfCallbackFunction() { - $constraint = new Choice(array('callback' => __NAMESPACE__.'\choice_callback')); + $constraint = new OneOf(array('callback' => __NAMESPACE__.'\oneof_callback')); $this->context->expects($this->never()) ->method('addViolation'); @@ -104,9 +104,9 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase $this->validator->validate('bar', $constraint); } - public function testValidChoiceCallbackClosure() + public function testValidOneOfCallbackClosure() { - $constraint = new Choice(array('callback' => function() { + $constraint = new OneOf(array('callback' => function() { return array('foo', 'bar'); })); @@ -116,9 +116,9 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase $this->validator->validate('bar', $constraint); } - public function testValidChoiceCallbackStaticMethod() + public function testValidOneOfCallbackStaticMethod() { - $constraint = new Choice(array('callback' => array(__CLASS__, 'staticCallback'))); + $constraint = new OneOf(array('callback' => array(__CLASS__, 'staticCallback'))); $this->context->expects($this->never()) ->method('addViolation'); @@ -126,9 +126,9 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase $this->validator->validate('bar', $constraint); } - public function testValidChoiceCallbackContextMethod() + public function testValidOneOfCallbackContextMethod() { - $constraint = new Choice(array('callback' => 'staticCallback')); + $constraint = new OneOf(array('callback' => 'staticCallback')); $this->context->expects($this->never()) ->method('addViolation'); @@ -136,9 +136,9 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase $this->validator->validate('bar', $constraint); } - public function testMultipleChoices() + public function testMultipleOneOfChoices() { - $constraint = new Choice(array( + $constraint = new OneOf(array( 'choices' => array('foo', 'bar', 'baz'), 'multiple' => true, )); @@ -149,9 +149,9 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase $this->validator->validate(array('baz', 'bar'), $constraint); } - public function testInvalidChoice() + public function testInvalidOneOf() { - $constraint = new Choice(array( + $constraint = new OneOf(array( 'choices' => array('foo', 'bar'), 'message' => 'myMessage', )); @@ -165,9 +165,9 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase $this->validator->validate('baz', $constraint); } - public function testInvalidChoiceMultiple() + public function testInvalidOneOfMultiple() { - $constraint = new Choice(array( + $constraint = new OneOf(array( 'choices' => array('foo', 'bar'), 'multipleMessage' => 'myMessage', 'multiple' => true, @@ -182,9 +182,9 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase $this->validator->validate(array('foo', 'baz'), $constraint); } - public function testTooFewChoices() + public function testTooFewOneOfChoices() { - $constraint = new Choice(array( + $constraint = new OneOf(array( 'choices' => array('foo', 'bar', 'moo', 'maa'), 'multiple' => true, 'min' => 2, @@ -200,9 +200,9 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase $this->validator->validate(array('foo'), $constraint); } - public function testTooManyChoices() + public function testTooManyOneOfChoices() { - $constraint = new Choice(array( + $constraint = new OneOf(array( 'choices' => array('foo', 'bar', 'moo', 'maa'), 'multiple' => true, 'max' => 2, @@ -220,7 +220,7 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase public function testNonStrict() { - $constraint = new Choice(array( + $constraint = new OneOf(array( 'choices' => array(1, 2), 'strict' => false, )); @@ -234,7 +234,7 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase public function testStrictAllowsExactValue() { - $constraint = new Choice(array( + $constraint = new OneOf(array( 'choices' => array(1, 2), 'strict' => true, )); @@ -247,7 +247,7 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase public function testStrictDisallowsDifferentType() { - $constraint = new Choice(array( + $constraint = new OneOf(array( 'choices' => array(1, 2), 'strict' => true, 'message' => 'myMessage' @@ -262,9 +262,9 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase $this->validator->validate('2', $constraint); } - public function testNonStrictWithMultipleChoices() + public function testNonStrictOneOfWithMultipleChoices() { - $constraint = new Choice(array( + $constraint = new OneOf(array( 'choices' => array(1, 2, 3), 'multiple' => true, 'strict' => false @@ -276,9 +276,9 @@ class ChoiceValidatorTest extends \PHPUnit_Framework_TestCase $this->validator->validate(array('2', 3), $constraint); } - public function testStrictWithMultipleChoices() + public function testStrictOneOfWithMultipleChoices() { - $constraint = new Choice(array( + $constraint = new OneOf(array( 'choices' => array(1, 2, 3), 'multiple' => true, 'strict' => true,