diff --git a/book/validation.rst b/book/validation.rst index 4ccb264fe8a..73415ee8d97 100644 --- a/book/validation.rst +++ b/book/validation.rst @@ -822,9 +822,13 @@ With this configuration, there are three validation groups: fields only. To tell the validator to use a specific group, pass one or more group names -as the second argument to the ``validate()`` method:: +as the third argument to the ``validate()`` method:: - $errors = $validator->validate($author, array('registration')); + // If you're using the new 2.5 validation API (you probably are!) + $errors = $validator->validate($author, null, array('registration')); + + // If you're using the old 2.4 validation API + // $errors = $validator->validate($author, array('registration')); If no groups are specified, all constraints that belong in group ``Default`` will be applied. @@ -1189,10 +1193,19 @@ it looks like this:: $emailConstraint->message = 'Invalid email address'; // use the validator to validate the value + // If you're using the new 2.5 validation API (you probably are!) + $errorList = $this->get('validator')->validate( + $email, + $emailConstraint + ); + + // If you're using the old 2.4 validation API + /* $errorList = $this->get('validator')->validateValue( $email, $emailConstraint ); + */ if (count($errorList) == 0) { // this IS a valid email address, do something @@ -1206,13 +1219,13 @@ it looks like this:: // ... } -By calling ``validateValue`` on the validator, you can pass in a raw value and +By calling ``validate`` on the validator, you can pass in a raw value and the constraint object that you want to validate that value against. A full list of the available constraints - as well as the full class name for each constraint - is available in the :doc:`constraints reference ` section . -The ``validateValue`` method returns a :class:`Symfony\\Component\\Validator\\ConstraintViolationList` +The ``validate`` method returns a :class:`Symfony\\Component\\Validator\\ConstraintViolationList` object, which acts just like an array of errors. Each error in the collection is a :class:`Symfony\\Component\\Validator\\ConstraintViolation` object, which holds the error message on its ``getMessage`` method. diff --git a/cookbook/bundles/best_practices.rst b/cookbook/bundles/best_practices.rst index 91168b9635a..8cbf0ab521a 100644 --- a/cookbook/bundles/best_practices.rst +++ b/cookbook/bundles/best_practices.rst @@ -335,6 +335,48 @@ semantic configuration described in the cookbook. If you are defining services, they should also be prefixed with the bundle alias. +Custom Validation Constraints +----------------------------- + +Starting with Symfony 2.5, a new Validation API was introduced. In fact, +there are 3 modes, which the user can configure in their project: + +* 2.4: the original 2.4 and earlier validation API; +* 2.5: the new 2.5 and later validation API; +* 2.5-BC: the new 2.5 API with a backwards-compatible layer so that the + 2.4 API still works. This is only available in PHP 5.3.9+. + +As a bundle author, you'll want to support *both* API's, since some users +may still be using the 2.4 API. Specifically, if your bundle adds a violation +directly to the :class:`Symfony\\Component\\Validator\\Context\\ExecutionContext` +(e.g. like in a custom validation constraint), you'll need to check for which +API is being used. The following code, would work for *all* users:: + + use Symfony\Component\Validator\ConstraintValidator; + use Symfony\Component\Validator\Constraint; + use Symfony\Component\Validator\Context\ExecutionContextInterface; + // ... + + class ContainsAlphanumericValidator extends ConstraintValidator + { + public function validate($value, Constraint $constraint) + { + if ($this->context instanceof ExecutionContextInterface) { + // the 2.5 API + $this->context->buildViolation($constraint->message) + ->setParameter('%string%', $value) + ->addViolation(); + ); + } else { + // the 2.4 API + $this->context->addViolation( + $constraint->message, + array('%string%' => $value) + ); + } + } + } + Learn more from the Cookbook ---------------------------- diff --git a/cookbook/form/unit_testing.rst b/cookbook/form/unit_testing.rst index 944ed25b372..a6d2cd458ce 100644 --- a/cookbook/form/unit_testing.rst +++ b/cookbook/form/unit_testing.rst @@ -185,7 +185,7 @@ on other extensions. You need add those extensions to the factory object:: { parent::setUp(); - $validator = $this->getMock('\Symfony\Component\Validator\ValidatorInterface'); + $validator = $this->getMock('\Symfony\Component\Validator\Validator\ValidatorInterface'); $validator->method('validate')->will($this->returnValue(new ConstraintViolationList())); $this->factory = Forms::createFormFactoryBuilder() diff --git a/cookbook/validation/custom_constraint.rst b/cookbook/validation/custom_constraint.rst index 5cfd2312759..caf582a4eee 100644 --- a/cookbook/validation/custom_constraint.rst +++ b/cookbook/validation/custom_constraint.rst @@ -65,22 +65,34 @@ The validator class is also simple, and only has one required method ``validate( public function validate($value, Constraint $constraint) { if (!preg_match('/^[a-zA-Za0-9]+$/', $value, $matches)) { + // If you're using the new 2.5 validation API (you probably are!) + $this->context->buildViolation($constraint->message) + ->setParameter('%string%', $value) + ->addViolation(); + ); + + // If you're using the old 2.4 validation API + /* $this->context->addViolation( $constraint->message, array('%string%' => $value) ); + */ } } } -.. note:: - - The ``validate`` method does not return a value; instead, it adds violations - to the validator's ``context`` property with an ``addViolation`` method - call if there are validation failures. Therefore, a value could be considered - as being valid if it causes no violations to be added to the context. - The first parameter of the ``addViolation`` call is the error message to - use for that violation. +Inside ``validate``, you don't need to return a value. Instead, you add violations +to the validator's ``context`` property and a value will be considered valid +if it causes no violations. The ``buildViolation`` method takes the error +message as its argument and returns an instance of +:class:`Symfony\\Component\\Validator\\Violation\\ConstraintViolationBuilderInterface`. +The ``addViolation`` method call finally adds the violation to the context. + +.. versionadded:: 2.5 + The ``buildViolation`` method was added in Symfony 2.5. For usage examples + with older Symfony versions, see the corresponding versions of this documentation + page. Using the new Validator ----------------------- diff --git a/reference/constraints/Callback.rst b/reference/constraints/Callback.rst index 36b55e97910..e0a21e4b2e0 100644 --- a/reference/constraints/Callback.rst +++ b/reference/constraints/Callback.rst @@ -50,7 +50,9 @@ Configuration namespace Acme\BlogBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; - use Symfony\Component\Validator\ExecutionContextInterface; + use Symfony\Component\Validator\Context\ExecutionContextInterface; + // if you're using the older 2.4 validation API, you'll need this instead + // use Symfony\Component\Validator\ExecutionContextInterface; class Author { @@ -100,7 +102,9 @@ can set "violations" directly on this object and determine to which field those errors should be attributed:: // ... - use Symfony\Component\Validator\ExecutionContextInterface; + use Symfony\Component\Validator\Context\ExecutionContextInterface; + // if you're using the older 2.4 validation API, you'll need this instead + // use Symfony\Component\Validator\ExecutionContextInterface; class Author { @@ -114,16 +118,27 @@ those errors should be attributed:: // check if the name is actually a fake name if (in_array($this->getFirstName(), $fakeNames)) { + // If you're using the new 2.5 validation API (you probably are!) + $context->buildViolation('This name sounds totally fake!') + ->atPath('firstName') + ->addViolation(); + + // If you're using the old 2.4 validation API + /* $context->addViolationAt( 'firstName', - 'This name sounds totally fake!', - array(), - null + 'This name sounds totally fake!' ); + */ } } } +.. versionadded:: 2.5 + The ``buildViolation`` method was added in Symfony 2.5. For usage examples + with older Symfony versions, see the corresponding versions of this documentation + page. + Static Callbacks ---------------- @@ -137,11 +152,16 @@ have access to the object instance, they receive the object as the first argumen // check if the name is actually a fake name if (in_array($object->getFirstName(), $fakeNames)) { + // If you're using the new 2.5 validation API (you probably are!) + $context->buildViolation('This name sounds totally fake!') + ->atPath('firstName') + ->addViolation() + ; + + // If you're using the old 2.4 validation API $context->addViolationAt( 'firstName', - 'This name sounds totally fake!', - array(), - null + 'This name sounds totally fake!' ); } } @@ -156,7 +176,9 @@ your validation function is ``Vendor\Package\Validator::validate()``:: namespace Vendor\Package; - use Symfony\Component\Validator\ExecutionContextInterface; + use Symfony\Component\Validator\Context\ExecutionContextInterface; + // if you're using the older 2.4 validation API, you'll need this instead + // use Symfony\Component\Validator\ExecutionContextInterface; class Validator { @@ -274,7 +296,7 @@ callback method: * A closure. -Concrete callbacks receive an :class:`Symfony\\Component\\Validator\\ExecutionContextInterface` +Concrete callbacks receive an :class:`Symfony\\Component\\Validator\\Context\\ExecutionContextInterface` instance as only argument. Static or closure callbacks receive the validated object as the first argument